AndyRussG has uploaded a new change for review. https://gerrit.wikimedia.org/r/151594
Change subject: Add QUnit tests and refactor JS as needed ...................................................................... Add QUnit tests and refactor JS as needed Change-Id: I704bd2b8bf0d90e119a3074b73c8812f0906e536 --- M Campaigns.hooks.php M Campaigns.php A modules/ext.campaigns.createaccount.js A modules/ext.campaigns.createaccount.lib.js D modules/ext.campaigns.js A tests/qunit/ext.campaigns.createacccount.lib.tests.js 6 files changed, 330 insertions(+), 124 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Campaigns refs/changes/94/151594/1 diff --git a/Campaigns.hooks.php b/Campaigns.hooks.php index 846c708..8181422 100644 --- a/Campaigns.hooks.php +++ b/Campaigns.hooks.php @@ -2,10 +2,12 @@ namespace Campaigns; -use \DatabaseUpdater; -use \RecursiveDirectoryIterator; -use \RecursiveIteratorIterator; -use \Campaigns\Setup\Setup; +use DatabaseUpdater; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use ResourceLoader; +use Campaigns\Setup\Setup; + /** * Static methods for hooks. @@ -92,7 +94,7 @@ } $out->addJsConfigVars( 'wgCampaignsCampaignSetOptIn', $setOptInVal ); - $out->addModules( 'ext.campaigns' ); + $out->addModules( 'ext.campaigns.createaccount' ); // Hidden controls on form $template->addInputItem( 'wpCampaignOptIn', 'false', 'hidden', null ); @@ -195,6 +197,26 @@ } /** + * Set JS testing modules + * + * @param array $testModules Array for adding JS testing modules + * @param ResourceLoader $resourceLoader + * @return bool + */ + public static function onResourceLoaderTestModules( + array &$testModules, ResourceLoader &$resourceLoader ) { + + $testModules['qunit']['ext.campaigns.tests'] = array( + 'scripts' => array( 'tests/qunit/ext.campaigns.createacccount.lib.tests.js' ), + 'dependencies' => array( 'ext.campaigns.createaccount.lib' ), + 'localBasePath' => dirname( __FILE__ ), + 'remoteExtPath' => 'Campaigns', + ); + + return true; + } + + /** * Call EventLogging::logEvent(), passing the same arguments received. * * Isolating this static call here lets us test onAddNewAccount() properly. diff --git a/Campaigns.php b/Campaigns.php index 2bcfdc1..e94c3e5 100644 --- a/Campaigns.php +++ b/Campaigns.php @@ -94,14 +94,25 @@ $wgHooks['UserLoginForm'][] = 'Campaigns\Hooks::onUserLoginForm'; $wgHooks['LoadExtensionSchemaUpdates'][] = 'Campaigns\Hooks::onLoadExtensionSchemaUpdate'; $wgHooks['UnitTestsList'][] = 'Campaigns\Hooks::onUnitTestsList'; +$wgHooks['ResourceLoaderTestModules'][] = 'Campaigns\Hooks::onResourceLoaderTestModules'; // Modules -$wgResourceModules['ext.campaigns'] = array( +$wgResourceModules['ext.campaigns.createaccount'] = array( 'localBasePath' => __DIR__ . '/modules', 'remoteExtPath' => 'Campaigns/modules', - 'scripts' => 'ext.campaigns.js', + 'scripts' => 'ext.campaigns.createaccount.js', + 'dependencies' => array( + 'ext.campaigns.createaccount.lib', + ), + 'targets' => array( 'mobile', 'desktop' ), +); + +$wgResourceModules['ext.campaigns.createaccount.lib'] = array( + 'localBasePath' => __DIR__ . '/modules', + 'remoteExtPath' => 'Campaigns/modules', + 'scripts' => 'ext.campaigns.createaccount.lib.js', 'styles' => 'ext.campaigns.less', 'dependencies' => array( 'jquery.cookie', diff --git a/modules/ext.campaigns.createaccount.js b/modules/ext.campaigns.createaccount.js new file mode 100644 index 0000000..09c1b01 --- /dev/null +++ b/modules/ext.campaigns.createaccount.js @@ -0,0 +1,27 @@ +/** + * Show a warning message and opt-in control for a joining a campaign via the + * CreateAccount page. + * + * @module ext.campaigns.createaccount.js + * @author Andrew Green <agr...@wikimedia.org> + * @author S Page <sp...@wikimedia.org> (previous version) + */ +( function ( mw, $ ) { + + var lib = mw.campaigns.createaccount.lib; + lib.init(); + + // Warn and bow-out if something's off + if ( !lib.hasCampaign() ) { + mw.log.warn( 'No campaign, why did server load me?' ); + return; + } + + if ( !lib.isOnCreateAccountPage() ) { + mw.log.warn( 'Not on create account page, why did server load me?' ); + return; + } + + lib.showMessageAndSetupControls(); + +}( mediaWiki, jQuery ) ); \ No newline at end of file diff --git a/modules/ext.campaigns.createaccount.lib.js b/modules/ext.campaigns.createaccount.lib.js new file mode 100644 index 0000000..abdf73d --- /dev/null +++ b/modules/ext.campaigns.createaccount.lib.js @@ -0,0 +1,146 @@ +/** + * If server detected a campaign, display a warning. + * + * @module ext.campaigns.createaccount.lib.js + * @author Andrew Green <agr...@wikimedia.org> + * @author S Page <sp...@wikimedia.org> (previous version) + */ +( function ( mw, $ ) { + 'use strict'; + + var CSS, campaignName, initialOptInVal, $signUp, $afterChkbxDiv, + $hiddenOptInFormInput; + + // CSS constants + // Coordinate with ext.campaigns.less + CSS = { + createAccountContainer: 'campaigns-create-account-container', + createAccountCheckbox: 'campaigns-create-account-checkbox', + createAccountAfterChkbx: 'campaigns-create-account-after-checkbox', + createAccountAfterChkbxUn: 'campaigns-create-account-after-checkbox-unchecked' + }; + + mw.campaigns = {}; + mw.campaigns.createaccount = {}; + mw.campaigns.createaccount.lib = { + + /** + * Set up some values used in a few places. Call this first. + */ + init: function() { + + // Retrieve config values sent by the server + campaignName = mw.config.get( 'wgCampaignsCampaignName' ); + + initialOptInVal = + mw.config.get( 'wgCampaignsCampaignSetOptIn' ) === 'true'; + + // DOM reference point for attaching warning message and checking + // that we're on the CreateAccount page + $signUp = $( '#signupstart' ); + + // Hidden opt-in input on create account form + $hiddenOptInFormInput = $( 'input[name=wpCampaignOptIn]' ); + }, + + /** + * Did we get info on a campaign? + */ + hasCampaign: function() { + return campaignName ? true : false; + }, + + /** + * Are we on the Create Account page? + */ + isOnCreateAccountPage: function() { + return $signUp.length > 0; + }, + + /** + * Show message and opt-in control, set the control's initial value, + * and set an event handler to control the form's hidden opt-in field. + */ + showMessageAndSetupControls: function() { + + // Build up the HTML manaully. Hopefully one day we'll be able to + // use client-side templates. + // (See https://www.mediawiki.org/wiki/Requests_for_comment/HTML_templating_library ) + + var $container, $introP, introText, $beforeChkbx, $chkbx, $chkbxP, + afterChkbxText, self; + + $container = $( '<div/>', { + 'class': 'warningbox ' + CSS.createAccountContainer + } ); + + $introP = $( '<p/>' ); + + introText = mw.message( 'campaigns-create-account-intro', + campaignName ).text(); + + $introP.text( introText ); + + $beforeChkbx = $( '<p/>' ); + $beforeChkbx.text( + mw.message( 'campaigns-create-account-before-checkbox' ).text() ); + + $chkbxP = $( '<p/>' ); + + $chkbx = $( '<input />', { + 'type': 'checkbox', + 'class': CSS.createAccountCheckbox + } ); + + $afterChkbxDiv = $( '<div/>', { + 'class': CSS.createAccountAfterChkbx + } ); + + afterChkbxText = mw.message( 'campaigns-create-account-after-checkbox', + campaignName ).text(); + + $afterChkbxDiv.text( afterChkbxText ); + + $chkbxP.append( $chkbx, $afterChkbxDiv ); + + $container.append( $introP, $beforeChkbx, $chkbxP ); + $signUp.prepend( $container ); + + $container.hide(); + + // Set the initial value opt-in value + $chkbx.prop( 'checked', initialOptInVal ); + this.setCheckboxState( initialOptInVal ); + + // Show the message and control + $container.fadeIn(); + + // Set an event handler to control the value of the hidden form + // input and the visible opt-in control and some styling + self = this; + $chkbx.change( function() { + self.setCheckboxState( $chkbx.is( ':checked' ) ); + } ); + }, + + /** + * Set the state of the hidden opt-in form field and the CSS class of + * the visible control in the warning box. + * Note: this should not be called before the warning message has been + * injected into the DOM. + * + * @param {Boolean} optIn + * @private + */ + setCheckboxState: function( optIn ) { + if ( optIn ) { + $hiddenOptInFormInput.val( true ); + $afterChkbxDiv.removeClass( CSS.createAccountAfterChkbxUn ); + } else { + $hiddenOptInFormInput.val( false ); + $afterChkbxDiv.addClass( CSS.createAccountAfterChkbxUn ); + } + } + }; + +} ( mediaWiki, jQuery ) ); diff --git a/modules/ext.campaigns.js b/modules/ext.campaigns.js deleted file mode 100644 index 8ce9867..0000000 --- a/modules/ext.campaigns.js +++ /dev/null @@ -1,117 +0,0 @@ -/** - * If server detected a campaign, display a warning. - * - * @module ext.campaigns.js - * @author S Page <sp...@wikimedia.org> - */ -( function ( mw, $ ) { - 'use strict'; - - var campaignName, $signUp, CSS, $container, $introP, introText, - $beforeChkbx, $chkbxP, $chkbx, $afterChkbxDiv, afterChkbxText, - initialOptInVal; - - campaignName = mw.config.get( 'wgCampaignsCampaignName' ); - - // Quick bow-out if something went wrong - - if ( !campaignName ) { - mw.log.warn( 'No campaign, why did server load me?' ); - return; - } - - // Make sure we're really on the create account page, just in case. - $signUp = $( '#signupstart' ); - - if ( $signUp.length === 0 ) { - mw.log.warn( 'Not on create account page, why did server load me?' ); - return; - } - - // Add message and opt-out control to UI - - // Here we build up the HTML manaully. Hopefully one day we'll be able to - // use client-side templates. - // (See https://www.mediawiki.org/wiki/Requests_for_comment/HTML_templating_library ) - - // CSS constants - // Coordinate with ext.campaigns.less - CSS = { - createAccountContainer: 'campaigns-create-account-container', - createAccountCheckbox: 'campaigns-create-account-checkbox', - createAccountAfterChkbx: 'campaigns-create-account-after-checkbox', - createAccountAfterChkbxUn: 'campaigns-create-account-after-checkbox-unchecked' - }; - - $container = $( '<div/>', { - 'class': 'warningbox ' + CSS.createAccountContainer - } ); - - $introP = $( '<p/>' ); - - introText = mw.message( 'campaigns-create-account-intro', - campaignName ).text(); - - $introP.text( introText ); - - $beforeChkbx = $( '<p/>' ); - $beforeChkbx.text( - mw.message( 'campaigns-create-account-before-checkbox' ) ); - - $chkbxP = $( '<p/>' ); - - $chkbx = $( '<input />', { - 'type': 'checkbox', - 'class': CSS.createAccountCheckbox - } ); - - $afterChkbxDiv = $( '<div/>', { - 'class': CSS.createAccountAfterChkbx - } ); - - afterChkbxText = mw.message( 'campaigns-create-account-after-checkbox', - campaignName ); - - $afterChkbxDiv.text( afterChkbxText ); - - $chkbxP.append( $chkbx, $afterChkbxDiv ); - - $container.append( $introP, $beforeChkbx, $chkbxP ); - $signUp.prepend( $container ); - - $container.hide(); - $container.fadeIn(); - - /** - * Set the state of the hidden opt-in form field and the CSS class of the - * visible control in the warning box. - * - * @param {Boolean} optIn - */ - function setOptInState( optIn ) { - if ( optIn ) { - $( 'input[name=wpCampaignOptIn]' ).val( true ); - $afterChkbxDiv.removeClass( CSS.createAccountAfterChkbxUn ); - } else { - $( 'input[name=wpCampaignOptIn]' ).val( false ); - $afterChkbxDiv.addClass( CSS.createAccountAfterChkbxUn ); - } - } - - // In the HTML sent from the server, the opt-in checkbox will be false. - // We'll set it to true here if instructed to do so by the server. We do - // this in JS so that users who have JS turned off (and thus don't see the - // warning) won't get added to campaigns without their knowledge. - initialOptInVal = mw.config.get( 'wgCampaignsCampaignSetOptIn' ) === 'true'; - $chkbx.prop( 'checked', initialOptInVal ); - setOptInState( initialOptInVal ); - - $chkbx.change( function() { - setOptInState( $chkbx.is( ':checked' ) ); - } ); - - // TODO (spage, 2013-06-11) We could remove the query string parameter from - // the browser history state, so users don't unintentionally propagate - // campaigns by bookmarking or sharing the landing page. - -} ( mediaWiki, jQuery ) ); diff --git a/tests/qunit/ext.campaigns.createacccount.lib.tests.js b/tests/qunit/ext.campaigns.createacccount.lib.tests.js new file mode 100644 index 0000000..ffe0be8 --- /dev/null +++ b/tests/qunit/ext.campaigns.createacccount.lib.tests.js @@ -0,0 +1,117 @@ +( function ( mw, $ ) { + 'use strict'; + + QUnit.module( 'ext.campaigns.createaccount.lib', QUnit.newMwEnvironment( { + + setup: function () { + mw.config.set( 'wgCampaignsCampaignName', 'testName' ); + $( '<div id="signupstart" />' ).appendTo( 'body' ); + + $( '<input name="wpCampaignOptIn" type="hidden" />' ) + .appendTo( 'body' ); + }, + + teardown: function () { + $( '#signupstart' ).remove(); + $( 'input[name=wpCampaignOptIn]' ).remove(); + } + } ) ); + + QUnit.test( 'hasCampaignTrueWhenExpected', 1, function( assert ) { + mw.campaigns.createaccount.lib.init(); + assert.ok( mw.campaigns.createaccount.lib.hasCampaign() ); + } ); + + QUnit.test( 'hasCampaignFalseWhenExpected', 1, function( assert ) { + mw.config.set( 'wgCampaignsCampaignName', null ); + mw.campaigns.createaccount.lib.init(); + assert.equal( false, mw.campaigns.createaccount.lib.hasCampaign() ); + } ); + + QUnit.test( 'isOnCreateAccountPageTrueWhenExpected', 1, function( assert ) { + mw.campaigns.createaccount.lib.init(); + assert.ok( mw.campaigns.createaccount.lib.isOnCreateAccountPage() ); + } ); + + QUnit.test( 'isOnCreateAccountPageFalseWhenExpected', 1, function( assert ) { + $( '#signupstart' ).remove(); + mw.campaigns.createaccount.lib.init(); + assert.equal( false, mw.campaigns.createaccount.lib.isOnCreateAccountPage() ); + } ); + + QUnit.test( 'showMessageAndSetupControlsInjectsContent', 5, function( assert ) { + var $container, $chkbx, containerHtml; + + mw.campaigns.createaccount.lib.init(); + mw.campaigns.createaccount.lib.showMessageAndSetupControls(); + + $container = + $( 'div[class="warningbox campaigns-create-account-container"]' ); + + assert.equal( 1, $container.length ); + + $chkbx = $( 'input[class=campaigns-create-account-checkbox]' ); + assert.equal( 1, $chkbx.length ); + + containerHtml = $container.html(); + + assert.ok( containerHtml.indexOf( + mw.message( 'campaigns-create-account-intro', 'testName' ).text() ) + > -1 ); + + assert.ok( containerHtml.indexOf( + mw.message( 'campaigns-create-account-before-checkbox' ).text() ) + > -1 ); + + assert.ok( containerHtml.indexOf( + mw.message( + 'campaigns-create-account-after-checkbox', 'testName' ).text() ) + > -1 ); + } ); + + QUnit.test( 'hiddenFieldChangesWithCheckbox', 2, function( assert ) { + var $chkbx, $hiddenOptInFormInput; + + mw.campaigns.createaccount.lib.init(); + mw.campaigns.createaccount.lib.showMessageAndSetupControls(); + + $chkbx = $( 'input[class=campaigns-create-account-checkbox]' ); + $hiddenOptInFormInput = $( 'input[name=wpCampaignOptIn]' ); + $hiddenOptInFormInput.val( 'false' ); + + $chkbx.prop( 'checked', true ); + $chkbx.trigger( 'change' ); + assert.equal( 'true', $hiddenOptInFormInput.val() ); + + $chkbx.prop( 'checked', false ); + $chkbx.trigger( 'change' ); + assert.equal( 'false', $hiddenOptInFormInput.val() ); + } ); + + QUnit.test( 'hiddenFieldAndCheckboxInitiallySetWhenExpected', 2, function( assert ) { + var $chkbx, $hiddenOptInFormInput; + + mw.config.set( 'wgCampaignsCampaignSetOptIn', 'true' ); + mw.campaigns.createaccount.lib.init(); + mw.campaigns.createaccount.lib.showMessageAndSetupControls(); + + $chkbx = $( 'input[class=campaigns-create-account-checkbox]' ); + $hiddenOptInFormInput = $( 'input[name=wpCampaignOptIn]' ); + assert.equal( true, $chkbx.prop( 'checked' ) ); + assert.equal( 'true', $hiddenOptInFormInput.val() ); + } ); + + QUnit.test( 'hiddenFieldAndCheckboxInitiallyNotSetWhenExpected', 2, function( assert ) { + var $chkbx, $hiddenOptInFormInput; + + mw.config.set( 'wgCampaignsCampaignSetOptIn', 'false' ); + mw.campaigns.createaccount.lib.init(); + mw.campaigns.createaccount.lib.showMessageAndSetupControls(); + + $chkbx = $( 'input[class=campaigns-create-account-checkbox]' ); + $hiddenOptInFormInput = $( 'input[name=wpCampaignOptIn]' ); + assert.equal( false, $chkbx.prop( 'checked' ) ); + assert.equal( 'false', $hiddenOptInFormInput.val() ); + } ); + +} ( mediaWiki, jQuery ) ); \ No newline at end of file -- To view, visit https://gerrit.wikimedia.org/r/151594 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I704bd2b8bf0d90e119a3074b73c8812f0906e536 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Campaigns Gerrit-Branch: wip/editorcampaigns Gerrit-Owner: AndyRussG <andrew.green...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits