jenkins-bot has submitted this change and it was merged. Change subject: Allow lazy loading references via mobileview API ......................................................................
Allow lazy loading references via mobileview API While we discuss the internals of a generic references API we should make use of the mobileview API we already have to source references. Changes: * Introduce 2 ReferencesGateway classes extending the interface class; * Make it safe to load `mobile.references` without side effects - move the initialisation code into skins.minerva.scripts; * Separate tests for all 2 gateways; * Clicking a nested reference no longer causes scrolling to the reference Bug: T130551 Bug: T129182 Change-Id: Iec812faf12182f80f5a2193c2bc4b9b95ea86bbe --- M extension.json M includes/MobileFrontend.hooks.php A resources/mobile.references.gateway/ReferencesGateway.js A resources/mobile.references.gateway/ReferencesHtmlScraperGateway.js A resources/mobile.references.gateway/ReferencesMobileViewGateway.js M resources/mobile.references/ReferencesDrawer.js D resources/mobile.references/references.js M resources/skins.minerva.scripts/init.js M resources/skins.minerva.scripts/preInit.js A resources/skins.minerva.scripts/references.js A tests/qunit/mobile.references.gateway/test_ReferencesHtmlScraperGateway.js A tests/qunit/mobile.references.gateway/test_ReferencesMobileViewGateway.js D tests/qunit/mobile.references/test_references.js A tests/qunit/tests.mobilefrontend/pageWithStrippedRefs.html A tests/qunit/tests.mobilefrontend/refSection.html 15 files changed, 458 insertions(+), 244 deletions(-) Approvals: Bmansurov: Looks good to me, approved jenkins-bot: Verified diff --git a/extension.json b/extension.json index 0e22c35..d1d5946 100644 --- a/extension.json +++ b/extension.json @@ -1077,6 +1077,7 @@ "desktop" ], "dependencies": [ + "mobile.references.gateway", "mobile.drawers", "mobile.editor.api", "mobile.references.images" @@ -1092,8 +1093,22 @@ "Drawer.hogan": "resources/mobile.references/ReferencesDrawer.hogan" }, "scripts": [ - "resources/mobile.references/ReferencesDrawer.js", - "resources/mobile.references/references.js" + "resources/mobile.references/ReferencesDrawer.js" + ] + }, + "mobile.references.gateway": { + "targets": [ + "mobile", + "desktop" + ], + "dependencies": [ + "mobile.startup", + "mobile.oo" + ], + "scripts": [ + "resources/mobile.references.gateway/ReferencesGateway.js", + "resources/mobile.references.gateway/ReferencesHtmlScraperGateway.js", + "resources/mobile.references.gateway/ReferencesMobileViewGateway.js" ] }, "mobile.toggle": { @@ -1593,6 +1608,7 @@ "resources/skins.minerva.scripts/init.js", "resources/skins.minerva.scripts/initLogging.js", "resources/skins.minerva.scripts/mobileRedirect.js", + "resources/skins.minerva.scripts/references.js", "resources/skins.minerva.scripts/search.js" ] }, diff --git a/includes/MobileFrontend.hooks.php b/includes/MobileFrontend.hooks.php index 559019c..8af7310 100644 --- a/includes/MobileFrontend.hooks.php +++ b/includes/MobileFrontend.hooks.php @@ -326,7 +326,9 @@ 'issues.hogan' => 'tests/qunit/tests.mobilefrontend/issues.hogan', 'page.html' => 'tests/qunit/tests.mobilefrontend/page.html', 'page2.html' => 'tests/qunit/tests.mobilefrontend/page2.html', + 'pageWithStrippedRefs.html' => 'tests/qunit/tests.mobilefrontend/pageWithStrippedRefs.html', 'references.html' => 'tests/qunit/tests.mobilefrontend/references.html', + 'refSection.html' => 'tests/qunit/tests.mobilefrontend/refSection.html', ), 'localBasePath' => $localBasePath, 'remoteExtPath' => 'MobileFrontend', diff --git a/resources/mobile.references.gateway/ReferencesGateway.js b/resources/mobile.references.gateway/ReferencesGateway.js new file mode 100644 index 0000000..a2e2fcf --- /dev/null +++ b/resources/mobile.references.gateway/ReferencesGateway.js @@ -0,0 +1,46 @@ +( function ( M ) { + /** + * Abstract base class + * Gateway for retrieving references + * + * @class ReferencesGateway + * @param {mw.Api} api + */ + function ReferencesGateway( api ) { + this.api = api; + } + + OO.mfExtend( ReferencesGateway, { + /** + * Escapes reference id to remove CSS selector meta characters + * + * @param {String} id of a DOM element in the page + * @returns {String} + */ + getEscapedId: function ( id ) { + var + // Escape (almost) all CSS selector meta characters + // see http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + meta = /[!"$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g; + + id = id.replace( meta, '\\$&' ); + return id.substr( 1, id.length ); + }, + // jscs:disable + /** + * Return the matched reference via API or DOM query + * + * @method + * @param {String} id CSS selector + * @param {Page} page to find reference for + * @returns {jQuery.Promise} resolves with an Object representing reference with a `text` property + or false if the reference does not exist + */ + getReference: function () { + throw new Error( 'Method unimplemented' ); + } + // jscs:enable + } ); + + M.define( 'mobile.references.gateway/ReferencesGateway', ReferencesGateway ); +}( mw.mobileFrontend ) ); diff --git a/resources/mobile.references.gateway/ReferencesHtmlScraperGateway.js b/resources/mobile.references.gateway/ReferencesHtmlScraperGateway.js new file mode 100644 index 0000000..bff3368 --- /dev/null +++ b/resources/mobile.references.gateway/ReferencesHtmlScraperGateway.js @@ -0,0 +1,35 @@ +( function ( M, $ ) { + var ReferencesGateway = M.require( 'mobile.references.gateway/ReferencesGateway' ); + + /** + * Gateway for retrieving references via the content of the Page + * + * @class ReferencesHtmlScraperGateway + * @extends ReferencesGateway + * @inheritdoc + */ + function ReferencesHtmlScraperGateway() { + ReferencesGateway.apply( this, arguments ); + } + + OO.mfExtend( ReferencesHtmlScraperGateway, ReferencesGateway, { + /** + * @inheritdoc + */ + getReference: function ( id, page ) { + var ref, + $refs = page.$( 'ol.references' ), + $el = $refs.find( '#' + this.getEscapedId( id ) ); + + ref = $el.length ? + { + text: $el.html() + } : false; + + return $.Deferred().resolve( ref ).promise(); + } + } ); + + M.define( 'mobile.references.gateway/ReferencesHtmlScraperGateway', + ReferencesHtmlScraperGateway ); +}( mw.mobileFrontend, jQuery ) ); diff --git a/resources/mobile.references.gateway/ReferencesMobileViewGateway.js b/resources/mobile.references.gateway/ReferencesMobileViewGateway.js new file mode 100644 index 0000000..a8bd459 --- /dev/null +++ b/resources/mobile.references.gateway/ReferencesMobileViewGateway.js @@ -0,0 +1,84 @@ +( function ( M, $ ) { + var ReferencesHtmlScraperGateway = M.require( + 'mobile.references.gateway/ReferencesHtmlScraperGateway' ), + Page = M.require( 'mobile.startup/Page' ); + + /** + * Gateway for retrieving references via the MobileView API + * + * @class ReferencesMobileViewGateway + * @extends ReferencesHtmlScraperGateway + * @inheritdoc + */ + function ReferencesMobileViewGateway() { + ReferencesHtmlScraperGateway.apply( this, arguments ); + } + + OO.mfExtend( ReferencesMobileViewGateway, ReferencesHtmlScraperGateway, { + /** + * Retrieve references for a given page + * + * @method + * @param {Page} page + * @return {jQuery.Promise} passed an instance of the jQuery.object + * representing all the sections in the page + */ + getReferencesElements: function ( page ) { + var self = this; + + if ( this.$references ) { + return $.Deferred().resolve( self.$references ).promise(); + } else if ( this.pendingMobileViewApi ) { + // avoid ever making more than one api request + return this.pendingMobileViewApi; + } + + this.pendingMobileViewApi = this.api.get( { + action: 'mobileview', + page: page.getTitle(), + sections: 'references', + prop: 'text', + revision: page.getRevisionId() + } ).then( function ( data ) { + var sections = data.mobileview.sections, + refs = []; + + if ( sections ) { + // There could be multiple <references> tags in the page. + $.each( sections, function ( i, section ) { + // skip the section header, just get the references + refs.push( $( '<div>' ).html( section.text ).find( '.references' ).eq( 0 ) ); + } ); + } + + // cache + self.$references = $( refs ); + + return self.$references; + } ); + return this.pendingMobileViewApi; + }, + /** + * @inheritdoc + */ + getReference: function ( id, page ) { + var self = this, + parentGetReference = ReferencesHtmlScraperGateway.prototype.getReference; + + return this.getReferencesElements( page ).then( function ( $refSections ) { + // append to a new page to avoid side effects on the passed Page object. + var refPage = new Page( page.options ); + + $refSections.each( function () { + // With each replace the matched element is removed from the list. + // That's why we always replace the first matched element. + refPage.$( '.mf-lazy-references-placeholder' ).eq( 0 ).replaceWith( this ); + } ); + return parentGetReference.call( self, id, refPage ); + } ); + } + } ); + + M.define( 'mobile.references.gateway/ReferencesMobileViewGateway', + ReferencesMobileViewGateway ); +}( mw.mobileFrontend, jQuery ) ); diff --git a/resources/mobile.references/ReferencesDrawer.js b/resources/mobile.references/ReferencesDrawer.js index 9d8f362..aa28872 100644 --- a/resources/mobile.references/ReferencesDrawer.js +++ b/resources/mobile.references/ReferencesDrawer.js @@ -76,20 +76,38 @@ }, /** * Fetch and render nested reference upon click + * @param {String} id of the reference to be retrieved + * @param {Page} page to locate reference for + * @param {String} refNumber the number it identifies as in the page + */ + showReference: function ( id, page, refNumber ) { + var drawer = this; + + // Save the page in case we have to show a nested reference. + this.options.page = page; + this.options.gateway.getReference( id, page ).done( function ( reference ) { + drawer.render( { + title: refNumber, + text: reference.text + } ); + } ).fail( function () { + drawer.render( { + error: true, + title: refNumber, + text: mw.msg( 'mobile-frontend-references-citation-error' ) + } ); + } ); + }, + /** + * Fetch and render nested reference upon click * @param {jQuery.Event} ev */ showNestedReference: function ( ev ) { - var $dest = $( ev.target ), - href = $dest.attr( 'href' ); + var $dest = $( ev.target ); - mw.track( 'mf.showReference', { - href: href, - title: $dest.text(), - page: this.options.page - } ); - - // Don't hide the already shown drawer - ev.stopPropagation(); + this.showReference( $dest.attr( 'href' ), this.options.page, $dest.text() ); + // Don't hide the already shown drawer via propagation and stop default scroll behaviour. + return false; } } ); diff --git a/resources/mobile.references/references.js b/resources/mobile.references/references.js deleted file mode 100644 index 718e014..0000000 --- a/resources/mobile.references/references.js +++ /dev/null @@ -1,172 +0,0 @@ -( function ( M, $ ) { - var drawer, referencesData, - context = M.require( 'mobile.context/context' ), - isBeta = context.isBetaGroupMember(), - ReferencesDrawer = M.require( 'mobile.references/ReferencesDrawer' ); - - mw.trackSubscribe( 'mf.showReference', function ( topic, data ) { - getReference( data.href, data.page ).done( function ( reference ) { - drawer.render( { - title: data.title, - text: reference.text - } ); - } ).fail( function () { - drawer.render( { - error: true, - title: data.title, - text: mw.msg( 'mobile-frontend-references-citation-error' ) - } ); - } ); - } ); - - /** - * Return a data structure indexing all references in the given page. - * @method - * @ignore - * @param {Page} page to retrieve references for - * @returns {jQuery.Deferred} resolving with an Object indexing all references - */ - function getReferenceData( page ) { - var api, - d = $.Deferred(); - - if ( referencesData ) { - d.resolve( referencesData ); - } else { - api = new mw.Api(); - api.get( { - action: 'query', - prop: 'references', - formatversion: 2, - titles: [ page.getTitle() ] - } ).then( function ( data ) { - if ( data && data.query && data.query.pages && data.query.pages.length ) { - referencesData = data.query.pages[0].references; - } else { - referencesData = {}; - } - d.resolve( referencesData ); - } ).fail( $.proxy( d, 'reject' ) ); - } - return d; - } - - /** - * Return the matched reference among the children of ol.references - * @method - * @ignore - * @param {String} id CSS selector - * @param {Page} page to retrieve reference for - * @returns {jQuery.Deferred} resolves with an Object representing reference - */ - function getReference( id, page ) { - var $el, - config = mw.config.get( 'wgMFLazyLoadReferences' ), - EditorGateway = M.require( 'mobile.editor.api/EditorGateway' ), - editorGateway = new EditorGateway( { - api: new mw.Api(), - title: page.getTitle() - } ), - d = $.Deferred(), - // Escape (almost) all CSS selector meta characters - // see http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - meta = /[!"$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g; - - id = id.replace( meta, '\\$&' ); - if ( config.base || ( isBeta && config.beta ) ) { - id = id.substr( 1, id.length ); - // FIXME: Use a gateway for this (?) - getReferenceData( page ).then( function ( references ) { - var ref = references[id]; - if ( !ref ) { - d.reject(); - } else if ( ref.html ) { - // use cached version to avoid lookup - d.resolve( { - text: ref.html - } ); - } else { - // reference was provided raw so we now need to parse it. - editorGateway.getPreview( { - text: ref.text - } ).done( function ( parsedText ) { - // cache for later use - ref.html = parsedText; - d.resolve( { - text: parsedText - } ); - } ).fail( $.proxy( d, 'reject' ) ); - } - } ).fail( $.proxy( d, 'reject' ) ); - } else { - // Use find rather than string concatenation - $el = page.$( 'ol.references' ).find( id ); - if ( $el.length ) { - d.resolve( { - text: $el.html() - } ); - } else { - d.reject(); - } - } - return d; - } - - /** - * Event handler to show reference when a reference link is clicked - * @method - * @ignore - * @param {jQuery.Event} ev Event object - */ - function showReference( ev ) { - var $dest = $( this ), - href = $dest.attr( 'href' ), - page = $dest.data( 'page' ); - - if ( !drawer ) { - // Note we only initialise here to avoid adding to DOM unnecessarily - // (Drawer currently auto appends within the postRender function ) - drawer = new ReferencesDrawer( { - page: page - } ); - } - - mw.track( 'mf.showReference', { - href: href, - page: page, - title: $dest.text() - } ); - - ev.preventDefault(); - // don't hide drawer (stop propagation of click) if it is already shown (e.g. click another reference) - if ( drawer.isVisible() ) { - ev.stopPropagation(); - } else { - // flush any existing reference information - drawer.render( { - text: undefined - } ); - // use setTimeout so that browser calculates dimensions before show() - setTimeout( $.proxy( drawer, 'show' ), 0 ); - } - } - - /** - * Make references clickable and show a drawer when clicked on. - * @method - * @ignore - * @param {Page} page Defaults to $( '#bodyContent' ) - */ - function setup( page ) { - page.$( 'sup a' ).off( 'click' ) - .data( 'page', page ) - .on( 'click', showReference ); - page.$( '.mw-cite-backlink a' ).off( 'click' ); - } - - M.define( 'mobile.references/references', { - getReference: getReference, - setup: setup - } ); - -}( mw.mobileFrontend, jQuery ) ); diff --git a/resources/skins.minerva.scripts/init.js b/resources/skins.minerva.scripts/init.js index 1543bde..54520a4 100644 --- a/resources/skins.minerva.scripts/init.js +++ b/resources/skins.minerva.scripts/init.js @@ -7,8 +7,6 @@ loader = M.require( 'mobile.overlays/moduleLoader' ), router = M.require( 'mobile.startup/router' ), context = M.require( 'mobile.context/context' ), - // FIXME: Don't pull in the mobile.references library on startup. Lazy load it when needed - references = M.require( 'mobile.references/references' ), cleanuptemplates = M.require( 'mobile.issues/cleanuptemplates' ), useNewMediaViewer = context.isBetaGroupMember(), overlayManager = M.require( 'mobile.startup/overlayManager' ), @@ -207,7 +205,6 @@ $( function () { initButton(); initMediaViewer(); - references.setup( page ); } ); // Access the beta optin experiment if available. diff --git a/resources/skins.minerva.scripts/preInit.js b/resources/skins.minerva.scripts/preInit.js index e53bc63..1190168 100644 --- a/resources/skins.minerva.scripts/preInit.js +++ b/resources/skins.minerva.scripts/preInit.js @@ -58,6 +58,7 @@ protection: { edit: permissions }, + revId: mw.config.get( 'wgRevisionId' ), isMainPage: mw.config.get( 'wgIsMainPage' ), isWatched: $( '#ca-watch' ).hasClass( 'watched' ), sections: gateway.getSectionsFromHTML( $content ), diff --git a/resources/skins.minerva.scripts/references.js b/resources/skins.minerva.scripts/references.js new file mode 100644 index 0000000..4e58287 --- /dev/null +++ b/resources/skins.minerva.scripts/references.js @@ -0,0 +1,100 @@ +( function ( M, $ ) { + var drawer, + page = M.getCurrentPage(), + context = M.require( 'mobile.context/context' ), + isBeta = context.isBetaGroupMember(); + + /** + * Retrieves the references gateway module info to be used on the page from config + * + * @method + * @ignore + * @returns {String} name of the class implementing ReferenceGateway to use + */ + function getReferenceGatewayClassName() { + var config = mw.config.get( 'wgMFLazyLoadReferences', {} ); + + return config.base || ( isBeta && config.beta ) ? + 'ReferencesMobileViewGateway' : 'ReferencesHtmlScraperGateway'; + } + + /** + * Creates a ReferenceDrawer based on the currently available ReferenceGateway + * + * @ignore + * @returns {ReferencesDrawer} + */ + function referenceDrawerFactory() { + var gatewayClassName = getReferenceGatewayClassName(), + ReferencesGateway = M.require( 'mobile.references.gateway/' + gatewayClassName ), + ReferencesDrawer = M.require( 'mobile.references/ReferencesDrawer' ); + + return new ReferencesDrawer( { + gateway: new ReferencesGateway( new mw.Api() ) + } ); + } + + /** + * Event handler to show reference when a reference link is clicked + * @ignore + * @param {jQuery.Event} ev Click event of the reference element + * @param {ReferencesDrawer} drawer to show the reference in + */ + function showReference( ev, drawer ) { + var $dest = $( ev.target ), + href = $dest.attr( 'href' ); + + ev.preventDefault(); + + drawer.showReference( href, page, $dest.text() ); + + // don't hide drawer (stop propagation of click) if it is already shown (e.g. click another reference) + if ( drawer.isVisible() ) { + ev.stopPropagation(); + } else { + // flush any existing reference information + drawer.render( { + text: undefined + } ); + // use setTimeout so that browser calculates dimensions before show() + setTimeout( $.proxy( drawer, 'show' ), 0 ); + } + } + + /** + * Event handler to show reference when a reference link is clicked. + * Delegates to `showReference` once the references drawer is ready. + * + * @ignore + * @param {jQuery.Event} ev Click event of the reference element + */ + function onClickReference( ev ) { + if ( !drawer ) { + drawer = referenceDrawerFactory(); + } + showReference( ev, drawer ); + } + + /** + * Make references clickable and show a drawer when clicked on. + * @ignore + * @param {Page} page + */ + function setup( page ) { + var $refs = page.$( 'sup a' ); + + if ( $refs.length ) { + $refs + .off( 'click' ) + .on( 'click', onClickReference ); + page.$( '.mw-cite-backlink a' ) + .off( 'click' ); + } + } + + // Setup + $( function () { + setup( page ); + } ); + +}( mw.mobileFrontend, jQuery ) ); diff --git a/tests/qunit/mobile.references.gateway/test_ReferencesHtmlScraperGateway.js b/tests/qunit/mobile.references.gateway/test_ReferencesHtmlScraperGateway.js new file mode 100644 index 0000000..b4b464a --- /dev/null +++ b/tests/qunit/mobile.references.gateway/test_ReferencesHtmlScraperGateway.js @@ -0,0 +1,37 @@ +( function ( $, M ) { + + var ReferencesHtmlScraperGateway = M.require( + 'mobile.references.gateway/ReferencesHtmlScraperGateway' ), + Page = M.require( 'mobile.startup/Page' ); + + QUnit.module( 'MobileFrontend: htmlScraper references gateway', { + setup: function () { + this.$container = mw.template.get( 'tests.mobilefrontend', 'references.html' ) + .render().appendTo( '#qunit-fixture' ); + this.page = new Page( { + el: this.$container, + title: 'Reftest' + } ); + this.referencesGateway = new ReferencesHtmlScraperGateway( new mw.Api() ); + // we use Page object which calls getUrl which uses config variables. + this.sandbox.stub( mw.util, 'getUrl' ).returns( '/wiki/Reftest' ); + } + } ); + + QUnit.test( 'checking good reference', 1, function ( assert ) { + var done = assert.async( 1 ); + this.referencesGateway.getReference( '#cite_note-1', this.page ).done( function ( ref ) { + assert.strictEqual( $( '<div>' ).html( ref.text ).find( '.reference-text' ).text(), 'hello' ); + done(); + } ); + } ); + + QUnit.test( 'checking bad reference', 1, function ( assert ) { + var done = assert.async( 1 ); + this.referencesGateway.getReference( '#cite_note-bad', this.page ).done( function ( ref ) { + assert.ok( ref === false, 'When bad id given false returned.' ); + done(); + } ); + } ); + +} )( jQuery, mw.mobileFrontend ); diff --git a/tests/qunit/mobile.references.gateway/test_ReferencesMobileViewGateway.js b/tests/qunit/mobile.references.gateway/test_ReferencesMobileViewGateway.js new file mode 100644 index 0000000..9a37d6d --- /dev/null +++ b/tests/qunit/mobile.references.gateway/test_ReferencesMobileViewGateway.js @@ -0,0 +1,95 @@ +( function ( $, M ) { + + var ReferencesMobileViewGateway = M.require( + 'mobile.references.gateway/ReferencesMobileViewGateway' ), + Page = M.require( 'mobile.startup/Page' ); + + QUnit.module( 'MobileFrontend: mobileView references gateway', { + setup: function () { + this.$container = mw.template.get( 'tests.mobilefrontend', 'pageWithStrippedRefs.html' ) + .render().appendTo( '#qunit-fixture' ); + + this.page = new Page( { + el: this.$container, + title: 'Reftest' + } ); + + this.api = new mw.Api(); + this.sandbox.stub( this.api, 'get' ).returns( + $.Deferred().resolve( { + mobileview: { + sections: [] + } + } ) + ); + this.gatewayHitsApi = new ReferencesMobileViewGateway( this.api ); + + this.referencesGateway = new ReferencesMobileViewGateway( new mw.Api() ); + // we use Page object which calls getUrl which uses config variables. + this.sandbox.stub( mw.util, 'getUrl' ).returns( '/wiki/Reftest' ); + this.sandbox.stub( this.referencesGateway, 'getReferencesElements' ).returns( + $.Deferred().resolve( + mw.template.get( 'tests.mobilefrontend', 'refSection.html' ).render() + ).promise() + ); + this.referencesGatewayEmpty = new ReferencesMobileViewGateway( new mw.Api() ); + this.sandbox.stub( this.referencesGatewayEmpty, 'getReferencesElements' ).returns( + $.Deferred().resolve( $() ).promise() + ); + this.referencesGatewayRejector = new ReferencesMobileViewGateway( new mw.Api() ); + this.sandbox.stub( this.referencesGatewayRejector, 'getReferencesElements' ).returns( + $.Deferred().reject().promise() + ); + } + } ); + + QUnit.test( 'Gateway only hits api once despite multiple calls', 1, function ( assert ) { + this.gatewayHitsApi.getReferencesElements( this.page ); + this.gatewayHitsApi.getReferencesElements( this.page ); + this.gatewayHitsApi.getReferencesElements( this.page ); + assert.strictEqual( this.api.get.calledOnce, true, 'The API should only ever be hit once.' ); + } ); + + QUnit.test( 'checking good reference', 1, function ( assert ) { + var done = assert.async( 1 ); + this.referencesGateway.getReference( '#cite_note-1', this.page ).done( function ( ref ) { + assert.strictEqual( ref.text, 'real lazy' ); + done(); + } ); + } ); + + QUnit.test( 'checking good reference (subsequent calls)', 1, function ( assert ) { + var done = assert.async( 1 ); + this.referencesGateway.getReference( '#cite_note-1', this.page ); + this.referencesGateway.getReference( '#cite_note-2', this.page ).done( function ( ref ) { + assert.strictEqual( ref.text, 'real lazy 2' ); + done(); + } ); + } ); + + QUnit.test( 'checking bad reference', 1, function ( assert ) { + var done = assert.async( 1 ); + this.referencesGateway.getReference( '#cite_note-bad', this.page ).done( function ( ref ) { + assert.ok( ref === false, 'When bad id given false returned.' ); + done(); + } ); + } ); + + QUnit.test( 'checking reference on non-existent page', 1, function ( assert ) { + var done = assert.async( 1 ); + this.referencesGatewayEmpty.getReference( '#cite_note-bad', this.page ).done( function ( ref ) { + assert.ok( ref === false, + 'When getReferencesElement returns empty list of elements reference is false.' ); + done(); + } ); + } ); + + QUnit.test( 'checking reference when gateway rejects', 1, function ( assert ) { + var done = assert.async( 1 ); + this.referencesGatewayRejector.getReference( '#cite_note-bad', this.page ).fail( function () { + assert.ok( true, 'getReference is rejected if API query fails' ); + done(); + } ); + } ); + +} )( jQuery, mw.mobileFrontend ); diff --git a/tests/qunit/mobile.references/test_references.js b/tests/qunit/mobile.references/test_references.js deleted file mode 100644 index 7a4d3c5..0000000 --- a/tests/qunit/mobile.references/test_references.js +++ /dev/null @@ -1,57 +0,0 @@ -( function ( $, M ) { - - var R = mw.mobileFrontend.require( 'mobile.references/references' ), - Page = M.require( 'mobile.startup/Page' ); - - QUnit.module( 'MobileFrontend references.js', { - setup: function () { - this.$container = mw.template.get( 'tests.mobilefrontend', 'references.html' ) - .render().appendTo( '#qunit-fixture' ); - this.page = new Page( { - el: this.$container, - title: 'Reftest' - } ); - // we use Page object which calls getUrl which uses config variables. - this.sandbox.stub( mw.util, 'getUrl' ).returns( '/wiki/Reftest' ); - } - } ); - - QUnit.test( 'Standard', 1, function ( assert ) { - this.sandbox.stub( mw.config, 'get' ).withArgs( 'wgMFLazyLoadReferences' ).returns( { - beta: false, - base: false - } ); - R.getReference( '#cite_note-1', this.page ).done( function ( ref ) { - assert.strictEqual( $( '<div>' ).html( ref.text ).find( '.reference-text' ).text(), 'hello' ); - } ); - } ); - - QUnit.test( 'Lazy loaded', 1, function ( assert ) { - this.sandbox.stub( mw.Api.prototype, 'get' ).returns( - $.Deferred().resolve( { - query: { - pages: [ - { - references: { - 'cite_note-1': { - key: 1, - // include html to avoid hitting EditorGateway - html: '<i>so lazy</i>', - text: '\'\'so lazy\'\'' - } - } - } - ] - } - } ) - ); - this.sandbox.stub( mw.config, 'get' ).withArgs( 'wgMFLazyLoadReferences' ).returns( { - beta: true, - base: true - } ); - R.getReference( '#cite_note-1', this.page ).done( function ( ref ) { - assert.strictEqual( ref.text, '<i>so lazy</i>' ); - } ); - } ); - -} )( jQuery, mw.mobileFrontend ); diff --git a/tests/qunit/tests.mobilefrontend/pageWithStrippedRefs.html b/tests/qunit/tests.mobilefrontend/pageWithStrippedRefs.html new file mode 100644 index 0000000..7cba1d4 --- /dev/null +++ b/tests/qunit/tests.mobilefrontend/pageWithStrippedRefs.html @@ -0,0 +1,8 @@ +<div> + <h2><span class="mw-headline" id="1.0">A1</span></h1> + <div>text</div> + <h2>references</h2> + <div> + <a class="mf-lazy-references-placeholder">View citations</a> + </div> +</div> \ No newline at end of file diff --git a/tests/qunit/tests.mobilefrontend/refSection.html b/tests/qunit/tests.mobilefrontend/refSection.html new file mode 100644 index 0000000..594baa6 --- /dev/null +++ b/tests/qunit/tests.mobilefrontend/refSection.html @@ -0,0 +1,4 @@ +<ol class="references"> + <li id="cite_note-1">real lazy</li> + <li id="cite_note-2">real lazy 2</li> +</ul> \ No newline at end of file -- To view, visit https://gerrit.wikimedia.org/r/275724 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Iec812faf12182f80f5a2193c2bc4b9b95ea86bbe Gerrit-PatchSet: 29 Gerrit-Project: mediawiki/extensions/MobileFrontend Gerrit-Branch: master Gerrit-Owner: Jdlrobson <jrob...@wikimedia.org> Gerrit-Reviewer: Bmansurov <bmansu...@wikimedia.org> Gerrit-Reviewer: Jdlrobson <jrob...@wikimedia.org> Gerrit-Reviewer: Jhobs <jhob...@wikimedia.org> Gerrit-Reviewer: Phuedx <g...@samsmith.io> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits