mediawiki-extensions-Echo/tests/qunit/viewmodel/test_mw.echo.dm.NotificationsModel.js
Matthias Mullie 876197b520 Get rid of addApiHandler factory
Some complexity is now gone. We didn't currently have a good justification
for a the APIHandler factory: the apiHandler caller would have to specify
(variable `foreign`) what kind of handler it would like to initiate anyway,
so it might as well just inject the object (which makes the code easier to
follow, decreases bugs risk because there are less code paths)

This also gives the caller more control of the API handlers:
registerForeignSources will now be able to do more. Now it can e.g. create
1 object that is shared for multiple wikis (to do lookups for multiple
wikis at once)

Also renamed addApiHandler to setApiHandler (it just sets the value it needs
without checking if it already existed anyway)

Change-Id: Ie1814c5bf1a1f0e5607033beb506df67f3585b24
2016-05-13 14:11:42 -04:00

257 lines
7.5 KiB
JavaScript

( function ( mw, $ ) {
var echoApi,
mockCounter,
noop = function () {};
QUnit.module( 'ext.echo.dm mw.echo.dm.NotificationsModel' );
function runPreparation( model, testPrepare ) {
var j, jlen;
for ( j = 0, jlen = testPrepare.length; j < jlen; j++ ) {
model[ testPrepare[ j ].method ].apply( model, testPrepare[ j ].params );
}
}
// Helper method to get an array of item ids for testing
function getIdArray( arr ) {
return arr.map( function ( item ) {
return item.getId();
} );
}
// Set up a dummy API handler to avoid sending requests to the API during tests
function TestApiHandler() {
// Parent constructor
TestApiHandler.parent.call( this );
}
/* Setup */
OO.inheritClass( TestApiHandler, mw.echo.api.APIHandler );
// Override api call
TestApiHandler.prototype.markItemsRead = function () {
return $.Deferred().resolve( 0 );
};
mockCounter = { estimateChange: noop, update: noop };
// Create an Echo API instance
echoApi = new mw.echo.api.EchoApi();
// HACK: Reach into the EchoAPI to create a test handler
echoApi.network.setApiHandler( 'test', new TestApiHandler() );
QUnit.test( 'Adding notifications', function ( assert ) {
var initialItems = [
new mw.echo.dm.NotificationItem( 0, { timestamp: '20150828173000', read: false } ),
new mw.echo.dm.NotificationItem( 1, { timestamp: '20150828173100', read: false } ),
new mw.echo.dm.NotificationItem( 2, { timestamp: '20150828173200', read: false } )
],
cases = [
{
items: initialItems,
expected: [ 2, 1, 0 ],
msg: 'Inserting items in timestamp order.'
},
{
items: [
initialItems[ 0 ],
initialItems[ 1 ],
initialItems[ 2 ],
initialItems[ 0 ]
],
expected: [ 2, 1, 0 ],
msg: 'Reinserting an item to its rightful position.'
},
{
items: [
new mw.echo.dm.NotificationItem( 0, { timestamp: '20150828173000', read: false } ),
new mw.echo.dm.NotificationItem( 1, { timestamp: '20150828173100', read: false } ),
new mw.echo.dm.NotificationItem( 2, { timestamp: '20150828173200', read: false } )
],
run: [
{
item: 0,
method: 'setTimestamp',
args: [ '20150830173000' ] // Newer timestamp
}
],
expected: [ 0, 2, 1 ],
msg: 'Changing timestamp on an item.'
},
{
items: [
new mw.echo.dm.NotificationItem( 0, { timestamp: '20150828173000', read: false } ),
new mw.echo.dm.NotificationItem( 1, { timestamp: '20150828173100', read: false } ),
new mw.echo.dm.NotificationItem( 2, { timestamp: '20150828173200', read: false } )
],
run: [
{
item: 1,
method: 'toggleRead',
args: [ true ] // Item is read
}
],
expected: [ 2, 0, 1 ],
msg: 'Changing read status of an item.'
}
];
QUnit.expect( cases.length );
cases.forEach( function ( test ) {
var r, runCase, runItem,
model = new mw.echo.dm.NotificationsModel( echoApi, mockCounter, {
type: 'alert',
source: 'test',
limit: 25,
userLang: 'en'
} );
model.addItems( test.items );
if ( test.add ) {
model.addItems( test.add.items );
}
if ( test.run ) {
for ( r = 0; r < test.run.length; r++ ) {
runCase = test.run[ r ];
runItem = test.items[ runCase.item ];
runItem[ runCase.method ].apply( runItem, runCase.args );
}
}
assert.deepEqual( getIdArray( model.getItems() ), test.expected, test.msg );
}, this );
} );
QUnit.test( 'Deleting notifications', 2, function ( assert ) {
var model = new mw.echo.dm.NotificationsModel( echoApi, mockCounter, {
type: 'alert',
source: 'test',
limit: 25,
userLang: 'en'
} ),
items = [
new mw.echo.dm.NotificationItem( 1, { content: '1', timestamp: '20150828172900' } ),
new mw.echo.dm.NotificationItem( 2, { content: '2', timestamp: '20150828172900' } ),
new mw.echo.dm.NotificationItem( 3, { content: '3', timestamp: '20150828172900' } ),
new mw.echo.dm.NotificationItem( 4, { content: '4', timestamp: '20150828172900' } ),
new mw.echo.dm.NotificationItem( 5, { content: '5', timestamp: '20150828172900' } ),
new mw.echo.dm.NotificationItem( 6, { content: '6', timestamp: '20150828172900' } ),
new mw.echo.dm.NotificationItem( 7, { content: '7', timestamp: '20150828172900' } ),
new mw.echo.dm.NotificationItem( 8, { content: '8', timestamp: '20150828172900' } ),
new mw.echo.dm.NotificationItem( 9, { content: '9', timestamp: '20150828172900' } ),
new mw.echo.dm.NotificationItem( 10, { content: '10', timestamp: '20150828172900' } )
];
// Add initial notifications
model.addItems( items );
// Verify we have the correct number initially
assert.equal( model.getItemCount(), 10, 'Added initial number of notifications' );
// Remove notifications
model.removeItems( [ items[ 0 ], items[ 1 ], items[ 5 ] ] );
// Test
assert.equal( model.getItemCount(), 7, 'Successfully deleted notifications' );
} );
QUnit.test( 'Clearing notifications', function ( assert ) {
var i, ilen, model, actual, test,
cases = [
{
prepare: [
{
method: 'addItems',
params: [
[
new mw.echo.dm.NotificationItem( 1, {
content: '1',
timestamp: '20150828172900'
} ),
new mw.echo.dm.NotificationItem( 2, { content: '2', timestamp: '20150828172900' } )
]
]
},
{
method: 'clearItems'
}
],
run: {
method: 'getItemCount'
},
expect: 0,
message: 'Clearing notifications'
}
];
assert.expect( cases.length );
for ( i = 0, ilen = cases.length; i < ilen; i++ ) {
model = new mw.echo.dm.NotificationsModel( echoApi, mockCounter, {
type: 'alert',
source: 'test',
limit: 25,
userLang: 'en'
} );
test = cases[ i ];
// Run preparation
runPreparation( model, test.prepare );
// Test
actual = model[ test.run.method ].apply( model, cases[ i ].run.params );
assert.equal( actual, cases[ i ].expect, cases[ i ].message );
}
} );
QUnit.test( 'Changing read/unread status', function ( assert ) {
var i,
initialItems = [
new mw.echo.dm.NotificationItem( 0, { timestamp: '20150828173000', read: false } ),
new mw.echo.dm.NotificationItem( 1, { timestamp: '20150828173100', read: false } ),
new mw.echo.dm.NotificationItem( 2, { timestamp: '20150828173200', read: false } ),
new mw.echo.dm.NotificationItem( 3, { timestamp: '20150828173300', read: false } ),
// Notice that in item 4 the timestamp is earlier
new mw.echo.dm.NotificationItem( 4, { timestamp: '20150828172900', read: true } ),
new mw.echo.dm.NotificationItem( 5, { timestamp: '20150828173500', read: true } )
],
cases = [
{
items: initialItems,
expected: [ 3, 2, 1, 0, 5, 4 ],
msg: 'Items organized by read/unread groups'
},
{
items: initialItems,
markRead: [ initialItems[ 1 ], initialItems[ 3 ] ],
expected: [ 2, 0, 5, 3, 1, 4 ],
msg: 'Items marked as read are pushed to the end'
}
];
QUnit.expect( cases.length );
cases.forEach( function ( test ) {
var model = new mw.echo.dm.NotificationsModel( echoApi, mockCounter, {
type: 'alert',
source: 'test',
limit: 25,
userLang: 'en'
} );
model.addItems( test.items );
if ( test.markRead ) {
for ( i = 0; i < test.markRead.length; i++ ) {
test.markRead[ i ].toggleRead( true );
}
}
assert.deepEqual( getIdArray( model.getItems() ), test.expected, test.msg );
}, this );
} );
} )( mediaWiki, jQuery );