3 class ResourceLoaderTest
extends ResourceLoaderTestCase
{
5 protected function setUp() {
9 'wgResourceLoaderLESSImportPaths' => [
10 dirname( dirname( __DIR__
) ) . '/data/less/common',
12 'wgResourceLoaderLESSVars' => [
21 * Ensure the ResourceLoaderRegisterModules hook is called.
23 * @covers ResourceLoader::__construct
25 public function testConstructRegistrationHook() {
26 $resourceLoaderRegisterModulesHook = false;
28 $this->setMwGlobals( 'wgHooks', [
29 'ResourceLoaderRegisterModules' => [
30 function ( &$resourceLoader ) use ( &$resourceLoaderRegisterModulesHook ) {
31 $resourceLoaderRegisterModulesHook = true;
36 $unused = new ResourceLoader();
38 $resourceLoaderRegisterModulesHook,
39 'Hook ResourceLoaderRegisterModules called'
44 * @covers ResourceLoader::register
45 * @covers ResourceLoader::getModule
47 public function testRegisterValid() {
48 $module = new ResourceLoaderTestModule();
49 $resourceLoader = new EmptyResourceLoader();
50 $resourceLoader->register( 'test', $module );
51 $this->assertEquals( $module, $resourceLoader->getModule( 'test' ) );
55 * @covers ResourceLoader::register
57 public function testRegisterInvalidName() {
58 $resourceLoader = new EmptyResourceLoader();
59 $this->setExpectedException( 'MWException', "name 'test!invalid' is invalid" );
60 $resourceLoader->register( 'test!invalid', new ResourceLoaderTestModule() );
64 * @covers ResourceLoader::register
66 public function testRegisterInvalidType() {
67 $resourceLoader = new EmptyResourceLoader();
68 $this->setExpectedException( 'MWException', 'ResourceLoader module info type error' );
69 $resourceLoader->register( 'test', new stdClass() );
73 * @covers ResourceLoader::getModuleNames
75 public function testGetModuleNames() {
76 // Use an empty one so that core and extension modules don't get in.
77 $resourceLoader = new EmptyResourceLoader();
78 $resourceLoader->register( 'test.foo', new ResourceLoaderTestModule() );
79 $resourceLoader->register( 'test.bar', new ResourceLoaderTestModule() );
81 [ 'test.foo', 'test.bar' ],
82 $resourceLoader->getModuleNames()
87 * @covers ResourceLoader::isModuleRegistered
89 public function testIsModuleRegistered() {
90 $rl = new EmptyResourceLoader();
91 $rl->register( 'test', new ResourceLoaderTestModule() );
92 $this->assertTrue( $rl->isModuleRegistered( 'test' ) );
93 $this->assertFalse( $rl->isModuleRegistered( 'test.unknown' ) );
97 * @covers ResourceLoader::getModule
99 public function testGetModuleUnknown() {
100 $rl = new EmptyResourceLoader();
101 $this->assertSame( null, $rl->getModule( 'test' ) );
105 * @covers ResourceLoader::getModule
107 public function testGetModuleClass() {
108 $rl = new EmptyResourceLoader();
109 $rl->register( 'test', [ 'class' => ResourceLoaderTestModule
::class ] );
110 $this->assertInstanceOf(
111 ResourceLoaderTestModule
::class,
112 $rl->getModule( 'test' )
117 * @covers ResourceLoader::getModule
119 public function testGetModuleClassDefault() {
120 $rl = new EmptyResourceLoader();
121 $rl->register( 'test', [] );
122 $this->assertInstanceOf(
123 ResourceLoaderFileModule
::class,
124 $rl->getModule( 'test' ),
125 'Array-style module registrations default to FileModule'
130 * @covers ResourceLoaderFileModule::compileLessFile
132 public function testLessFileCompilation() {
133 $context = $this->getResourceLoaderContext();
134 $basePath = __DIR__
. '/../../data/less/module';
135 $module = new ResourceLoaderFileModule( [
136 'localBasePath' => $basePath,
137 'styles' => [ 'styles.less' ],
139 $module->setName( 'test.less' );
140 $styles = $module->getStyles( $context );
141 $this->assertStringEqualsFile( $basePath . '/styles.css', $styles['all'] );
144 public static function providePackedModules() {
147 'Example from makePackedModulesString doc comment',
148 [ 'foo.bar', 'foo.baz', 'bar.baz', 'bar.quux' ],
149 'foo.bar,baz|bar.baz,quux',
152 'Example from expandModuleNames doc comment',
153 [ 'jquery.foo', 'jquery.bar', 'jquery.ui.baz', 'jquery.ui.quux' ],
154 'jquery.foo,bar|jquery.ui.baz,quux',
157 'Regression fixed in r88706 with dotless names',
158 [ 'foo', 'bar', 'baz' ],
162 'Prefixless modules after a prefixed module',
163 [ 'single.module', 'foobar', 'foobaz' ],
164 'single.module|foobar,foobaz',
168 [ 'foo', 'foo.baz', 'baz.quux', 'foo.bar' ],
169 'foo|foo.baz,bar|baz.quux',
170 [ 'foo', 'foo.baz', 'foo.bar', 'baz.quux' ],
176 * @dataProvider providePackedModules
177 * @covers ResourceLoader::makePackedModulesString
179 public function testMakePackedModulesString( $desc, $modules, $packed ) {
180 $this->assertEquals( $packed, ResourceLoader
::makePackedModulesString( $modules ), $desc );
184 * @dataProvider providePackedModules
185 * @covers ResourceLoaderContext::expandModuleNames
187 public function testExpandModuleNames( $desc, $modules, $packed, $unpacked = null ) {
189 $unpacked ?
: $modules,
190 ResourceLoaderContext
::expandModuleNames( $packed ),
195 public static function provideAddSource() {
197 [ 'foowiki', 'https://example.org/w/load.php', 'foowiki' ],
198 [ 'foowiki', [ 'loadScript' => 'https://example.org/w/load.php' ], 'foowiki' ],
201 'foowiki' => 'https://example.org/w/load.php',
202 'bazwiki' => 'https://example.com/w/load.php',
205 [ 'foowiki', 'bazwiki' ]
211 * @dataProvider provideAddSource
212 * @covers ResourceLoader::addSource
213 * @covers ResourceLoader::getSources
215 public function testAddSource( $name, $info, $expected ) {
216 $rl = new ResourceLoader
;
217 $rl->addSource( $name, $info );
218 if ( is_array( $expected ) ) {
219 foreach ( $expected as $source ) {
220 $this->assertArrayHasKey( $source, $rl->getSources() );
223 $this->assertArrayHasKey( $expected, $rl->getSources() );
228 * @covers ResourceLoader::addSource
230 public function testAddSourceDupe() {
231 $rl = new ResourceLoader
;
232 $this->setExpectedException( 'MWException', 'ResourceLoader duplicate source addition error' );
233 $rl->addSource( 'foo', 'https://example.org/w/load.php' );
234 $rl->addSource( 'foo', 'https://example.com/w/load.php' );
238 * @covers ResourceLoader::addSource
240 public function testAddSourceInvalid() {
241 $rl = new ResourceLoader
;
242 $this->setExpectedException( 'MWException', 'with no "loadScript" key' );
243 $rl->addSource( 'foo', [ 'x' => 'https://example.org/w/load.php' ] );
246 public static function provideLoaderImplement() {
249 'title' => 'Implement scripts, styles and messages',
251 'name' => 'test.example',
252 'scripts' => 'mw.example();',
253 'styles' => [ 'css' => [ '.mw-example {}' ] ],
254 'messages' => [ 'example' => '' ],
257 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery, require, module ) {
268 'title' => 'Implement scripts',
270 'name' => 'test.example',
271 'scripts' => 'mw.example();',
274 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery, require, module ) {
279 'title' => 'Implement styles',
281 'name' => 'test.example',
283 'styles' => [ 'css' => [ '.mw-example {}' ] ],
284 'messages' => new XmlJsCode( '{}' ),
286 'expected' => 'mw.loader.implement( "test.example", [], {
293 'title' => 'Implement scripts and messages',
295 'name' => 'test.example',
296 'scripts' => 'mw.example();',
297 'messages' => [ 'example' => '' ],
299 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery, require, module ) {
306 'title' => 'Implement scripts and templates',
308 'name' => 'test.example',
309 'scripts' => 'mw.example();',
310 'templates' => [ 'example.html' => '' ],
312 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery, require, module ) {
319 'title' => 'Implement unwrapped user script',
322 'scripts' => 'mw.example( 1 );',
324 'expected' => 'mw.loader.implement( "user", "mw.example( 1 );" );',
327 'title' => 'Implement unwrapped user script',
331 'scripts' => 'mw.example( 1 );',
333 'expected' => 'mw.loader.implement("user","mw.example(1);");',
339 * @dataProvider provideLoaderImplement
340 * @covers ResourceLoader::makeLoaderImplementScript
341 * @covers ResourceLoader::trimArray
343 public function testMakeLoaderImplementScript( $case ) {
345 'styles' => [], 'templates' => [], 'messages' => new XmlJsCode( '{}' ),
348 ResourceLoader
::clearCache();
349 $this->setMwGlobals( 'wgResourceLoaderDebug', $case['debug'] );
353 ResourceLoader
::makeLoaderImplementScript(
364 * @covers ResourceLoader::makeLoaderImplementScript
366 public function testMakeLoaderImplementScriptInvalid() {
367 $this->setExpectedException( 'MWException', 'Invalid scripts error' );
368 ResourceLoader
::makeLoaderImplementScript(
378 * @covers ResourceLoader::makeLoaderSourcesScript
380 public function testMakeLoaderSourcesScript() {
382 'mw.loader.addSource( "local", "/w/load.php" );',
383 ResourceLoader
::makeLoaderSourcesScript( 'local', '/w/load.php' )
386 'mw.loader.addSource( {
387 "local": "/w/load.php"
389 ResourceLoader
::makeLoaderSourcesScript( [ 'local' => '/w/load.php' ] )
392 'mw.loader.addSource( {
393 "local": "/w/load.php",
394 "example": "https://example.org/w/load.php"
396 ResourceLoader
::makeLoaderSourcesScript( [
397 'local' => '/w/load.php',
398 'example' => 'https://example.org/w/load.php'
402 'mw.loader.addSource( [] );',
403 ResourceLoader
::makeLoaderSourcesScript( [] )
407 private static function fakeSources() {
410 'loadScript' => '//example.org/w/load.php',
411 'apiScript' => '//example.org/w/api.php',
414 'loadScript' => '//example.com/w/load.php',
415 'apiScript' => '//example.com/w/api.php',
421 * @covers ResourceLoader::getLoadScript
423 public function testGetLoadScript() {
424 $this->setMwGlobals( 'wgResourceLoaderSources', [] );
425 $rl = new ResourceLoader();
426 $sources = self
::fakeSources();
427 $rl->addSource( $sources );
428 foreach ( [ 'examplewiki', 'example2wiki' ] as $name ) {
429 $this->assertEquals( $rl->getLoadScript( $name ), $sources[$name]['loadScript'] );
433 $rl->getLoadScript( 'thiswasneverreigstered' );
434 $this->assertTrue( false, 'ResourceLoader::getLoadScript should have thrown an exception' );
435 } catch ( MWException
$e ) {
436 $this->assertTrue( true );