From c447423593789920a9c77da280463e2f900e54c7 Mon Sep 17 00:00:00 2001 From: Antoine Musso Date: Tue, 3 Jan 2012 18:33:26 +0000 Subject: [PATCH] merge JSTesting branch into trunk Changed written by Timo and reviewed by Hashar. This should be harmless. To enable the feature: $wgEnableJavaScriptTest = true; Then head to: [[Special:JavaScriptTest/qunit]] --- RELEASE-NOTES-1.19 | 3 + docs/hooks.txt | 10 ++ includes/AutoLoader.php | 1 + includes/DefaultSettings.php | 15 ++ includes/Skin.php | 14 +- includes/SpecialPageFactory.php | 1 + includes/resourceloader/ResourceLoader.php | 64 +++++++- includes/specials/SpecialJavaScriptTest.php | 127 ++++++++++++++++ languages/messages/MessagesEn.php | 14 ++ languages/messages/MessagesQqq.php | 11 ++ resources/Resources.php | 30 +++- .../mediawiki.special.javaScriptTest.js | 33 +++++ tests/qunit/QUnitTestResources.php | 55 +++++++ tests/qunit/data/testrunner.js | 123 +++++++++++++--- .../jquery/jquery.autoEllipsis.test.js | 2 +- .../jquery/jquery.byteLength.test.js | 2 +- .../resources/jquery/jquery.byteLimit.test.js | 10 +- .../resources/jquery/jquery.client.test.js | 2 +- .../resources/jquery/jquery.colorUtil.test.js | 2 +- .../resources/jquery/jquery.getAttrs.test.js | 2 +- .../jquery/jquery.highlightText.test.js | 2 +- .../resources/jquery/jquery.localize.test.js | 2 +- .../jquery/jquery.mwExtension.test.js | 2 +- .../resources/jquery/jquery.tabIndex.test.js | 2 +- .../jquery/jquery.tablesorter.test.js | 23 +-- .../jquery/jquery.textSelection.test.js | 2 +- .../mediawiki.special.recentchanges.test.js | 2 +- .../mediawiki/mediawiki.Title.test.js | 139 +++++++++--------- .../mediawiki/mediawiki.jscompat.test.js | 2 +- .../resources/mediawiki/mediawiki.test.js | 27 +++- .../mediawiki/mediawiki.user.test.js | 12 +- .../mediawiki/mediawiki.util.test.js | 6 +- 32 files changed, 607 insertions(+), 135 deletions(-) create mode 100644 includes/specials/SpecialJavaScriptTest.php create mode 100644 resources/mediawiki.special/mediawiki.special.javaScriptTest.js create mode 100644 tests/qunit/QUnitTestResources.php diff --git a/RELEASE-NOTES-1.19 b/RELEASE-NOTES-1.19 index 60fdd82cd4..b2c6d820f3 100644 --- a/RELEASE-NOTES-1.19 +++ b/RELEASE-NOTES-1.19 @@ -112,6 +112,9 @@ production. * (bug 23427) Introduced {{PAGEID}} variable to expose page.page_id. * (bug 33447) Link to the broken image tracking category from Special:Wantedfiles. * (bug 27724) Add timestamp to job queue. +* (bug 30339) Implement SpecialPage for running javascript tests. Disabled by default, due to + tests potentially being harmful, not to be run on a production wiki. + Enable by setting $wgEnableJavaScriptTest to true. === Bug fixes in 1.19 === * $wgUploadNavigationUrl should be used for file redlinks if. diff --git a/docs/hooks.txt b/docs/hooks.txt index 4ca46e2088..c7bd7ddf80 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -1579,6 +1579,16 @@ scripts. loader request or generating HTML output. &$resourceLoader: ResourceLoader object +'ResourceLoaderTestModules': let you add new javascript testing modules. This is called after the addition of 'qunit' and MediaWiki testing ressources. +&testModules: array of javascript testing modules. 'qunit' is feed using tests/qunit/QUnitTestResources.php. +&RessourceLoader object +To add a new qunit module named 'myext.tests': +testModules['qunit']['myext.tests'] = array( + 'script' => 'extension/myext/tests.js', + 'dependencies' => +); +For qunit framework, the mediawiki.tests.qunit.testrunner dependency will be added to any module. + 'RevisionInsertComplete': called after a revision is inserted into the DB &$revision: the Revision $data: the data stored in old_text. The meaning depends on $flags: if external diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index c269a70cde..e805c8cbda 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -812,6 +812,7 @@ $wgAutoloadLocalClasses = array( 'SpecialExport' => 'includes/specials/SpecialExport.php', 'SpecialFilepath' => 'includes/specials/SpecialFilepath.php', 'SpecialImport' => 'includes/specials/SpecialImport.php', + 'SpecialJavaScriptTest' => 'includes/specials/SpecialJavaScriptTest.php', 'SpecialListFiles' => 'includes/specials/SpecialListfiles.php', 'SpecialListGroupRights' => 'includes/specials/SpecialListgrouprights.php', 'SpecialListUsers' => 'includes/specials/SpecialListusers.php', diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 0f6dd0eaec..545a780ed6 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -4194,6 +4194,20 @@ $wgParserTestFiles = array( * ); */ $wgParserTestRemote = false; + +/** + * Allow running of javascript test suites via [[Special:JavaScriptTest]] (such as QUnit). + */ +$wgEnableJavaScriptTest = false; + +/** + * Configuration for javascript testing. + */ +$wgJavaScriptTestConfig = array( + 'qunit' => array( + 'documentation' => '//www.mediawiki.org/wiki/Manual:JavaScript_unit_testing', + ), +); /** @@ -5248,6 +5262,7 @@ $wgSpecialPageGroups = array( 'Specialpages' => 'other', 'Blockme' => 'other', 'Booksources' => 'other', + 'JavaScriptTest' => 'other', ); /** Whether or not to sort special pages in Special:Specialpages */ diff --git a/includes/Skin.php b/includes/Skin.php index 9ecb6150b3..1841f8a08e 100644 --- a/includes/Skin.php +++ b/includes/Skin.php @@ -22,7 +22,7 @@ abstract class Skin extends ContextSource { /** * Fetch the set of available skins. - * @return array of strings + * @return associative array of strings */ static function getSkinNames() { global $wgValidSkinNames; @@ -55,6 +55,18 @@ abstract class Skin extends ContextSource { } return $wgValidSkinNames; } + + /** + * Fetch the skinname messages for available skins. + * @return array of strings + */ + static function getSkinNameMessages() { + $messages = array(); + foreach( self::getSkinNames() as $skinKey => $skinName ) { + $messages[] = "skinname-$skinKey"; + } + return $messages; + } /** * Fetch the list of usable skins in regards to $wgSkipSkins. diff --git a/includes/SpecialPageFactory.php b/includes/SpecialPageFactory.php index a307575f18..0a1631b0fe 100644 --- a/includes/SpecialPageFactory.php +++ b/includes/SpecialPageFactory.php @@ -138,6 +138,7 @@ class SpecialPageFactory { 'Blankpage' => 'SpecialBlankpage', 'Blockme' => 'SpecialBlockme', 'Emailuser' => 'SpecialEmailUser', + 'JavaScriptTest' => 'SpecialJavaScriptTest', 'Movepage' => 'MovePageForm', 'Mycontributions' => 'SpecialMycontributions', 'Mypage' => 'SpecialMypage', diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index cfc64946d5..0d1eef02b3 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -37,6 +37,10 @@ class ResourceLoader { /** Associative array mapping module name to info associative array */ protected $moduleInfos = array(); + + /** Associative array mapping framework ids to a list of names of test suite modules */ + /** like array( 'qunit' => array( 'mediawiki.tests.qunit.suites', 'ext.foo.tests', .. ), .. ) */ + protected $testModuleNames = array(); /** array( 'source-id' => array( 'loadScript' => 'http://.../load.php' ) ) **/ protected $sources = array(); @@ -183,7 +187,7 @@ class ResourceLoader { * Registers core modules and runs registration hooks. */ public function __construct() { - global $IP, $wgResourceModules, $wgResourceLoaderSources, $wgLoadScript; + global $IP, $wgResourceModules, $wgResourceLoaderSources, $wgLoadScript, $wgEnableJavaScriptTest; wfProfileIn( __METHOD__ ); @@ -199,6 +203,11 @@ class ResourceLoader { wfRunHooks( 'ResourceLoaderRegisterModules', array( &$this ) ); $this->register( $wgResourceModules ); + if ( $wgEnableJavaScriptTest === true ) { + $this->registerTestModules(); + } + + wfProfileOut( __METHOD__ ); } @@ -256,6 +265,40 @@ class ResourceLoader { wfProfileOut( __METHOD__ ); } + /** + */ + public function registerTestModules() { + global $IP, $wgEnableJavaScriptTest; + + if ( $wgEnableJavaScriptTest !== true ) { + throw new MWException( 'Attempt to register JavaScript test modules but $wgEnableJavaScriptTest is false. Edit your LocalSettings.php to enable it.' ); + } + + wfProfileIn( __METHOD__ ); + + // Get core test suites + $testModules = array(); + $testModules['qunit'] = include( "$IP/tests/qunit/QUnitTestResources.php" ); + // Get other test suites (e.g. from extensions) + wfRunHooks( 'ResourceLoaderTestModules', array( &$testModules, &$this ) ); + + // Add the testrunner (which configures QUnit) to the dependencies. + // Since it must be ready before any of the test suites are executed. + foreach( $testModules['qunit'] as $moduleName => $moduleProps ) { + $testModules['qunit'][$moduleName]['dependencies'][] = 'mediawiki.tests.qunit.testrunner'; + } + + foreach( $testModules as $id => $names ) { + // Register test modules + $this->register( $testModules[$id] ); + + // Keep track of their names so that they can be loaded together + $this->testModuleNames[$id] = array_keys( $testModules[$id] ); + } + + wfProfileOut( __METHOD__ ); + } + /** * Add a foreign source of modules. * @@ -300,6 +343,25 @@ class ResourceLoader { public function getModuleNames() { return array_keys( $this->moduleInfos ); } + + /** + * Get a list of test module names for one (or all) frameworks. + * If the given framework id is unknkown, or if the in-object variable is not an array, + * then it will return an empty array. + * + * @param $framework String: Optional. Get only the test module names for one + * particular framework. + * @return Array + */ + public function getTestModuleNames( $framework = 'all' ) { + if ( $framework == 'all' ) { + return $this->testModuleNames; + } elseif ( isset( $this->testModuleNames[$framework] ) && is_array( $this->testModuleNames[$framework] ) ) { + return $this->testModuleNames[$framework]; + } else { + return array(); + } + } /** * Get the ResourceLoaderModule object for a given module name. diff --git a/includes/specials/SpecialJavaScriptTest.php b/includes/specials/SpecialJavaScriptTest.php new file mode 100644 index 0000000000..d19eb8e698 --- /dev/null +++ b/includes/specials/SpecialJavaScriptTest.php @@ -0,0 +1,127 @@ + 'initQUnitTesting', + ); + + public function __construct() { + parent::__construct( 'JavaScriptTest' ); + } + + public function execute( $par ) { + global $wgEnableJavaScriptTest; + + $out = $this->getOutput(); + + $this->setHeaders(); + $out->disallowUserJs(); + + // Abort early if we're disabled + if ( $wgEnableJavaScriptTest !== true ) { + $out->addWikiMsg( 'javascripttest-disabled' ); + return; + } + + $out->addModules( 'mediawiki.special.javaScriptTest' ); + + // Determine framework + $pars = explode( '/', $par ); + $framework = strtolower( $pars[0] ); + + // No framework specified + if ( $par == '' ) { + $out->setPagetitle( wfMsg( 'javascripttest' ) ); + $summary = $this->wrapSummaryHtml( + wfMsg( 'javascripttest-pagetext-noframework' ) . $this->getFrameworkListHtml(), + 'noframework' + ); + $out->addHtml( $summary ); + + // Matched! Display proper title and initialize the framework + } elseif ( isset( self::$frameworks[$framework] ) ) { + $out->setPagetitle( wfMsg( 'javascripttest-title', wfMsg( "javascripttest-$framework-name" ) ) ); + $out->setSubtitle( + wfMessage( 'javascripttest-backlink' )->rawParams( Linker::linkKnown( $this->getTitle() ) )->escaped() + ); + $this->{self::$frameworks[$framework]}(); + + // Framework not found, display error + } else { + $out->setPagetitle( wfMsg( 'javascripttest' ) ); + $summary = $this->wrapSummaryHtml( '

' + . wfMsg( 'javascripttest-pagetext-unknownframework', $par ) + . '

' + . $this->getFrameworkListHtml() ); + $out->addHtml( $summary, 'unknownframework' ); + } + } + + /** + * Get a list of frameworks (including introduction paragraph and links to the framework run pages) + * @return String: HTML + */ + private function getFrameworkListHtml() { + $list = ''; + $msg = wfMessage( 'javascripttest-pagetext-frameworks' )->rawParams( $list )->parseAsBlock(); + + return $msg; + } + + /** + * Function to wrap the summary. + * @param $html String: The raw HTML. + * @param $state String: State, one of 'noframework', 'unknownframework' or 'frameworkfound' + */ + private function wrapSummaryHtml( $html = '', $state ) { + return "
$html
"; + } + + /** + * Initialize the page for QUnit. + */ + private function initQUnitTesting() { + global $wgJavaScriptTestConfig; + + $out = $this->getOutput(); + + $out->addModules( 'mediawiki.tests.qunit.testrunner' ); + $qunitTestModules = $out->getResourceLoader()->getTestModuleNames( 'qunit' ); + $out->addModules( $qunitTestModules ); + + $summary = wfMessage( 'javascripttest-qunit-intro' ) + ->params( $wgJavaScriptTestConfig['qunit']['documentation'] ) + ->parseAsBlock(); + $header = wfMessage( 'javascripttest-qunit-heading' )->escaped(); + + $baseHtml = <<$header +
+
+
+
    +HTML; + $out->addHtml( $this->wrapSummaryHtml( $summary, 'frameworkfound' ) . $baseHtml ); + + } + + public function isListed(){ + global $wgEnableJavaScriptTest; + return $wgEnableJavaScriptTest === true; + } + +} diff --git a/languages/messages/MessagesEn.php b/languages/messages/MessagesEn.php index 8bdc59fe76..cd32d8d02d 100644 --- a/languages/messages/MessagesEn.php +++ b/languages/messages/MessagesEn.php @@ -393,6 +393,7 @@ $specialPageAliases = array( 'Filepath' => array( 'FilePath' ), 'Import' => array( 'Import' ), 'Invalidateemail' => array( 'InvalidateEmail' ), + 'JavaScriptTest' => array( 'JavaScriptTest' ), 'BlockList' => array( 'BlockList', 'ListBlocks', 'IPBlockList' ), 'LinkSearch' => array( 'LinkSearch' ), 'Listadmins' => array( 'ListAdmins' ), @@ -3405,6 +3406,19 @@ Please try again.', 'import-logentry-upload-detail' => '$1 {{PLURAL:$1|revision|revisions}}', 'import-logentry-interwiki' => 'transwikied $1', 'import-logentry-interwiki-detail' => '$1 {{PLURAL:$1|revision|revisions}} from $2', + +# JavaScriptTest +'javascripttest' => 'JavaScript Test', +'javascripttest-backlink' => '< $1', +'javascripttest-disabled' => 'This function is disabled.', +'javascripttest-title' => 'Running $1 tests', +'javascripttest-pagetext-noframework' => 'This page is reserved for running javascript tests.', +'javascripttest-pagetext-unknownframework' => 'Unknown framework "$1".', +'javascripttest-pagetext-frameworks' => 'Please choose one of the following frameworks: $1', +'javascripttest-pagetext-skins' => 'Available skins', +'javascripttest-qunit-name' => 'QUnit', // Ignore, do not translate +'javascripttest-qunit-intro' => 'See [$1 testing documentation] on mediawiki.org.', +'javascripttest-qunit-heading' => 'MediaWiki JavaScript QUnit Test Suite', // Optional, only translate if needed # Keyboard access keys for power users 'accesskey-pt-userpage' => '.', # do not translate or duplicate this message to other languages diff --git a/languages/messages/MessagesQqq.php b/languages/messages/MessagesQqq.php index b0f41bb2a7..6e3ad162ab 100644 --- a/languages/messages/MessagesQqq.php +++ b/languages/messages/MessagesQqq.php @@ -3059,6 +3059,17 @@ See also: 'import-logentry-upload' => 'This is the text of an entry in the Import log (and Recent Changes), after hour (and date, only in the Import log) and sysop name: * $1 is the name of the imported file', +# JavaScriptTest +'javascripttest' => 'Title of the special page', +'javascripttest-backlink' => '{{optional}}', +'javascripttest-disabled' => '{{Identical|Function disabled}}.', +'javascripttest-title' => 'Title of the special page when running a test suite. $1 is the name of the framework.', +'javascripttest-pagetext-unknownframework' => 'Error message when given framework id is not found. $1 is the if of the framework.', +'javascripttest-pagetext-frameworks' => '$1 is the if of the framework.', +'javascripttest-qunit-name' => '{{Ignore}}', +'javascripttest-qunit-intro' => '$1 is the configured url to the documentation.', +'javascripttest-qunit-heading' => '{{Optional}}', + # Tooltip help for the actions 'tooltip-pt-userpage' => 'Tooltip shown when hovering the mouse over the link to your own User page in the upper-side personal toolbox.', 'tooltip-pt-mytalk' => 'Tooltip shown when hovering over the "my talk" link in your personal toolbox (upper right side).', diff --git a/resources/Resources.php b/resources/Resources.php index 8d73540e0e..463c85c90e 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -166,15 +166,15 @@ return array( 'jquery.placeholder' => array( 'scripts' => 'resources/jquery/jquery.placeholder.js', ), - 'jquery.qunit.completenessTest' => array( - 'scripts' => 'resources/jquery/jquery.qunit.completenessTest.js', - 'dependencies' => 'jquery.qunit', - ), 'jquery.qunit' => array( 'scripts' => 'resources/jquery/jquery.qunit.js', 'styles' => 'resources/jquery/jquery.qunit.css', 'position' => 'top', ), + 'jquery.qunit.completenessTest' => array( + 'scripts' => 'resources/jquery/jquery.qunit.completenessTest.js', + 'dependencies' => 'jquery.qunit', + ), 'jquery.spinner' => array( 'scripts' => 'resources/jquery/jquery.spinner.js', 'styles' => 'resources/jquery/jquery.spinner.css', @@ -767,6 +767,28 @@ return array( ), 'dependencies' => array( 'mediawiki.libs.jpegmeta', 'mediawiki.util' ), ), + 'mediawiki.special.javaScriptTest' => array( + 'scripts' => 'resources/mediawiki.special/mediawiki.special.javaScriptTest.js', + 'messages' => array_merge( Skin::getSkinNameMessages(), array( + 'colon-separator', + 'javascripttest-pagetext-skins', + ) ), + 'dependencies' => array( 'jquery.qunit' ), + 'position' => 'top', + ), + + /* MediaWiki Tests */ + + 'mediawiki.tests.qunit.testrunner' => array( + 'scripts' => 'tests/qunit/data/testrunner.js', + 'dependencies' => array( + 'jquery.qunit', + 'jquery.qunit.completenessTest', + 'mediawiki.page.startup', + 'mediawiki.page.ready', + ), + 'position' => 'top', + ), /* MediaWiki Legacy */ diff --git a/resources/mediawiki.special/mediawiki.special.javaScriptTest.js b/resources/mediawiki.special/mediawiki.special.javaScriptTest.js new file mode 100644 index 0000000000..a342989c24 --- /dev/null +++ b/resources/mediawiki.special/mediawiki.special.javaScriptTest.js @@ -0,0 +1,33 @@ +/* + * JavaScript for Special:JavaScriptTest + */ +jQuery( document ).ready( function( $ ) { + + // Create useskin dropdown menu and reload onchange to the selected skin + // (only if a framework was found, not on error pages). + $( '#mw-javascripttest-summary.mw-javascripttest-frameworkfound' ).append( function() { + + var $html = $( '

    ' ), + select = ' further + $.each( mw.config.get( 'wgAvailableSkins' ), function( id ) { + select += ''; + } ); + select += ''; + + // Bind onchange event handler and append to form + $html.append( + $( select ).change( function() { + window.location = QUnit.url( { useskin: $(this).val() } ); + } ) + ); + + return $html; + } ); +} ); diff --git a/tests/qunit/QUnitTestResources.php b/tests/qunit/QUnitTestResources.php new file mode 100644 index 0000000000..a744009b0c --- /dev/null +++ b/tests/qunit/QUnitTestResources.php @@ -0,0 +1,55 @@ + array( + 'scripts' => array( + 'tests/qunit/suites/resources/jquery/jquery.autoEllipsis.test.js', + 'tests/qunit/suites/resources/jquery/jquery.byteLength.test.js', + 'tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js', + 'tests/qunit/suites/resources/jquery/jquery.client.test.js', + 'tests/qunit/suites/resources/jquery/jquery.colorUtil.test.js', + 'tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js', + 'tests/qunit/suites/resources/jquery/jquery.highlightText.test.js', + 'tests/qunit/suites/resources/jquery/jquery.localize.test.js', + 'tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js', + 'tests/qunit/suites/resources/jquery/jquery.tabIndex.test.js', + 'tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js', + 'tests/qunit/suites/resources/jquery/jquery.textSelection.test.js', + 'tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js', + 'tests/qunit/suites/resources/mediawiki/mediawiki.test.js', + 'tests/qunit/suites/resources/mediawiki/mediawiki.title.test.js', + 'tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js', + 'tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js', + 'tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js', + + // *has mw-config def: + // This means the module overwrites/sets mw.config variables, reason being that + // the static /qunit/index.html has an empty mw.config since it's static. + // Until /qunit/index.html is fully replaceable and WMF's TestSwarm is up and running + // with Special:JavaScriptTest - untill then, it is important that tests do not depend + // on anything being in mw.config (not even wgServer). + ), + 'dependencies' => array( + 'jquery.autoEllipsis', + 'jquery.byteLength', + 'jquery.byteLimit', + 'jquery.client', + 'jquery.colorUtil', + 'jquery.getAttrs', + 'jquery.highlightText', + 'jquery.localize', + 'jquery.mwExtension', + 'jquery.tabIndex', + 'jquery.tablesorter', + 'jquery.textSelection', + 'mediawiki', + 'mediawiki.Title', + 'mediawiki.user', + 'mediawiki.util', + 'mediawiki.special.recentchanges', + ), + ) +); diff --git a/tests/qunit/data/testrunner.js b/tests/qunit/data/testrunner.js index 8e6671ed96..fdd3116b07 100644 --- a/tests/qunit/data/testrunner.js +++ b/tests/qunit/data/testrunner.js @@ -1,13 +1,19 @@ -( function( $ ) { +( function ( $, mw, QUnit, undefined ) { +"use strict"; + +var mwTestIgnore, mwTester, addons; /** * Add bogus to url to prevent IE crazy caching * - * @param value {String} a relative path (eg. 'data/defineTestCallback.js' or 'data/test.php?foo=bar') + * @param value {String} a relative path (eg. 'data/defineTestCallback.js' + * or 'data/test.php?foo=bar'). * @return {String} Such as 'data/defineTestCallback.js?131031765087663960' */ -QUnit.fixurl = function(value) { - return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000); +QUnit.fixurl = function (value) { + return value + (/\?/.test( value ) ? '&' : '?') + + String( new Date().getTime() ) + + String( parseInt( Math.random()*100000, 10 ) ); }; /** @@ -15,31 +21,41 @@ QUnit.fixurl = function(value) { */ QUnit.config.testTimeout = 5000; +/** + * MediaWiki debug mode + */ +QUnit.config.urlConfig.push( 'debug' ); + /** * Load TestSwarm agent */ if ( QUnit.urlParams.swarmURL ) { - document.write(""); + document.write( "" ); } /** - * Load completenesstest + * CompletenessTest */ +// Adds toggle checkbox to header +QUnit.config.urlConfig.push( 'completenesstest' ); + +// Initiate when enabled if ( QUnit.urlParams.completenesstest ) { // Return true to ignore - var mwTestIgnore = function( val, tester, funcPath ) { + mwTestIgnore = function ( val, tester, funcPath ) { // Don't record methods of the properties of constructors, // to avoid getting into a loop (prototype.constructor.prototype..). // Since we're therefor skipping any injection for // "new mw.Foo()", manually set it to true here. if ( val instanceof mw.Map ) { - tester.methodCallTracker['Map'] = true; + tester.methodCallTracker.Map = true; return true; } if ( val instanceof mw.Title ) { - tester.methodCallTracker['Title'] = true; + tester.methodCallTracker.Title = true; return true; } @@ -51,42 +67,113 @@ if ( QUnit.urlParams.completenesstest ) { return false; }; - var mwTester = new CompletenessTest( mw, mwTestIgnore ); + mwTester = new CompletenessTest( mw, mwTestIgnore ); } +/** + * Test environment recommended for all QUnit test modules + */ +// Whether to log environment changes to the console +QUnit.config.urlConfig.push( 'mwlogenv' ); + +/** + * Reset mw.config to a fresh copy of the live config for each test(); + * @param override {Object} [optional] + * @example: + * + * module( .., newMwEnvironment() ); + * + * test( .., function () { + * mw.config.set( 'foo', 'bar' ); // just for this test + * } ); + * + * test( .., function () { + * mw.config.get( 'foo' ); // doesn't exist + * } ); + * + * + * module( .., newMwEnvironment({ quux: 'corge' }) ); + * + * test( .., function () { + * mw.config.get( 'quux' ); // "corge" + * mw.config.set( 'quux', "grault" ); + * } ); + * + * test( .., function () { + * mw.config.get( 'quux' ); // "corge" + * } ); + * + */ +QUnit.newMwEnvironment = ( function () { + var liveConfig, freshConfigCopy, log; + + liveConfig = mw.config.values; + + freshConfigCopy = function ( custom ) { + // "deep=true" is important here. + // Otherwise we just create a new object with values referring to live config. + // e.g. mw.config.set( 'wgFileExtensions', [] ) would not effect liveConfig, + // but mw.config.get( 'wgFileExtensions' ).push( 'png' ) would as the array + // was passed by reference in $.extend's loop. + return $.extend({}, liveConfig, custom, /*deep=*/true ); + }; + + log = QUnit.urlParams.mwlogenv ? mw.log : function () {}; + + return function ( override ) { + override = override || {}; + + return { + setup: function () { + log( 'MwEnvironment> SETUP for "' + QUnit.config.current.module + + ': ' + QUnit.config.current.testName + '"' ); + // Greetings, mock configuration! + mw.config.values = freshConfigCopy( override ); + }, + + teardown: function () { + log( 'MwEnvironment> TEARDOWN for "' + QUnit.config.current.module + + ': ' + QUnit.config.current.testName + '"' ); + // Farewell, mock configuration! + mw.config.values = liveConfig; + } + }; + }; +}() ); + /** * Add-on assertion helpers */ // Define the add-ons -var addons = { +addons = { // Expect boolean true - assertTrue: function( actual, message ) { + assertTrue: function ( actual, message ) { strictEqual( actual, true, message ); }, // Expect boolean false - assertFalse: function( actual, message ) { + assertFalse: function ( actual, message ) { strictEqual( actual, false, message ); }, // Expect numerical value less than X - lt: function( actual, expected, message ) { + lt: function ( actual, expected, message ) { QUnit.push( actual < expected, actual, 'less than ' + expected, message ); }, // Expect numerical value less than or equal to X - ltOrEq: function( actual, expected, message ) { + ltOrEq: function ( actual, expected, message ) { QUnit.push( actual <= expected, actual, 'less than or equal to ' + expected, message ); }, // Expect numerical value greater than X - gt: function( actual, expected, message ) { + gt: function ( actual, expected, message ) { QUnit.push( actual > expected, actual, 'greater than ' + expected, message ); }, // Expect numerical value greater than or equal to X - gtOrEq: function( actual, expected, message ) { + gtOrEq: function ( actual, expected, message ) { QUnit.push( actual >= expected, actual, 'greater than or equal to ' + expected, message ); }, @@ -98,4 +185,4 @@ var addons = { $.extend( QUnit, addons ); $.extend( window, addons ); -})( jQuery ); +})( jQuery, mediaWiki, QUnit ); diff --git a/tests/qunit/suites/resources/jquery/jquery.autoEllipsis.test.js b/tests/qunit/suites/resources/jquery/jquery.autoEllipsis.test.js index 690ffb21e8..ba03f2b2ff 100644 --- a/tests/qunit/suites/resources/jquery/jquery.autoEllipsis.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.autoEllipsis.test.js @@ -1,4 +1,4 @@ -module( 'jquery.autoEllipsis' ); +module( 'jquery.autoEllipsis', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(1); diff --git a/tests/qunit/suites/resources/jquery/jquery.byteLength.test.js b/tests/qunit/suites/resources/jquery/jquery.byteLength.test.js index 68a08b968d..15fac69119 100644 --- a/tests/qunit/suites/resources/jquery/jquery.byteLength.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.byteLength.test.js @@ -1,4 +1,4 @@ -module( 'jquery.byteLength' ); +module( 'jquery.byteLength', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(1); diff --git a/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js b/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js index 7e28c72310..2c4dda6332 100644 --- a/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js @@ -1,4 +1,6 @@ -module( 'jquery.byteLimit' ); +( function () { + +module( 'jquery.byteLimit', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(1); @@ -150,8 +152,6 @@ byteLimitTest({ $input: $( '' ) .attr( 'type', 'text' ) .byteLimit( 6, function( val ) { - _titleConfig(); - // Invalid title if ( val == '' ) { return ''; @@ -172,8 +172,6 @@ byteLimitTest({ .attr( 'type', 'text' ) .prop( 'maxLength', '6' ) .byteLimit( function( val ) { - _titleConfig(); - // Invalid title if ( val === '' ) { return ''; @@ -187,3 +185,5 @@ byteLimitTest({ limit: 6, // 'Sample' length expected: 'User:Sample' }); + +}() ); \ No newline at end of file diff --git a/tests/qunit/suites/resources/jquery/jquery.client.test.js b/tests/qunit/suites/resources/jquery/jquery.client.test.js index 99c3070d8e..f6eb700e04 100644 --- a/tests/qunit/suites/resources/jquery/jquery.client.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.client.test.js @@ -1,4 +1,4 @@ -module( 'jquery.client' ); +module( 'jquery.client', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(1); diff --git a/tests/qunit/suites/resources/jquery/jquery.colorUtil.test.js b/tests/qunit/suites/resources/jquery/jquery.colorUtil.test.js index 88791cada0..655ee564f9 100644 --- a/tests/qunit/suites/resources/jquery/jquery.colorUtil.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.colorUtil.test.js @@ -1,4 +1,4 @@ -module( 'jquery.colorUtil' ); +module( 'jquery.colorUtil', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(1); diff --git a/tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js b/tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js index 5685756f3d..9377a2f63f 100644 --- a/tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js @@ -1,4 +1,4 @@ -module( 'jquery.getAttrs' ); +module( 'jquery.getAttrs', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(1); diff --git a/tests/qunit/suites/resources/jquery/jquery.highlightText.test.js b/tests/qunit/suites/resources/jquery/jquery.highlightText.test.js index 1d506dab53..4750d2b879 100644 --- a/tests/qunit/suites/resources/jquery/jquery.highlightText.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.highlightText.test.js @@ -1,4 +1,4 @@ -module( 'jquery.highlightText' ); +module( 'jquery.highlightText', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(1); diff --git a/tests/qunit/suites/resources/jquery/jquery.localize.test.js b/tests/qunit/suites/resources/jquery/jquery.localize.test.js index c5d8c4ddda..cd82863465 100644 --- a/tests/qunit/suites/resources/jquery/jquery.localize.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.localize.test.js @@ -1,4 +1,4 @@ -module( 'jquery.localize' ); +module( 'jquery.localize', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(1); diff --git a/tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js b/tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js index 7a1281d397..3a2d0d831d 100644 --- a/tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js @@ -1,4 +1,4 @@ -module( 'jquery.mwExtension' ); +module( 'jquery.mwExtension', QUnit.newMwEnvironment() ); test( 'String functions', function() { diff --git a/tests/qunit/suites/resources/jquery/jquery.tabIndex.test.js b/tests/qunit/suites/resources/jquery/jquery.tabIndex.test.js index 7d014f38e4..f26ba7b168 100644 --- a/tests/qunit/suites/resources/jquery/jquery.tabIndex.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.tabIndex.test.js @@ -1,4 +1,4 @@ -module( 'jquery.tabIndex' ); +module( 'jquery.tabIndex', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(2); diff --git a/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js b/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js index 61f1408df1..31415d61a7 100644 --- a/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js @@ -1,12 +1,13 @@ -(function() { +( function () { -module( 'jquery.tablesorter' ); - -// setup hack -mw.config.set( 'wgMonthNames', [ '', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ] ); -mw.config.set( 'wgMonthNamesShort', ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] ); -mw.config.set( 'wgDefaultDateFormat', 'dmy' ); +var config = { + wgMonthNames: ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + wgMonthNamesShort: ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + wgDefaultDateFormat: 'dmy', + wgContentLanguage: 'en' +}; +module( 'jquery.tablesorter', QUnit.newMwEnvironment( config ) ); test( '-- Initial check', function() { expect(1); @@ -181,8 +182,9 @@ tableTest( ['11.11.2011'] ], function( $table ) { - // @fixme reset it at end or change module to allow us to override it mw.config.set( 'wgDefaultDateFormat', 'dmy' ); + mw.config.set( 'wgContentLanguage', 'de' ); + $table.tablesorter(); $table.find( '.headerSort:eq(0)' ).click(); } @@ -206,8 +208,8 @@ tableTest( ['11.11.2011'] ], function( $table ) { - // @fixme reset it at end or change module to allow us to override it mw.config.set( 'wgDefaultDateFormat', 'mdy' ); + $table.tablesorter(); $table.find( '.headerSort:eq(0)' ).click(); } @@ -293,9 +295,9 @@ tableTest( 'ß': 'ss', 'ü':'ue' } ); + $table.tablesorter(); $table.find( '.headerSort:eq(0)' ).click(); - mw.config.set( 'tableSorterCollation', {} ); } ); @@ -361,6 +363,7 @@ tableTest( complexMDYSorted, function( $table ) { mw.config.set( 'wgDefaultDateFormat', 'mdy' ); + $table.tablesorter(); $table.find( '.headerSort:eq(0)' ).click(); } diff --git a/tests/qunit/suites/resources/jquery/jquery.textSelection.test.js b/tests/qunit/suites/resources/jquery/jquery.textSelection.test.js index a493bbeed6..a9a244672e 100644 --- a/tests/qunit/suites/resources/jquery/jquery.textSelection.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.textSelection.test.js @@ -1,4 +1,4 @@ -module( 'jquery.textSelection' ); +module( 'jquery.textSelection', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(1); diff --git a/tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js b/tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js index e959d4bcfc..d73fe5a650 100644 --- a/tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js +++ b/tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js @@ -1,4 +1,4 @@ -module( 'mediawiki.special.recentchanges' ); +module( 'mediawiki.special.recentchanges', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect( 2 ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js index 4d1b50e7e6..e04111f106 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js @@ -1,71 +1,69 @@ -module( 'mediawiki.Title' ); +( function () { // mw.Title relies on these three config vars // Restore them after each test run -var _titleConfig = function() { - - mw.config.set({ - "wgFormattedNamespaces": { - "-2": "Media", - "-1": "Special", - "0": "", - "1": "Talk", - "2": "User", - "3": "User talk", - "4": "Wikipedia", - "5": "Wikipedia talk", - "6": "File", - "7": "File talk", - "8": "MediaWiki", - "9": "MediaWiki talk", - "10": "Template", - "11": "Template talk", - "12": "Help", - "13": "Help talk", - "14": "Category", - "15": "Category talk", - /* testing custom / localized */ - "100": "Penguins" - }, - "wgNamespaceIds": { - "media": -2, - "special": -1, - "": 0, - "talk": 1, - "user": 2, - "user_talk": 3, - "wikipedia": 4, - "wikipedia_talk": 5, - "file": 6, - "file_talk": 7, - "mediawiki": 8, - "mediawiki_talk": 9, - "template": 10, - "template_talk": 11, - "help": 12, - "help_talk": 13, - "category": 14, - "category_talk": 15, - "image": 6, - "image_talk": 7, - "project": 4, - "project_talk": 5, - /* testing custom / alias */ - "penguins": 100, - "antarctic_waterfowl": 100 - }, - "wgCaseSensitiveNamespaces": [] - }); +var config = { + "wgFormattedNamespaces": { + "-2": "Media", + "-1": "Special", + "0": "", + "1": "Talk", + "2": "User", + "3": "User talk", + "4": "Wikipedia", + "5": "Wikipedia talk", + "6": "File", + "7": "File talk", + "8": "MediaWiki", + "9": "MediaWiki talk", + "10": "Template", + "11": "Template talk", + "12": "Help", + "13": "Help talk", + "14": "Category", + "15": "Category talk", + // testing custom / localized namespace + "100": "Penguins" + }, + "wgNamespaceIds": { + "media": -2, + "special": -1, + "": 0, + "talk": 1, + "user": 2, + "user_talk": 3, + "wikipedia": 4, + "wikipedia_talk": 5, + "file": 6, + "file_talk": 7, + "mediawiki": 8, + "mediawiki_talk": 9, + "template": 10, + "template_talk": 11, + "help": 12, + "help_talk": 13, + "category": 14, + "category_talk": 15, + "image": 6, + "image_talk": 7, + "project": 4, + "project_talk": 5, + /* testing custom / alias */ + "penguins": 100, + "antarctic_waterfowl": 100 + }, + "wgCaseSensitiveNamespaces": [] }; -test( '-- Initial check', function() { +module( 'mediawiki.Title', QUnit.newMwEnvironment( config ) ); + +test( '-- Initial check', function () { expect(1); ok( mw.Title, 'mw.Title defined' ); }); -test( 'Transformation', function() { +test( 'Transformation', function () { expect(8); - _titleConfig(); var title; @@ -89,9 +87,8 @@ test( 'Transformation', function() { equal( title.getName(), 'Foo_bar_.js', "Merge multiple spaces to a single space." ); }); -test( 'Main text for filename', function() { +test( 'Main text for filename', function () { expect(8); - _titleConfig(); var title = new mw.Title( 'File:foo_bar.JPG' ); @@ -105,9 +102,8 @@ test( 'Main text for filename', function() { equal( title.getDotExtension(), '.JPG' ); }); -test( 'Namespace detection and conversion', function() { +test( 'Namespace detection and conversion', function () { expect(6); - _titleConfig(); var title; @@ -128,18 +124,16 @@ test( 'Namespace detection and conversion', function() { equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' ); }); -test( 'Throw error on invalid title', function() { +test( 'Throw error on invalid title', function () { expect(1); - _titleConfig(); - raises(function() { + raises(function () { var title = new mw.Title( '' ); }, 'Throw error on empty string' ); }); -test( 'Case-sensivity', function() { +test( 'Case-sensivity', function () { expect(3); - _titleConfig(); var title; @@ -159,9 +153,8 @@ test( 'Case-sensivity', function() { equal( title.toString(), 'User:John', '$wgCapitalLinks=false: User namespace is insensitive, first-letter becomes uppercase' ); }); -test( 'toString / toText', function() { +test( 'toString / toText', function () { expect(2); - _titleConfig(); var title = new mw.Title( 'Some random page' ); @@ -169,9 +162,8 @@ test( 'toString / toText', function() { equal( title.toText(), title.getPrefixedText() ); }); -test( 'Exists', function() { +test( 'Exists', function () { expect(3); - _titleConfig(); var title; @@ -191,9 +183,8 @@ test( 'Exists', function() { }); -test( 'Url', function() { +test( 'Url', function () { expect(2); - _titleConfig(); var title; @@ -206,3 +197,5 @@ test( 'Url', function() { title = new mw.Title( 'John Doe', 3 ); equal( title.getUrl(), '/wiki/User_talk:John_Doe', 'Escaping in title and namespace for urls' ); }); + +}() ); \ No newline at end of file diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js index adaf5f964e..24005b645e 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js @@ -1,6 +1,6 @@ /* Some misc JavaScript compatibility tests, just to make sure the environments we run in are consistent */ -module( 'mediawiki.jscompat' ); +module( 'mediawiki.jscompat', QUnit.newMwEnvironment() ); test( 'Variable with Unicode letter in name', function() { expect(3); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js index 85c2472714..92141315df 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js @@ -1,4 +1,4 @@ -module( 'mediawiki' ); +module( 'mediawiki', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(8); @@ -173,12 +173,29 @@ test( 'mw.loader.bug30825', function() { // This bug was actually already fixed in 1.18 and later when discovered in 1.17. // Test is for regressions! - expect(1); + expect(2); + + var server = mw.config.get( 'wgServer' ), + basePath = mw.config.get( 'wgScriptPath' ); + + // From [[Special:JavaScriptTest]] we need to preprend the script path + // with the actual server (http://localhost/). + // Running from file tests/qunit/index.html, wgScriptPath is already + // including the wgServer part + if( server !== null ) { + basePath = server + basePath; + } + // Forge an URL to the test callback script + var target = QUnit.fixurl( + basePath + '/tests/qunit/data/qunitOkCall.js' + ); // Confirm that mw.loader.load() works with protocol-relative URLs - var loc = window.location, - base = ('//' + loc.hostname + loc.pathname).replace(/\/[^\/]*$/, ''), - target = base + '/data/qunitOkCall.js?' + (new Date()).getTime(); + target = target.replace( /https?:/, '' ); + + equal( target.substr( 0, 2 ), '//', + 'URL must be relative to test relative URLs!' + ); // Async! stop(); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js index 1aa46989fd..15265db57d 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js @@ -1,4 +1,4 @@ -module( 'mediawiki.user' ); +module( 'mediawiki.user', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(1); @@ -16,6 +16,16 @@ test( 'options', function() { test( 'User login status', function() { expect(5); + /** + * Tests can be run under three different conditions: + * 1) From tests/qunit/index.html, user will be anonymous. + * 2) Logged in on [[Special:JavaScriptTest/qunit]] + * 3) Anonymously at the same special page. + */ + + // Forge an anonymous user: + mw.config.set( 'wgUserName', null); + strictEqual( mw.user.name(), null, 'user.name should return null when anonymous' ); ok( mw.user.anonymous(), 'user.anonymous should reutrn true when anonymous' ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js index da18f02f4a..445f82cb86 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js @@ -1,4 +1,4 @@ -module( 'mediawiki.util' ); +module( 'mediawiki.util', QUnit.newMwEnvironment() ); test( '-- Initial check', function() { expect(1); @@ -39,7 +39,6 @@ test( 'wikiGetlink', function() { test( 'wikiScript', function() { expect(2); - var prevConfig = mw.config.get([ 'wgScript', 'wgScriptPath', 'wgScriptExtension' ]); mw.config.set({ 'wgScript': '/w/index.php', 'wgScriptPath': '/w', @@ -48,9 +47,6 @@ test( 'wikiScript', function() { equal( mw.util.wikiScript(), mw.config.get( 'wgScript' ), 'Defaults to index.php and is equal to wgScript' ); equal( mw.util.wikiScript( 'api' ), '/w/api.php', 'API path' ); - - // Restore mw.config - mw.config.set( prevConfig ); }); test( 'addCSS', function() { -- 2.20.1