jenkins-bot has submitted this change and it was merged.

Change subject: Add a NetworkHandler as a central API authority to Echo
......................................................................


Add a NetworkHandler as a central API authority to Echo

This is in preparation for dealing with cross-wiki notifications
where we may need several types of operations to extract bundled
notifications from local and external APIs.

Also, renamed files:
* mw.echo.dm.AbstractAPIHandler -> mw.echo.dm.APIHandler
* mw.echo.dm.APIHandler -> mw.echo.dm.LocalAPIHandler
* All API-related handler files moved to their own folder
  for better organization.

Change-Id: Ib730c780ea52c93a6026c5d0b22012b6f39bb50d
---
M Resources.php
M modules/ext.echo.init.js
R modules/viewmodel/handlers/mw.echo.dm.APIHandler.js
A modules/viewmodel/handlers/mw.echo.dm.ForeignAPIHandler.js
R modules/viewmodel/handlers/mw.echo.dm.LocalAPIHandler.js
A modules/viewmodel/handlers/mw.echo.dm.NetworkHandler.js
M modules/viewmodel/mw.echo.dm.NotificationsModel.js
M tests/qunit/viewmodel/test_mw.echo.dm.NotificationsModel.js
8 files changed, 194 insertions(+), 54 deletions(-)

Approvals:
  Catrope: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/Resources.php b/Resources.php
index a63d26e..072adf9 100644
--- a/Resources.php
+++ b/Resources.php
@@ -87,11 +87,12 @@
        'ext.echo.dm' => $echoResourceTemplate + array(
                'scripts' => array(
                        'viewmodel/mw.echo.dm.js',
-                       'viewmodel/mw.echo.dm.NotificationItem.js',
-                       'viewmodel/mw.echo.dm.AbstractAPIHandler.js',
-                       'viewmodel/mw.echo.dm.APIHandler.js',
                        'viewmodel/mw.echo.dm.List.js',
                        'viewmodel/mw.echo.dm.SortedList.js',
+                       'viewmodel/handlers/mw.echo.dm.APIHandler.js',
+                       'viewmodel/handlers/mw.echo.dm.LocalAPIHandler.js',
+                       'viewmodel/handlers/mw.echo.dm.NetworkHandler.js',
+                       'viewmodel/mw.echo.dm.NotificationItem.js',
                        'viewmodel/mw.echo.dm.NotificationList.js',
                        'viewmodel/mw.echo.dm.NotificationsModel.js',
                ),
diff --git a/modules/ext.echo.init.js b/modules/ext.echo.init.js
index 0d84e4f..42c5e77 100644
--- a/modules/ext.echo.init.js
+++ b/modules/ext.echo.init.js
@@ -46,10 +46,10 @@
 
                        // Fire the notification API requests
                        apiRequest = new mw.Api( { ajax: { cache: false } } 
).get( $.extend( { notsections: myType }, mw.echo.apiCallParams ) )
-                                       .then( function ( data ) {
-                                               mw.track( 
'timing.MediaWiki.echo.overlay.api', mw.now() - time );
-                                               return data;
-                                       } );
+                               .then( function ( data ) {
+                                       mw.track( 
'timing.MediaWiki.echo.overlay.api', mw.now() - time );
+                                       return data;
+                               } );
 
                        // Load the ui
                        mw.loader.using( 'ext.echo.ui', function () {
@@ -58,10 +58,9 @@
                                // Load message button and popup if messages 
exist
                                if ( $existingMessageLink.length ) {
                                        messageNotificationsModel = new 
mw.echo.dm.NotificationsModel(
-                                               new mw.echo.dm.APIHandler( {
+                                               // Create a network handler
+                                               new mw.echo.dm.NetworkHandler( {
                                                        type: 'message',
-                                                       limit: 25,
-                                                       userLang: 
mw.config.get( 'wgUserLanguage' ),
                                                        baseParams: 
mw.echo.apiCallParams
                                                } ),
                                                {
@@ -88,13 +87,11 @@
                                                        .text( mw.msg( 'mytalk' 
) );
                                        } );
                                }
-
                                // Load alerts popup and button
                                alertNotificationsModel = new 
mw.echo.dm.NotificationsModel(
-                                       new mw.echo.dm.APIHandler( {
+                                       // Create a network handler
+                                       new mw.echo.dm.NetworkHandler( {
                                                type: 'alert',
-                                               limit: 25,
-                                               userLang: mw.config.get( 
'wgUserLanguage' ),
                                                baseParams: 
mw.echo.apiCallParams
                                        } ),
                                        {
diff --git a/modules/viewmodel/mw.echo.dm.AbstractAPIHandler.js 
b/modules/viewmodel/handlers/mw.echo.dm.APIHandler.js
similarity index 77%
rename from modules/viewmodel/mw.echo.dm.AbstractAPIHandler.js
rename to modules/viewmodel/handlers/mw.echo.dm.APIHandler.js
index 1ce0a38..97b6320 100644
--- a/modules/viewmodel/mw.echo.dm.AbstractAPIHandler.js
+++ b/modules/viewmodel/handlers/mw.echo.dm.APIHandler.js
@@ -14,7 +14,7 @@
         * @cfg {string} [type='alert'] Notification type
         * @cfg {string} [userLang='en'] User language
         */
-       mw.echo.dm.AbstractAPIHandler = function MwEchoDmAPIHandler( config ) {
+       mw.echo.dm.APIHandler = function MwEchoDmAPIHandler( config ) {
                config = config || {};
 
                // Mixin constructor
@@ -33,8 +33,8 @@
 
        /* Setup */
 
-       OO.initClass( mw.echo.dm.AbstractAPIHandler );
-       OO.mixinClass( mw.echo.dm.AbstractAPIHandler, OO.EventEmitter );
+       OO.initClass( mw.echo.dm.APIHandler );
+       OO.mixinClass( mw.echo.dm.APIHandler, OO.EventEmitter );
 
        /**
         * Fetch notifications from the API.
@@ -46,7 +46,7 @@
         * @return {jQuery.Promise} A promise that resolves with an object 
containing the
         *  notification items
         */
-       mw.echo.dm.AbstractAPIHandler.prototype.fetchNotifications = null;
+       mw.echo.dm.APIHandler.prototype.fetchNotifications = null;
 
        /**
         * Update the seen timestamp
@@ -55,7 +55,7 @@
         *  an array of both.
         * @return {jQuery.Promise} A promise that resolves with the seen 
timestamp
         */
-       mw.echo.dm.AbstractAPIHandler.prototype.updateSeenTime = null;
+       mw.echo.dm.APIHandler.prototype.updateSeenTime = null;
 
        /**
         * Mark all notifications as read
@@ -63,7 +63,7 @@
         * @return {jQuery.Promise} A promise that resolves when all 
notifications
         *  are marked as read.
         */
-       mw.echo.dm.AbstractAPIHandler.prototype.markAllRead = null;
+       mw.echo.dm.APIHandler.prototype.markAllRead = null;
 
        /**
         * Update the read status of a notification item in the API
@@ -72,7 +72,7 @@
         * @return {jQuery.Promise} A promise that resolves when the 
notifications
         *  are marked as read.
         */
-       mw.echo.dm.AbstractAPIHandler.prototype.markItemRead = null;
+       mw.echo.dm.APIHandler.prototype.markItemRead = null;
 
        /**
         * Query the API for unread count of the notifications in this model
@@ -80,14 +80,14 @@
         * @return {jQuery.Promise} jQuery promise that's resolved when the 
unread count is fetched
         *  and the badge label is updated.
         */
-       mw.echo.dm.AbstractAPIHandler.prototype.fetchUnreadCount = null;
+       mw.echo.dm.APIHandler.prototype.fetchUnreadCount = null;
 
        /**
         * Check whether the model is fetching notifications from the API
         *
         * @return {boolean} The model is in the process of fetching from the 
API
         */
-       mw.echo.dm.AbstractAPIHandler.prototype.isFetchingNotifications = 
function () {
+       mw.echo.dm.APIHandler.prototype.isFetchingNotifications = function () {
                return !!this.fetchNotificationsPromise;
        };
 
@@ -96,7 +96,7 @@
         *
         * @return {boolean} The model is in API error state
         */
-       mw.echo.dm.AbstractAPIHandler.prototype.isFetchingErrorState = function 
() {
+       mw.echo.dm.APIHandler.prototype.isFetchingErrorState = function () {
                return !!this.apiErrorState;
        };
 
@@ -105,7 +105,7 @@
         * @return {jQuery.Promise} Promise that is resolved when notifications 
are
         *  fetched from the API.
         */
-       mw.echo.dm.AbstractAPIHandler.prototype.getFetchNotificationPromise = 
function () {
+       mw.echo.dm.APIHandler.prototype.getFetchNotificationPromise = function 
() {
                return this.fetchNotificationsPromise;
        };
 
@@ -114,7 +114,7 @@
         *
         * @return {Object} Base API params
         */
-       mw.echo.dm.AbstractAPIHandler.prototype.getBaseParams = function () {
+       mw.echo.dm.APIHandler.prototype.getBaseParams = function () {
                return this.baseParams;
        };
 } )( mediaWiki );
diff --git a/modules/viewmodel/handlers/mw.echo.dm.ForeignAPIHandler.js 
b/modules/viewmodel/handlers/mw.echo.dm.ForeignAPIHandler.js
new file mode 100644
index 0000000..3f0de65
--- /dev/null
+++ b/modules/viewmodel/handlers/mw.echo.dm.ForeignAPIHandler.js
@@ -0,0 +1,25 @@
+( function ( mw ) {
+       /**
+        * Foreign notification API handler
+        *
+        * @class
+        * @extends mw.echo.dm.LocalAPIHandler
+        *
+        * @constructor
+        * @param {string} apiUrl A url for the access point of the
+        *  foreign API.
+        * @param {Object} [config] Configuration object
+        */
+       mw.echo.dm.ForeignAPIHandler = function MwEchoDmForeignAPIHandler( 
apiUrl, config ) {
+               config = config || {};
+
+               // Parent constructor
+               mw.echo.dm.ForeignAPIHandler.parent.call( this, config );
+
+               this.api = new mw.ForeignApi( apiUrl );
+       };
+
+       /* Setup */
+
+       OO.inheritClass( mw.echo.dm.ForeignAPIHandler, 
mw.echo.dm.LocalAPIHandler );
+} )( mediaWiki );
diff --git a/modules/viewmodel/mw.echo.dm.APIHandler.js 
b/modules/viewmodel/handlers/mw.echo.dm.LocalAPIHandler.js
similarity index 73%
rename from modules/viewmodel/mw.echo.dm.APIHandler.js
rename to modules/viewmodel/handlers/mw.echo.dm.LocalAPIHandler.js
index 7818daa..0bc500a 100644
--- a/modules/viewmodel/mw.echo.dm.APIHandler.js
+++ b/modules/viewmodel/handlers/mw.echo.dm.LocalAPIHandler.js
@@ -3,28 +3,28 @@
         * Notification API handler
         *
         * @class
-        * @extends mw.echo.dm.AbstractAPIHandler
+        * @extends mw.echo.dm.APIHandler
         *
         * @constructor
         * @param {Object} [config] Configuration object
         */
-       mw.echo.dm.APIHandler = function MwEchoDmAPIHandler( config ) {
+       mw.echo.dm.LocalAPIHandler = function MwEchoDmLocalAPIHandler( config ) 
{
                config = config || {};
 
                // Parent constructor
-               mw.echo.dm.APIHandler.parent.call( this, config );
+               mw.echo.dm.LocalAPIHandler.parent.call( this, config );
 
                this.api = new mw.Api( { ajax: { cache: false } } );
        };
 
        /* Setup */
 
-       OO.inheritClass( mw.echo.dm.APIHandler, mw.echo.dm.AbstractAPIHandler );
+       OO.inheritClass( mw.echo.dm.LocalAPIHandler, mw.echo.dm.APIHandler );
 
        /**
         * @inheritdoc
         */
-       mw.echo.dm.APIHandler.prototype.fetchNotifications = function ( 
apiPromise ) {
+       mw.echo.dm.LocalAPIHandler.prototype.fetchNotifications = function ( 
apiPromise ) {
                var helper = this,
                        params = $.extend( { notsections: this.type }, 
this.getBaseParams() );
 
@@ -46,7 +46,7 @@
        /**
         * @inheritdoc
         */
-       mw.echo.dm.APIHandler.prototype.updateSeenTime = function ( type ) {
+       mw.echo.dm.LocalAPIHandler.prototype.updateSeenTime = function ( type ) 
{
                type = type || this.type;
 
                return this.api.postWithToken( 'edit', {
@@ -63,12 +63,12 @@
        /**
         * @inheritdoc
         */
-       mw.echo.dm.APIHandler.prototype.markAllRead = function () {
+       mw.echo.dm.LocalAPIHandler.prototype.markAllRead = function () {
                var model = this,
                        data = {
                                action: 'echomarkread',
                                uselang: this.userLang,
-                               sections: this.type
+                               sections: $.isArray( this.type ) ? 
this.type.join( '|' ) : this.type
                        };
 
                return this.api.postWithToken( 'edit', data )
@@ -80,7 +80,7 @@
        /**
         * @inheritdoc
         */
-       mw.echo.dm.APIHandler.prototype.markItemRead = function ( itemId ) {
+       mw.echo.dm.LocalAPIHandler.prototype.markItemRead = function ( itemId ) 
{
                var model = this,
                        data = {
                                action: 'echomarkread',
@@ -97,11 +97,11 @@
        /**
         * @inheritdoc
         */
-       mw.echo.dm.APIHandler.prototype.fetchUnreadCount = function () {
+       mw.echo.dm.LocalAPIHandler.prototype.fetchUnreadCount = function () {
                var apiData = {
                                action: 'query',
                                meta: 'notifications',
-                               notsections: this.type,
+                               notsections: $.isArray( this.type ) ? 
this.type.join( '|' ) : this.type,
                                notmessageunreadfirst: 1,
                                notlimit: this.limit,
                                notprop: 'index|count',
diff --git a/modules/viewmodel/handlers/mw.echo.dm.NetworkHandler.js 
b/modules/viewmodel/handlers/mw.echo.dm.NetworkHandler.js
new file mode 100644
index 0000000..b1e90aa
--- /dev/null
+++ b/modules/viewmodel/handlers/mw.echo.dm.NetworkHandler.js
@@ -0,0 +1,92 @@
+( function ( mw, $ ) {
+       /**
+        * Network handler for echo notifications. Manages multiple APIHandlers
+        * according to their sources.
+        *
+        * @class
+        * @mixins OO.EventEmitter
+        *
+        * @constructor
+        * @param {Object} [config] Configuration object
+        * @cfg {string} [type="alert"] Notification type
+        * @cfg {Object} [baseParams] The base params to send to the
+        *  APIs with every fetch notifications process.
+        */
+       mw.echo.dm.NetworkHandler = function MwEchoDmNetworkHandler( config ) {
+               config = config || {};
+
+               // Mixin constructor
+               OO.EventEmitter.call( this );
+
+               this.type = config.type || 'alert';
+               this.baseParams = config.baseParams || {};
+               this.handlers = {};
+
+               // Add initial local handler
+               this.addApiHandler( 'local', {} );
+       };
+
+       /* Setup */
+
+       OO.initClass( mw.echo.dm.NetworkHandler );
+       OO.mixinClass( mw.echo.dm.NetworkHandler, OO.EventEmitter );
+
+       /* Methods */
+
+       /**
+        * Get the API handler that matches the symbolic name
+        *
+        * @param {string} name Symbolic name of the API handler
+        * @return {mw.echo.dm.APIHandler|undefined} API handler, if exists
+        */
+       mw.echo.dm.NetworkHandler.prototype.getApiHandler = function ( name ) {
+               return this.handlers[ name ];
+       };
+
+       /**
+        * Add an API handler
+        *
+        * @param {string} name Symbolic name
+        * @param {Object} config Configuration details
+        * @param {boolean} isExternal Is an external API
+        * @throws {Error} If no URL was given for a foreign API
+        */
+       mw.echo.dm.NetworkHandler.prototype.addApiHandler = function ( name, 
config, isExternal ) {
+               var apiConfig;
+
+               if ( !this.handlers[ name ] ) {
+                       apiConfig = $.extend( true, {}, { baseParams: 
this.baseParams, type: this.getType() }, config );
+
+                       if ( isExternal ) {
+                               if ( !config.url ) {
+                                       throw new Error( 'External APIs must 
have a valid url.' );
+                               }
+                               this.addCustomApiHandler( name, new 
mw.echo.dm.ForeignAPIHandler( config.url, apiConfig ) );
+                       } else {
+                               this.addCustomApiHandler( name, new 
mw.echo.dm.LocalAPIHandler( apiConfig ) );
+                       }
+               }
+       };
+
+       /**
+        * Add a custom API handler by passing in an instance of an 
mw.echo.dm.APIHandler subclass directly.
+        *
+        * @param {string} name Symbolic name
+        * @param {mw.echo.dm.APIHandler} handler Handler object
+        */
+       mw.echo.dm.NetworkHandler.prototype.addCustomApiHandler = function ( 
name, handler ) {
+               if ( !this.handlers[ name ] ) {
+                       this.handlers[ name ] = handler;
+               }
+       };
+
+       /**
+        * Get the type of notifications this network handler is associated with
+        *
+        * @return {string} Notification type
+        */
+       mw.echo.dm.NetworkHandler.prototype.getType = function () {
+               return this.type;
+       };
+
+} )( mediaWiki, jQuery );
diff --git a/modules/viewmodel/mw.echo.dm.NotificationsModel.js 
b/modules/viewmodel/mw.echo.dm.NotificationsModel.js
index 4904297..874f19f 100644
--- a/modules/viewmodel/mw.echo.dm.NotificationsModel.js
+++ b/modules/viewmodel/mw.echo.dm.NotificationsModel.js
@@ -6,14 +6,16 @@
         * @mixins OO.EventEmitter
         *
         * @constructor
-        * @param {mw.echo.dm.AbstractAPIHandler} apiHandler API handler
+        * @param {mw.echo.dm.NetworkHandler} networkHandler Network handler
         * @param {Object} [config] Configuration object
         * @cfg {string|string[]} [type='alert'] Notification type 'alert', 
'message'
         *  or an array [ 'alert', 'message' ]
+        * @cfg {string} [source='local'] Model source, 'local' or some 
symbolic name identifying
+        *  the source of the notification items for the network handler.
         * @cfg {number} [limit=25] Notification limit
         * @cfg {string} [userLang] User language
         */
-       mw.echo.dm.NotificationsModel = function MwEchoDmNotificationsModel( 
apiHandler, config ) {
+       mw.echo.dm.NotificationsModel = function MwEchoDmNotificationsModel( 
networkHandler, config ) {
                config = config || {};
 
                // Mixin constructor
@@ -23,8 +25,9 @@
                mw.echo.dm.SortedList.call( this );
 
                this.type = config.type || 'alert';
+               this.source = config.source || 'local';
 
-               this.apiHandler = apiHandler;
+               this.networkHandler = networkHandler;
 
                this.seenTime = mw.config.get( 'wgEchoSeenTime' ) || {};
 
@@ -244,7 +247,7 @@
                }
                this.emit( 'updateSeenTime' );
 
-               return this.apiHandler.updateSeenTime( type )
+               return this.getApi().updateSeenTime( type )
                        .then( this.setSeenTime.bind( this ) );
        };
 
@@ -261,7 +264,7 @@
                        return $.Deferred().resolve( 0 ).promise();
                }
 
-               return this.apiHandler.markAllRead()
+               return this.getApi().markAllRead()
                        .then( function () {
                                var i, len,
                                        items = 
model.unreadNotifications.getItems();
@@ -286,7 +289,7 @@
                        return $.Deferred().resolve( 0 ).promise();
                }
 
-               return this.apiHandler.markItemRead( itemId );
+               return this.getApi().markItemRead( itemId );
        };
 
        /**
@@ -304,7 +307,7 @@
 
                // Rebuild the notifications promise either when it is null or 
when
                // it exists in a failed state
-               return this.apiHandler.fetchNotifications( apiPromise )
+               return this.getApi().fetchNotifications( apiPromise )
                        .then( function ( result ) {
                                var notifData, i, len, t, tlen, $content,
                                        notificationModel, types,
@@ -410,7 +413,7 @@
         *  and the badge label is updated.
         */
        mw.echo.dm.NotificationsModel.prototype.fetchUnreadCountFromApi = 
function () {
-               return this.apiHandler.fetchUnreadCount();
+               return this.getApi().fetchUnreadCount();
        };
 
        /**
@@ -419,7 +422,7 @@
         * @return {boolean} The model is in the process of fetching from the 
API
         */
        mw.echo.dm.NotificationsModel.prototype.isFetchingNotifications = 
function () {
-               return this.apiHandler.isFetchingNotifications();
+               return this.getApi().isFetchingNotifications();
        };
 
        /**
@@ -428,7 +431,7 @@
         * @return {boolean} The model is in api error state
         */
        mw.echo.dm.NotificationsModel.prototype.isFetchingErrorState = function 
() {
-               return this.apiHandler.isFetchingErrorState();
+               return this.getApi().isFetchingErrorState();
        };
 
        /**
@@ -437,6 +440,16 @@
         *  fetched from the API.
         */
        mw.echo.dm.NotificationsModel.prototype.getFetchNotificationPromise = 
function () {
-               return this.apiHandler.getFetchNotificationPromise();
+               return this.getApi().getFetchNotificationPromise();
        };
+
+       /**
+        * Get the API handler associated with this model's source
+        *
+        * @return {mw.echo.dm.APIHandler} API handler
+        */
+       mw.echo.dm.NotificationsModel.prototype.getApi = function () {
+               return this.networkHandler.getApiHandler( this.source );
+       };
+
 } )( mediaWiki, jQuery );
diff --git a/tests/qunit/viewmodel/test_mw.echo.dm.NotificationsModel.js 
b/tests/qunit/viewmodel/test_mw.echo.dm.NotificationsModel.js
index 7a6e53d..3a42174 100644
--- a/tests/qunit/viewmodel/test_mw.echo.dm.NotificationsModel.js
+++ b/tests/qunit/viewmodel/test_mw.echo.dm.NotificationsModel.js
@@ -22,7 +22,7 @@
                TestApiHandler.parent.call( this );
        }
        /* Setup */
-       OO.inheritClass( TestApiHandler, mw.echo.dm.AbstractAPIHandler );
+       OO.inheritClass( TestApiHandler, mw.echo.dm.APIHandler );
        // Override api call
        TestApiHandler.prototype.markItemRead = function () {
                return $.Deferred().resolve( 0 );
@@ -88,12 +88,15 @@
 
                cases.forEach( function ( test ) {
                        var r, runCase, runItem,
-                               model = new mw.echo.dm.NotificationsModel( new 
TestApiHandler(), {
+                               networkHandler = new 
mw.echo.dm.NetworkHandler(),
+                               model = new mw.echo.dm.NotificationsModel( 
networkHandler, {
                                        type: 'alert',
+                                       source: 'test',
                                        limit: 25,
                                        userLang: 'en'
                                } );
 
+                       networkHandler.addCustomApiHandler( 'test', new 
TestApiHandler() );
                        model.addItems( test.items );
 
                        if ( test.add ) {
@@ -112,8 +115,10 @@
        } );
 
        QUnit.test( 'Deleting notifications', 2, function ( assert ) {
-               var model = new mw.echo.dm.NotificationsModel( new 
TestApiHandler(), {
+               var networkHandler = new mw.echo.dm.NetworkHandler(),
+                       model = new mw.echo.dm.NotificationsModel( 
networkHandler, {
                                type: 'alert',
+                               source: 'test',
                                limit: 25,
                                userLang: 'en'
                        } ),
@@ -130,6 +135,7 @@
                                new mw.echo.dm.NotificationItem( 10, { content: 
'10', timestamp: '20150828172900' } )
                        ];
 
+               networkHandler.addCustomApiHandler( 'test', new 
TestApiHandler() );
                // Add initial notifications
                model.addItems( items );
 
@@ -145,6 +151,7 @@
 
        QUnit.test( 'Clearing notifications', function ( assert ) {
                var i, ilen, model, actual, test,
+                       networkHandler = new mw.echo.dm.NetworkHandler(),
                        cases = [
                                {
                                        prepare: [
@@ -175,11 +182,14 @@
                assert.expect( cases.length );
 
                for ( i = 0, ilen = cases.length; i < ilen; i++ ) {
-                       model = new mw.echo.dm.NotificationsModel( new 
TestApiHandler(), {
+                       model = new mw.echo.dm.NotificationsModel( 
networkHandler, {
                                type: 'alert',
+                               source: 'test',
                                limit: 25,
                                userLang: 'en'
                        } );
+
+                       networkHandler.addCustomApiHandler( 'test', new 
TestApiHandler() );
 
                        test = cases[ i ];
 
@@ -194,6 +204,7 @@
 
        QUnit.test( 'Changing read/unread status', function ( assert ) {
                var i,
+                       networkHandler = new mw.echo.dm.NetworkHandler(),
                        initialItems = [
                                new mw.echo.dm.NotificationItem( 0, { 
timestamp: '20150828173000', read: false } ),
                                new mw.echo.dm.NotificationItem( 1, { 
timestamp: '20150828173100', read: false } ),
@@ -220,13 +231,14 @@
                QUnit.expect( cases.length );
 
                cases.forEach( function ( test ) {
-                       var apiHandler = new TestApiHandler(),
-                               model = new mw.echo.dm.NotificationsModel( 
apiHandler, {
+                       var model = new mw.echo.dm.NotificationsModel( 
networkHandler, {
                                        type: 'alert',
+                                       source: 'test',
                                        limit: 25,
                                        userLang: 'en'
                                } );
 
+                       networkHandler.addCustomApiHandler( 'test', new 
TestApiHandler() );
                        model.addItems( test.items );
 
                        if ( test.markRead ) {

-- 
To view, visit https://gerrit.wikimedia.org/r/252597
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ib730c780ea52c93a6026c5d0b22012b6f39bb50d
Gerrit-PatchSet: 10
Gerrit-Project: mediawiki/extensions/Echo
Gerrit-Branch: master
Gerrit-Owner: Mooeypoo <mor...@gmail.com>
Gerrit-Reviewer: Catrope <roan.katt...@gmail.com>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to