From d1666a89fff613f42c682b454d690186a4702dfd Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Fri, 18 Jan 2019 12:21:35 -0800 Subject: [PATCH] resourceloader: Support TestModules registration via extension.json Bug: T126091 Change-Id: I27ecebe27d7aaebe6d1317bc5eaea9cca368b45d --- RELEASE-NOTES-1.33 | 3 ++ docs/extension.schema.v1.json | 4 ++ docs/extension.schema.v2.json | 47 +++++++++++++++++++ docs/hooks.txt | 20 ++++---- includes/registration/ExtensionProcessor.php | 16 ++++++- includes/resourceloader/ResourceLoader.php | 20 ++++---- .../registration/ExtensionProcessorTest.php | 32 ++++++++++++- 7 files changed, 119 insertions(+), 23 deletions(-) diff --git a/RELEASE-NOTES-1.33 b/RELEASE-NOTES-1.33 index 5c4832a750..d3117ca560 100644 --- a/RELEASE-NOTES-1.33 +++ b/RELEASE-NOTES-1.33 @@ -222,6 +222,9 @@ because of Phabricator reports. * Password::equals() is deprecated, use verify(). * BaseTemplate::msgWiki() and QuickTemplate::msgWiki() will be removed. Use other means to fetch a properly escaped message string or Message object. +* (T126091) The 'ResourceLoaderTestModules' hook, which lets you declare QUnit + testing code for your JavaScript modules, is deprecated. Instead, you can now + use the new extension registration key 'QUnitTestModule'. === Other changes in 1.33 === * (T208871) The hard-coded Google search form on the database error page was diff --git a/docs/extension.schema.v1.json b/docs/extension.schema.v1.json index dc0abdcd5d..fcc41af376 100644 --- a/docs/extension.schema.v1.json +++ b/docs/extension.schema.v1.json @@ -360,6 +360,10 @@ "type": "object", "description": "ResourceLoader sources to register" }, + "QUnitTestModule": { + "type": "object", + "description": "A ResourceLoaderFileModule definition registered only when wgEnableJavaScriptTest is true." + }, "ConfigRegistry": { "type": "object", "description": "Registry of factory functions to create Config objects" diff --git a/docs/extension.schema.v2.json b/docs/extension.schema.v2.json index 9da636f4fd..d561638905 100644 --- a/docs/extension.schema.v2.json +++ b/docs/extension.schema.v2.json @@ -373,6 +373,53 @@ "type": "object", "description": "ResourceLoader sources to register" }, + "QUnitTestModule": { + "type": "object", + "description": "A ResourceLoaderFileModule definition registered only when wgEnableJavaScriptTest is true.", + "additionalProperties": false, + "properties": { + "localBasePath": { + "type": "string", + "description": "Prefix for local paths to files in $options, relative to extenion directory" + }, + "remoteExtPath": { + "type": "string", + "description": "Prefix for URLs to files in $options, relative to $wgExtensionAssetsPath" + }, + "remoteSkinPath": { + "type": "string", + "description": "Prefix for URLs to files in $options, relative to $wgStylePath" + }, + "scripts": { + "type": ["string", "array"], + "description": "Scripts to include (array of file paths)", + "items": { + "type": "string" + } + }, + "dependencies": { + "type": ["string", "array"], + "description": "Modules which must be loaded before this module", + "items": { + "type": "string" + } + }, + "styles": { + "type": ["string", "array", "object"], + "description": "Styles to load", + "items": { + "type": "string" + } + }, + "messages": { + "type": ["string", "array"], + "description": "Messages to load", + "items": { + "type": "string" + } + } + } + }, "ConfigRegistry": { "type": "object", "description": "Registry of factory functions to create Config objects" diff --git a/docs/hooks.txt b/docs/hooks.txt index d175bcdf82..8b5e4d7a70 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -2833,17 +2833,17 @@ such as when responding to a resource 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 resources. -&$testModules: array of JavaScript testing modules. The 'qunit' framework, - included in core, is fed using tests/qunit/QUnitTestResources.php. - To add a new qunit module named 'myext.tests': - $testModules['qunit']['myext.tests'] = [ - 'script' => 'extension/myext/tests.js', - 'dependencies' => +'ResourceLoaderTestModules': DEPRECATED since 1.33! Register ResourceLoader modules +that are only available when `$wgEnableJavaScriptTest` is true. Use this for test +suites and other test-only resources. +&$testModules: one array of modules per test framework. The modules array +follows the same format as `$wgResourceModules`. For example: + $testModules['qunit']['ext.Example.test'] = [ + 'localBasePath' => __DIR__ . '/tests/qunit', + 'remoteExtPath' => 'Example/tests/qunit', + 'script' => [ 'tests/qunit/foo.js' ], + 'dependencies' => [ 'ext.Example.foo' ] ]; - For QUnit framework, the mediawiki.tests.qunit.testrunner dependency will be - added to any module. &$ResourceLoader: object 'RevisionDataUpdates': Called when constructing a list of DeferrableUpdate to be diff --git a/includes/registration/ExtensionProcessor.php b/includes/registration/ExtensionProcessor.php index 07fab78f96..1d3fd86d8b 100644 --- a/includes/registration/ExtensionProcessor.php +++ b/includes/registration/ExtensionProcessor.php @@ -107,7 +107,7 @@ class ExtensionProcessor implements Processor { ]; /** - * Things that are not 'attributes', but are not in + * Things that are not 'attributes', and are not in * $globalSettings or $creditsAttributes. * * @var array @@ -119,6 +119,7 @@ class ExtensionProcessor implements Processor { 'ResourceFileModulePaths', 'ResourceModules', 'ResourceModuleSkinStyles', + 'QUnitTestModule', 'ExtensionMessagesFiles', 'MessagesDirs', 'type', @@ -394,6 +395,19 @@ class ExtensionProcessor implements Processor { } } } + + if ( isset( $info['QUnitTestModule'] ) ) { + $data = $info['QUnitTestModule']; + if ( isset( $data['localBasePath'] ) ) { + if ( $data['localBasePath'] === '' ) { + // Avoid double slashes (e.g. /extensions/Example//path) + $data['localBasePath'] = $dir; + } else { + $data['localBasePath'] = "$dir/{$data['localBasePath']}"; + } + } + $this->attributes['QUnitTestModules']["test.{$info['name']}"] = $data; + } } protected function extractExtensionMessagesFiles( $dir, array $info ) { diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index c513aed018..f05c8c8d98 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -408,24 +408,24 @@ class ResourceLoader implements LoggerAwareInterface { . 'Edit your LocalSettings.php to enable it.' ); } - // Get core test suites - $testModules = []; - $testModules['qunit'] = []; - // Get other test suites (e.g. from extensions) + $testModules = [ + 'qunit' => [], + ]; + + // Get test suites from extensions // Avoid PHP 7.1 warning from passing $this by reference $rl = $this; Hooks::run( 'ResourceLoaderTestModules', [ &$testModules, &$rl ] ); + $extRegistry = ExtensionRegistry::getInstance(); + // In case of conflict, the deprecated hook has precedence. + $testModules['qunit'] += $extRegistry->getAttribute( 'QUnitTestModules' ); - // Add the testrunner (which configures QUnit) to the dependencies. - // Since it must be ready before any of the test suites are executed. + // Add the QUnit testrunner as implicit dependency to extension test suites. foreach ( $testModules['qunit'] as &$module ) { - // Make sure all test modules are top-loading so that when QUnit starts - // on document-ready, it will run once and finish. If some tests arrive - // later (possibly after QUnit has already finished) they will be ignored. - $module['position'] = 'top'; $module['dependencies'][] = 'test.mediawiki.qunit.testrunner'; } + // Get core test suites $testModules['qunit'] = ( include "$IP/tests/qunit/QUnitTestResources.php" ) + $testModules['qunit']; diff --git a/tests/phpunit/includes/registration/ExtensionProcessorTest.php b/tests/phpunit/includes/registration/ExtensionProcessorTest.php index 71a3a4fa80..d5a2b3a5a7 100644 --- a/tests/phpunit/includes/registration/ExtensionProcessorTest.php +++ b/tests/phpunit/includes/registration/ExtensionProcessorTest.php @@ -357,13 +357,20 @@ class ExtensionProcessorTest extends MediaWikiTestCase { /** * @dataProvider provideExtractResourceLoaderModules */ - public function testExtractResourceLoaderModules( $input, $expected ) { + public function testExtractResourceLoaderModules( + $input, + array $expectedGlobals, + array $expectedAttribs = [] + ) { $processor = new ExtensionProcessor(); $processor->extractInfo( $this->dir, $input + self::$default, 1 ); $out = $processor->getExtractedInfo(); - foreach ( $expected as $key => $value ) { + foreach ( $expectedGlobals as $key => $value ) { $this->assertEquals( $value, $out['globals'][$key] ); } + foreach ( $expectedAttribs as $key => $value ) { + $this->assertEquals( $value, $out['attributes'][$key] ); + } } public static function provideExtractResourceLoaderModules() { @@ -503,6 +510,27 @@ class ExtensionProcessorTest extends MediaWikiTestCase { ], ], ], + 'QUnit test module' => [ + // Input + [ + 'QUnitTestModule' => [ + 'localBasePath' => '', + 'remoteExtPath' => 'Foo', + 'scripts' => 'bar.js', + ], + ], + // Expected + [], + [ + 'QUnitTestModules' => [ + 'test.FooBar' => [ + 'localBasePath' => $dir, + 'remoteExtPath' => 'Foo', + 'scripts' => 'bar.js', + ], + ], + ], + ], ]; } -- 2.20.1