jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/348795 )

Change subject: Hygiene: Refactor Notification code - add NotificationBadge 
class
......................................................................


Hygiene: Refactor Notification code - add NotificationBadge class

The code is very brittle here as the NotificationOverlay
communicates with the NotificationBadge. NotificationOverlay assumes
HTML markup rather than uses reliable methods to communicate changes.

This formalises their relationship.

To render the badge on the client the secondaryButton template is
now shipped to the client.

Tests have been added to cover behaviour.
The module lives in skins.minerva.notifications.badge to avoid pulling
all skins.minerva.notifications modules into the environment which can
lead to side effects due to the unconditional wiring up many of these modules
do to the existing HTML. It is not added to mobile.notifications.overlay to
avoid pulling OOjs UI into the startup JavaScript.

Additional changes:
* Migrate Minerva specific onResourceLoaderRegisterModules code
into Minerva.hooks
* Now loadModuleScript lives inside NotificationBadge revert to using
loader.using - this also has the benefit of not removing the notification
badge icon in the top right corner
* Drop the .zero display:none rule as now only one of the badges is rendered
at any given time.

Change-Id: I246ed23164ff3f7ef8ea15896a9b3a0d19c2bb0d
---
M extension.json
M includes/Minerva.hooks.php
M includes/MobileFrontend.hooks.php
M includes/skins/SkinMinerva.php
M includes/skins/minerva.mustache
M includes/skins/secondaryButton.mustache
M resources/mobile.notifications.overlay/NotificationsOverlay.js
M resources/skins.minerva.base.styles/ui.less
A resources/skins.minerva.notifications.badge/NotificationBadge.js
M resources/skins.minerva.notifications/init.js
M tests/phpunit/skins/SkinMinervaTest.php
A tests/qunit/skins.minerva.notifications.badge/test_NotificationBadge.js
12 files changed, 313 insertions(+), 127 deletions(-)

Approvals:
  Pmiazga: Looks good to me, but someone else must approve
  Jhernandez: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/extension.json b/extension.json
index 329af48..d119b23 100644
--- a/extension.json
+++ b/extension.json
@@ -1653,6 +1653,7 @@
                        "MobileFrontendHooks::onDiffViewHeader"
                ],
                "ResourceLoaderTestModules": [
+                       "MinervaHooks::onResourceLoaderTestModules",
                        "MobileFrontendHooks::onResourceLoaderTestModules"
                ],
                "GetCacheVaryCookies": [
@@ -1705,6 +1706,7 @@
                        "MobileFrontendHooks::onCentralAuthSilentLoginRedirect"
                ],
                "ResourceLoaderRegisterModules": [
+                       "MinervaHooks::onResourceLoaderRegisterModules",
                        "MobileFrontendHooks::onResourceLoaderRegisterModules"
                ],
                "EventLoggingRegisterSchemas": [
diff --git a/includes/Minerva.hooks.php b/includes/Minerva.hooks.php
index 5e0956b..596c0f2 100644
--- a/includes/Minerva.hooks.php
+++ b/includes/Minerva.hooks.php
@@ -31,6 +31,33 @@
        }
 
        /**
+        * ResourceLoaderTestModules hook handler
+        * @see 
https://www.mediawiki.org/wiki/Manual:Hooks/ResourceLoaderTestModules
+        *
+        * @param array $testModules
+        * @param ResourceLoader $resourceLoader
+        * @return bool
+        */
+       public static function onResourceLoaderTestModules( array &$testModules,
+               ResourceLoader &$resourceLoader
+       ) {
+               $testModule = [
+                       'dependencies' => [
+                               'skins.minerva.notifications.badge'
+                       ],
+                       'localBasePath' => dirname( __DIR__ ),
+                       'remoteExtPath' => 'MobileFrontend',
+                       'targets' => [ 'mobile', 'desktop' ],
+                       'scripts' => [
+                               
'tests/qunit/skins.minerva.notifications.badge/test_NotificationBadge.js'
+                       ],
+               ];
+
+               // Expose templates module
+               $testModules['qunit']["tests.skins.minerva"] = $testModule;
+       }
+
+       /**
         * Invocation of hook SpecialPageBeforeExecute
         *
         * We use this hook to ensure that login/account creation pages
@@ -77,6 +104,57 @@
        }
 
        /**
+        * ResourceLoaderRegisterModules hook handler.
+        *
+        * Registers:
+        *
+        * * EventLogging schema modules, if the EventLogging extension is 
loaded;
+        * * Modules for the Visual Editor overlay, if the VisualEditor 
extension is loaded; and
+        * * Modules for the notifications overlay, if the Echo extension is 
loaded.
+        *
+        * @see 
https://www.mediawiki.org/wiki/Manual:Hooks/ResourceLoaderRegisterModules
+        *
+        * @param ResourceLoader &$resourceLoader The ResourceLoader object
+        * @return bool Always true
+        */
+       public static function onResourceLoaderRegisterModules( ResourceLoader 
&$resourceLoader ) {
+               $resourceBoilerplate = [
+                       'localBasePath' => dirname( __DIR__ ),
+                       // Rename to Minerva when you move to a skin
+                       'remoteExtPath' => 'MobileFrontend',
+               ];
+
+               if ( class_exists( 'MWEchoNotifUser' ) ) {
+                       $resourceLoader->register( [
+                               'skins.minerva.notifications.badge' => 
$resourceBoilerplate + [
+                                       'dependencies' => [
+                                               'mediawiki.router',
+                                               'mobile.startup',
+                                       ],
+                                       'scripts' => [
+                                               
'resources/skins.minerva.notifications.badge/NotificationBadge.js',
+                                       ],
+                                       'templates' => [
+                                               'badge.hogan' => 
'includes/skins/secondaryButton.mustache',
+                                       ],
+                                       'targets' => [ 'mobile', 'desktop' ],
+                               ],
+                               'skins.minerva.notifications' => 
$resourceBoilerplate + [
+                                       'dependencies' => [
+                                               
'skins.minerva.notifications.badge',
+                                               'mediawiki.ui.anchor',
+                                               'skins.minerva.scripts',
+                                       ],
+                                       'scripts' => [
+                                               
'resources/skins.minerva.notifications/init.js',
+                                       ],
+                                       'targets' => [ 'mobile', 'desktop' ],
+                               ],
+                       ] );
+               }
+       }
+
+       /**
         * BeforePageDisplayMobile hook handler.
         *
         * @param OutputPage $out
diff --git a/includes/MobileFrontend.hooks.php 
b/includes/MobileFrontend.hooks.php
index 4073c06..3b32822 100644
--- a/includes/MobileFrontend.hooks.php
+++ b/includes/MobileFrontend.hooks.php
@@ -978,18 +978,6 @@
                // add Echo, if it's installed
                if ( ExtensionRegistry::getInstance()->isLoaded( 'Echo' ) ) {
                        $resourceLoader->register( [
-                               'skins.minerva.notifications' => 
$resourceBoilerplate + [
-                                       'dependencies' => [
-                                               'mobile.startup',
-                                               'mediawiki.router',
-                                               'skins.minerva.scripts',
-                                               'mediawiki.ui.anchor'
-                                       ],
-                                       'scripts' => [
-                                               
'resources/skins.minerva.notifications/init.js',
-                                       ],
-                                       'targets' => [ 'mobile', 'desktop' ],
-                               ],
                                'mobile.notifications.overlay' => 
$resourceBoilerplate + [
                                        'dependencies' => [
                                                'mediawiki.util',
diff --git a/includes/skins/SkinMinerva.php b/includes/skins/SkinMinerva.php
index 67bc6b8..3439300 100644
--- a/includes/skins/SkinMinerva.php
+++ b/includes/skins/SkinMinerva.php
@@ -437,11 +437,12 @@
                                [ 'returnto' => 
$currentTitle->getPrefixedText() ] );
 
                        $tpl->set( 'secondaryButtonData', [
-                               'class' => MobileUI::iconClass( 'notifications' 
),
+                               'notificationIconClass' => MobileUI::iconClass( 
'notifications' ),
                                'title' => $notificationsMsg,
                                'url' => $url,
                                'notificationCount' => $countLabel,
                                'isNotificationCountZero' => $isZero,
+                               'hasNotifications' => $hasUnseen,
                                'hasUnseenNotifications' => $hasUnseen
                        ] );
                }
diff --git a/includes/skins/minerva.mustache b/includes/skins/minerva.mustache
index b082526..e43504d 100644
--- a/includes/skins/minerva.mustache
+++ b/includes/skins/minerva.mustache
@@ -32,4 +32,4 @@
                {{>footer}}
        </div>
 </div>
-<!-- v:7 -->
+<!-- v:8 -->
diff --git a/includes/skins/secondaryButton.mustache 
b/includes/skins/secondaryButton.mustache
index 205554e..59bd982 100644
--- a/includes/skins/secondaryButton.mustache
+++ b/includes/skins/secondaryButton.mustache
@@ -1,13 +1,13 @@
-{{^hasUnseenNotifications}}
+{{^hasNotifications}}
 <a href="{{url}}" title="{{title}}"
-   class="{{class}} user-button main-header-button" id="secondary-button">
+   class="{{notificationIconClass}} user-button main-header-button" 
id="secondary-button">
     {{title}}
 </a>
-{{/hasUnseenNotifications}}
-{{#hasUnseenNotifications}}
+{{/hasNotifications}}
+{{#hasNotifications}}
 <a href="{{url}}" title="{{title}}"
   id="secondary-button"
-  class="notification-count user-button notification-unseen
+  class="notification-count user-button 
{{#hasUnseenNotifications}}notification-unseen{{/hasUnseenNotifications}}
     {{#isNotificationCountZero}}zero{{/isNotificationCountZero}}">
        <div class="circle">
                 <span>
@@ -15,4 +15,4 @@
                </span>
        </div>
 </a>
-{{/hasUnseenNotifications}}
+{{/hasNotifications}}
diff --git a/resources/mobile.notifications.overlay/NotificationsOverlay.js 
b/resources/mobile.notifications.overlay/NotificationsOverlay.js
index c31d827..c21245f 100644
--- a/resources/mobile.notifications.overlay/NotificationsOverlay.js
+++ b/resources/mobile.notifications.overlay/NotificationsOverlay.js
@@ -14,13 +14,14 @@
         */
        NotificationsOverlay = function ( options ) {
                var modelManager, unreadCounter, wrapperWidget,
+                       self = this,
                        maxNotificationCount = mw.config.get( 
'wgEchoMaxNotificationCount' ),
                        echoApi = new mw.echo.api.EchoApi();
 
                Overlay.apply( this, options );
 
                // Anchor tag that corresponds to a notifications badge
-               this.$badge = options.$badge;
+               this.badge = options.badge;
                this.$overlay = $( '<div>' )
                        .addClass( 'notifications-overlay-overlay 
position-fixed' );
 
@@ -32,7 +33,6 @@
 
                mw.echo.config.maxPrioritizedActions = 1;
 
-               this.count = 0;
                this.doneLoading = false;
 
                unreadCounter = new mw.echo.dm.UnreadNotificationCounter( 
echoApi, 'all', maxNotificationCount );
@@ -87,11 +87,12 @@
                );
 
                // Populate notifications
-               wrapperWidget.populate()
-                       .then( this.setDoneLoading.bind( this ) )
-                       .then( this.controller.updateSeenTime.bind( 
this.controller ) )
-                       .then( this.setBadgeSeen.bind( this ) )
-                       .then( this.checkShowMarkAllRead.bind( this ) );
+               wrapperWidget.populate().then( function () {
+                       self.setDoneLoading();
+                       self.controller.updateSeenTime();
+                       self.badge.markAsSeen();
+                       self.checkShowMarkAllRead();
+               } );
        };
 
        OO.mfExtend( NotificationsOverlay, Overlay, {
@@ -159,7 +160,7 @@
                 * @method
                 */
                onError: function () {
-                       window.location.href = this.$badge.attr( 'href' );
+                       window.location.href = this.badge.getNotificationURL();
                },
                /**
                 * Update the unread number on the notifications badge
@@ -168,29 +169,13 @@
                 * @method
                 */
                onUnreadCountChange: function ( count ) {
-                       var $badgeCounter = this.$badge.find( 
'.notification-count' );
-                       this.count = 
this.controller.manager.getUnreadCounter().getCappedNotificationCount( count );
+                       this.badge.setCount(
+                               
this.controller.manager.getUnreadCounter().getCappedNotificationCount( count )
+                       );
 
-                       if ( this.count >= 0 ) {
-                               $badgeCounter.find( 'span' ).text(
-                                       mw.msg( 'echo-badge-count', 
mw.language.convertNumber( this.count ) )
-                               ).show();
-                       }
-                       if ( this.count === 0 ) {
-                               $badgeCounter.removeClass( 
'notification-unseen' );
-                       }
                        this.checkShowMarkAllRead();
                },
-               /**
-                * Mark that all the notifications in the badge are seen.
-                *
-                * @method
-                */
-               setBadgeSeen: function () {
-                       this.$badge
-                               .find( '.notification-count' )
-                               .removeClass( 'notification-unseen' );
-               },
+
                /** @inheritdoc */
                preRender: function () {
                        this.options.heading = '<strong>' + mw.message( 
'notifications' ).escaped() + '</strong>';
diff --git a/resources/skins.minerva.base.styles/ui.less 
b/resources/skins.minerva.base.styles/ui.less
index b3258e2..160db87 100644
--- a/resources/skins.minerva.base.styles/ui.less
+++ b/resources/skins.minerva.base.styles/ui.less
@@ -365,10 +365,6 @@
                }
        }
 
-       &.zero {
-               display: none;
-       }
-
        // FIXME: There must be a better way of doing this
        &.max {
                right: 0.2em;
diff --git a/resources/skins.minerva.notifications.badge/NotificationBadge.js 
b/resources/skins.minerva.notifications.badge/NotificationBadge.js
new file mode 100644
index 0000000..91149e4
--- /dev/null
+++ b/resources/skins.minerva.notifications.badge/NotificationBadge.js
@@ -0,0 +1,147 @@
+( function ( M ) {
+       var View = M.require( 'mobile.startup/View' ),
+               Icon = M.require( 'mobile.startup/Icon' ),
+               notificationIcon = new Icon( { name: 'notifications' } ),
+               icons = M.require( 'mobile.startup/icons' );
+
+       /**
+        * A notification button for communicating with an NotificationOverlay
+        * @class NotificationButton
+        * @extends View
+        *
+        * @constructor
+        * @param {Object} options Configuration options
+        */
+       function NotificationBadge( options ) {
+               var $el,
+                       el = options.el;
+
+               if ( el ) {
+                       $el = $( el );
+                       options.hasUnseenNotifications = $el.find( 
'.notification-unseen' ).length;
+                       options.hasNotifications = 
options.hasUnseenNotifications;
+                       options.title = $el.find( 'a' ).attr( 'title' );
+                       options.url = $el.find( 'a' ).attr( 'href' );
+                       options.notificationCount = parseInt( $el.find( 'span' 
).text(), 10 );
+               }
+               View.call( this, options );
+               this.url = this.$el.find( 'a' ).attr( 'href' );
+               this._bindOverlayManager();
+       }
+
+       OO.mfExtend( NotificationBadge, View, {
+               /**
+                * @inheritdoc
+                * @cfg {Object} defaults Default options hash.
+                * @cfg {String} defaults.notificationIconClass e.g. mw-ui-icon 
for icon
+                * @cfg {String} defaults.loadingIconHtml for spinner
+                * @cfg {Boolean} defaults.hasUnseenNotifications whether the 
user has unseen notifications
+                * @cfg {Number} defaults.notificationCount number of unread 
notifications
+                */
+               defaults: {
+                       notificationIconClass: notificationIcon.getClassName(),
+                       loadingIconHtml: icons.spinner().toHtmlString(),
+                       hasNotifications: false,
+                       hasUnseenNotifications: false,
+                       notificationCount: 0
+               },
+               /**
+                * @inheritdoc
+                */
+               isBorderBox: false,
+               /**
+                * Loads a ResourceLoader module script. Shows ajax loader 
whilst loading.
+                * @method
+                * @private
+                * @param {string} moduleName Name of a module to fetch
+                * @return {jQuery.Deferred}
+                */
+               _loadModuleScript: function ( moduleName ) {
+                       var self = this;
+
+                       this.$el.html( this.options.loadingIconHtml );
+                       return mw.loader.using( moduleName ).done( function () {
+                               // trigger a re-render once one to remove 
loading icon
+                               self.render();
+                       } );
+               },
+               /**
+                * Load the notification overlay.
+                * @method
+                * @private
+                * @uses NotificationsOverlay
+                * @return {jQuery.Deferred} with an instance of 
NotificationsOverlay
+                */
+               _loadNotificationOverlay: function () {
+                       var self = this;
+
+                       return this._loadModuleScript( 
'mobile.notifications.overlay' ).then( function () {
+                               var NotificationsOverlay = M.require( 
'mobile.notifications.overlay/NotificationsOverlay' );
+                               return new NotificationsOverlay( {
+                                       badge: self
+                               } );
+                       } );
+               },
+               /**
+                * Sets up routes in overlay manager and click behaviour for 
NotificationBadge
+                * This is not unit tested as it's behaviour is covered by 
browser tests.
+                * @private
+                */
+               _bindOverlayManager: function () {
+                       var self = this,
+                               mainMenu = this.options.mainMenu;
+
+                       this.$el.on( 'click', $.proxy( this.onClickBadge, this 
) );
+                       this.options.overlayManager.add( /^\/notifications$/, 
function () {
+                               return self._loadNotificationOverlay().done( 
function ( overlay ) {
+                                       mainMenu.openNavigationDrawer( 
'secondary' );
+                                       overlay.on( 'hide', function () {
+                                               
mainMenu.closeNavigationDrawers();
+                                               $( '#mw-mf-page-center' ).off( 
'.secondary' );
+                                       } );
+
+                                       $( '#mw-mf-page-center' ).one( 
'click.secondary', function () {
+                                               self.options.router.back();
+                                       } );
+                               } );
+                       } );
+               },
+               /** @inheritdoc */
+               template: mw.template.get( 'skins.minerva.notifications.badge', 
'badge.hogan' ),
+               /**
+                * Click handler for clicking on the badge
+                * @return {Boolean}
+                */
+               onClickBadge: function () {
+                       this.options.router.navigate( '#/notifications' );
+                       // Important that we also prevent propagation to avoid 
interference with events that may be
+                       // binded on #mw-mf-page-center that close overlay
+                       return false;
+               },
+               /**
+                * Return the URL for the full non-overlay notification view
+                * @return {String} url
+                */
+               getNotificationURL: function () {
+                       return this.options.url;
+               },
+               /**
+                * Update the notification count
+                * @param {Number} count
+                */
+               setCount: function ( count ) {
+                       this.options.notificationCount = count;
+                       this.options.isNotificationCountZero = count === 0;
+                       this.render();
+               },
+               /**
+                * Marks all notifications as seen
+                */
+               markAsSeen: function () {
+                       this.options.hasUnseenNotifications = false;
+                       this.render();
+               }
+       } );
+
+       M.define( 'skins.minerva.notifications/NotificationBadge', 
NotificationBadge );
+}( mw.mobileFrontend ) );
diff --git a/resources/skins.minerva.notifications/init.js 
b/resources/skins.minerva.notifications/init.js
index 6ef9770..db0a2a7 100644
--- a/resources/skins.minerva.notifications/init.js
+++ b/resources/skins.minerva.notifications/init.js
@@ -2,87 +2,22 @@
  * This code loads the necessary modules for the notifications overlay, not to 
be confused
  * with the Toast notifications defined by common/toast.js.
  */
-( function ( M, $, mw ) {
+( function ( M, $ ) {
        var mainMenu = M.require( 'skins.minerva.scripts/skin' ).getMainMenu(),
-               $btn = $( '#secondary-button.user-button' ).parent(),
                router = require( 'mediawiki.router' ),
+               NotificationBadge = M.require( 
'skins.minerva.notifications/NotificationBadge' ),
                overlayManager = M.require( 
'skins.minerva.scripts/overlayManager' ),
-               icons = M.require( 'mobile.startup/icons' ),
                initialized = false;
-
-       /**
-        * Loads a ResourceLoader module script. Shows ajax loader whilst 
loading.
-        * @method
-        * @ignore
-        * FIXME: Upstream to mw.mobileFrontend and reuse elsewhere
-        * @param {string} moduleName Name of a module to fetch
-        * @return {jQuery.Deferred}
-        */
-       function loadModuleScript( moduleName ) {
-               var $spinner = $( icons.spinner().toHtmlString() );
-
-               $btn.hide().after( $spinner );
-               return mw.loader.using( moduleName ).then( function () {
-                       // FIXME: Some code uses the loading class while other 
code uses the
-                       // spinner class. Make all code consistent so it's 
easier to change.
-                       $spinner.remove();
-                       $btn.show();
-               } );
-       }
 
        // Once the DOM is loaded hijack the notifications button to display an 
overlay rather
        // than linking to Special:Notifications.
        $( function () {
-
-               /**
-                * Click event handler which opens the drawer and disables 
default link behaviour
-                * @method
-                * @ignore
-                * @return {Boolean}
-                */
-               function openNavigationDrawer() {
-                       router.navigate( '#/notifications' );
-                       // Important that we also prevent propagation to avoid 
interference with events that may be
-                       // binded on #mw-mf-page-center that close overlay
-                       return false;
-               }
-               $btn.on( 'click', openNavigationDrawer );
-
-               /**
-                * Load the notification overlay.
-                * @method
-                * @ignore
-                * @private
-                * @uses NotificationsOverlay
-                * @return {jQuery.Deferred} with an instance of 
NotificationsOverlay
-                */
-               function loadNotificationOverlay() {
-                       var result = $.Deferred();
-                       loadModuleScript( 'mobile.notifications.overlay' 
).done( function () {
-                               var NotificationsOverlay = M.require( 
'mobile.notifications.overlay/NotificationsOverlay' );
-                               result.resolve(
-                                       new NotificationsOverlay( {
-                                               $badge: $btn,
-                                               count: parseInt( $btn.find( 
'span' ).text(), 10 )
-                                       } )
-                               );
-                       } );
-
-                       return result;
-               }
-
-               overlayManager.add( /^\/notifications$/, function () {
-                       return loadNotificationOverlay().done( function ( 
overlay ) {
-                               mainMenu.openNavigationDrawer( 'secondary' );
-                               overlay.on( 'hide', function () {
-                                       mainMenu.closeNavigationDrawers();
-                                       $( '#mw-mf-page-center' ).off( 
'.secondary' );
-                               } );
-
-                               $( '#mw-mf-page-center' ).one( 
'click.secondary', function () {
-                                       router.back();
-                               } );
-                       } );
+               // eslint-disable-next-line no-new
+               new NotificationBadge( {
+                       overlayManager: overlayManager,
+                       router: router,
+                       mainMenu: mainMenu,
+                       el: $( '#secondary-button.user-button' ).parent()
                } );
 
                /**
@@ -141,4 +76,5 @@
                        initialized = true;
                } );
        } );
-}( mw.mobileFrontend, jQuery, mw ) );
+
+}( mw.mobileFrontend, jQuery ) );
diff --git a/tests/phpunit/skins/SkinMinervaTest.php 
b/tests/phpunit/skins/SkinMinervaTest.php
index fb1e7b3..31af1b8 100644
--- a/tests/phpunit/skins/SkinMinervaTest.php
+++ b/tests/phpunit/skins/SkinMinervaTest.php
@@ -281,13 +281,14 @@
                $hasUnseen
        ) {
                return [
-                       'class' => MobileUI::iconClass( 'notifications' ),
+                       'notificationIconClass' => MobileUI::iconClass( 
'notifications' ),
                        'title' => $notificationsMsg,
                        'url' => SpecialPage::getTitleFor( $notificationsTitle )
                                ->getLocalURL(
                                        [ 'returnto' => 
$title->getPrefixedText() ] ),
                        'notificationCount' => $countLabel,
                        'isNotificationCountZero' => $isZero,
+                       'hasNotifications' => $hasUnseen,
                        'hasUnseenNotifications' => $hasUnseen
                ];
        }
diff --git 
a/tests/qunit/skins.minerva.notifications.badge/test_NotificationBadge.js 
b/tests/qunit/skins.minerva.notifications.badge/test_NotificationBadge.js
new file mode 100644
index 0000000..11961d1
--- /dev/null
+++ b/tests/qunit/skins.minerva.notifications.badge/test_NotificationBadge.js
@@ -0,0 +1,52 @@
+( function ( M ) {
+       var OverlayManager = M.require( 'mobile.startup/OverlayManager' ),
+               NotificationBadge = M.require( 
'skins.minerva.notifications/NotificationBadge' );
+
+       QUnit.module( 'Minerva NotificationBadge', {
+               setup: function () {
+                       this.router = require( 'mediawiki.router' );
+                       this.OverlayManager = new OverlayManager( this.router );
+               }
+       } );
+
+       QUnit.test( '#setCount', 2, function ( assert ) {
+               var initialClassExpectationsMet,
+                       badge = new NotificationBadge( {
+                               overlayManager: this.OverlayManager,
+                               hasNotifications: true,
+                               hasUnseenNotifications: true,
+                               notificationCount: 5
+                       } );
+               initialClassExpectationsMet = badge.$el.find( '.mw-ui-icon' 
).length === 0 &&
+                       badge.$el.find( '.zero' ).length === 0;
+
+               badge.setCount( 0 );
+               assert.ok( initialClassExpectationsMet, 'No icon and no zero 
class' );
+               assert.ok( badge.$el.find( '.zero' ).length === 1, 'A zero 
class is present on the badge' );
+       } );
+
+       QUnit.test( '#render [hasUnseenNotifications]', 1, function ( assert ) {
+               var badge = new NotificationBadge( {
+                       notificationCount: 0,
+                       overlayManager: this.OverlayManager,
+                       hasNotifications: false,
+                       hasUnseenNotifications: false
+               } );
+               assert.ok( badge.$el.find( '.mw-ui-icon' ).length === 1, 'A 
bell icon is visible' );
+       } );
+
+       QUnit.test( '#markAsSeen', 2, function ( assert ) {
+               var badge = new NotificationBadge( {
+                       notificationCount: 2,
+                       overlayManager: this.OverlayManager,
+                       hasNotifications: true,
+                       hasUnseenNotifications: true
+               } );
+               // Badge resets counter to zero
+               badge.setCount( 0 );
+               assert.ok( badge.$el.find( '.mw-ui-icon' ).length === 0, 'The 
bell icon is not visible' );
+               badge.markAsSeen();
+               assert.ok( badge.$el.find( '.notification-unseen' ).length === 
0,
+                       'Unseen class disappears after markAsSeen called.' );
+       } );
+}( mw.mobileFrontend ) );

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I246ed23164ff3f7ef8ea15896a9b3a0d19c2bb0d
Gerrit-PatchSet: 21
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: Jdlrobson <[email protected]>
Gerrit-Reviewer: Jdlrobson <[email protected]>
Gerrit-Reviewer: Jhernandez <[email protected]>
Gerrit-Reviewer: Mooeypoo <[email protected]>
Gerrit-Reviewer: Pmiazga <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to