resourceloader: Support TestModules registration via extension.json

Bug: T126091
Change-Id: I27ecebe27d7aaebe6d1317bc5eaea9cca368b45d
This commit is contained in:
Timo Tijhof 2019-01-18 12:21:35 -08:00 committed by James D. Forrester
parent bed86f448f
commit d1666a89ff
7 changed files with 119 additions and 23 deletions

View file

@ -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

View file

@ -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"

View file

@ -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"

View file

@ -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' => <any module dependency you might have>
'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

View file

@ -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 ) {

View file

@ -408,24 +408,24 @@ class ResourceLoader implements LoggerAwareInterface {
. 'Edit your <code>LocalSettings.php</code> 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'];

View file

@ -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',
],
],
],
],
];
}