3 class ResourceLoaderStartUpModuleTest
extends ResourceLoaderTestCase
{
5 protected static function expandPlaceholders( $text ) {
7 '{blankVer}' => self
::BLANK_VERSION
11 public function provideGetModuleRegistrations() {
14 'msg' => 'Empty registry',
17 mw.loader.addSource( {
18 "local": "/w/load.php"
20 mw.loader.register( [] );'
23 'msg' => 'Basic registry',
25 'test.blank' => new ResourceLoaderTestModule(),
28 mw.loader.addSource( {
29 "local": "/w/load.php"
39 'msg' => 'Optimise the dependency tree (basic case)',
41 'a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'b', 'c', 'd' ] ] ),
42 'b' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'c' ] ] ),
43 'c' => new ResourceLoaderTestModule( [ 'dependencies' => [] ] ),
44 'd' => new ResourceLoaderTestModule( [ 'dependencies' => [] ] ),
47 mw.loader.addSource( {
48 "local": "/w/load.php"
77 'msg' => 'Optimise the dependency tree (tolerate unknown deps)',
79 'a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'b', 'c', 'x' ] ] ),
80 'b' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'c', 'x' ] ] ),
81 'c' => new ResourceLoaderTestModule( [ 'dependencies' => [] ] ),
84 mw.loader.addSource( {
85 "local": "/w/load.php"
111 'msg' => 'Omit raw modules from registry',
113 'test.raw' => new ResourceLoaderTestModule( [ 'isRaw' => true ] ),
114 'test.blank' => new ResourceLoaderTestModule(),
117 mw.loader.addSource( {
118 "local": "/w/load.php"
120 mw.loader.register( [
128 'msg' => 'Version falls back gracefully if getVersionHash throws',
131 ( $mock = $this->getMockBuilder( ResourceLoaderTestModule
::class )
132 ->setMethods( [ 'getVersionHash' ] )->getMock() )
133 && $mock->method( 'getVersionHash' )->will(
134 $this->throwException( new Exception
)
139 mw.loader.addSource( {
140 "local": "/w/load.php"
142 mw.loader.register( [
153 'msg' => 'Use version from getVersionHash',
156 ( $mock = $this->getMockBuilder( ResourceLoaderTestModule
::class )
157 ->setMethods( [ 'getVersionHash' ] )->getMock() )
158 && $mock->method( 'getVersionHash' )->willReturn( '1234567' )
162 mw.loader.addSource( {
163 "local": "/w/load.php"
165 mw.loader.register( [
173 'msg' => 'Re-hash version from getVersionHash if too long',
176 ( $mock = $this->getMockBuilder( ResourceLoaderTestModule
::class )
177 ->setMethods( [ 'getVersionHash' ] )->getMock() )
178 && $mock->method( 'getVersionHash' )->willReturn( '12345678' )
182 mw.loader.addSource( {
183 "local": "/w/load.php"
185 mw.loader.register( [
193 'msg' => 'Group signature',
195 'test.blank' => new ResourceLoaderTestModule(),
196 'test.group.foo' => new ResourceLoaderTestModule( [ 'group' => 'x-foo' ] ),
197 'test.group.bar' => new ResourceLoaderTestModule( [ 'group' => 'x-bar' ] ),
200 mw.loader.addSource( {
201 "local": "/w/load.php"
203 mw.loader.register( [
223 'msg' => 'Different target (non-test should not be registered)',
225 'test.blank' => new ResourceLoaderTestModule(),
226 'test.target.foo' => new ResourceLoaderTestModule( [ 'targets' => [ 'x-foo' ] ] ),
229 mw.loader.addSource( {
230 "local": "/w/load.php"
232 mw.loader.register( [
240 'msg' => 'Safemode disabled (default; register all modules)',
242 // Default origin: ORIGIN_CORE_SITEWIDE
243 'test.blank' => new ResourceLoaderTestModule(),
244 'test.core-generated' => new ResourceLoaderTestModule( [
245 'origin' => ResourceLoaderModule
::ORIGIN_CORE_INDIVIDUAL
247 'test.sitewide' => new ResourceLoaderTestModule( [
248 'origin' => ResourceLoaderModule
::ORIGIN_USER_SITEWIDE
250 'test.user' => new ResourceLoaderTestModule( [
251 'origin' => ResourceLoaderModule
::ORIGIN_USER_INDIVIDUAL
255 mw.loader.addSource( {
256 "local": "/w/load.php"
258 mw.loader.register( [
264 "test.core-generated",
278 'msg' => 'Safemode enabled (filter modules with user/site origin)',
279 'extraQuery' => [ 'safemode' => '1' ],
281 // Default origin: ORIGIN_CORE_SITEWIDE
282 'test.blank' => new ResourceLoaderTestModule(),
283 'test.core-generated' => new ResourceLoaderTestModule( [
284 'origin' => ResourceLoaderModule
::ORIGIN_CORE_INDIVIDUAL
286 'test.sitewide' => new ResourceLoaderTestModule( [
287 'origin' => ResourceLoaderModule
::ORIGIN_USER_SITEWIDE
289 'test.user' => new ResourceLoaderTestModule( [
290 'origin' => ResourceLoaderModule
::ORIGIN_USER_INDIVIDUAL
294 mw.loader.addSource( {
295 "local": "/w/load.php"
297 mw.loader.register( [
303 "test.core-generated",
309 'msg' => 'Foreign source',
312 'loadScript' => 'http://example.org/w/load.php',
313 'apiScript' => 'http://example.org/w/api.php',
317 'test.blank' => new ResourceLoaderTestModule( [ 'source' => 'example' ] ),
320 mw.loader.addSource( {
321 "local": "/w/load.php",
322 "example": "http://example.org/w/load.php"
324 mw.loader.register( [
335 'msg' => 'Conditional dependency function',
337 'test.x.core' => new ResourceLoaderTestModule(),
338 'test.x.polyfill' => new ResourceLoaderTestModule( [
339 'skipFunction' => 'return true;'
341 'test.y.polyfill' => new ResourceLoaderTestModule( [
349 'test.z.foo' => new ResourceLoaderTestModule( [
358 mw.loader.addSource( {
359 "local": "/w/load.php"
361 mw.loader.register( [
380 "return !!( window.JSON \u0026\u0026 JSON.parse \u0026\u0026 JSON.stringify);"
394 // This may seem like an edge case, but a plain MediaWiki core install
395 // with a few extensions installed is likely far more complex than this
396 // even, not to mention an install like Wikipedia.
397 // TODO: Make this even more realistic.
398 'msg' => 'Advanced (everything combined)',
401 'loadScript' => 'http://example.org/w/load.php',
402 'apiScript' => 'http://example.org/w/api.php',
406 'test.blank' => new ResourceLoaderTestModule(),
407 'test.x.core' => new ResourceLoaderTestModule(),
408 'test.x.util' => new ResourceLoaderTestModule( [
413 'test.x.foo' => new ResourceLoaderTestModule( [
418 'test.x.bar' => new ResourceLoaderTestModule( [
424 'test.x.quux' => new ResourceLoaderTestModule( [
432 'test.group.foo.1' => new ResourceLoaderTestModule( [
435 'test.group.foo.2' => new ResourceLoaderTestModule( [
438 'test.group.bar.1' => new ResourceLoaderTestModule( [
441 'test.group.bar.2' => new ResourceLoaderTestModule( [
443 'source' => 'example',
445 'test.target.foo' => new ResourceLoaderTestModule( [
446 'targets' => [ 'x-foo' ],
448 'test.target.bar' => new ResourceLoaderTestModule( [
449 'source' => 'example',
450 'targets' => [ 'x-foo' ],
454 mw.loader.addSource( {
455 "local": "/w/load.php",
456 "example": "http://example.org/w/load.php"
458 mw.loader.register( [
528 * @dataProvider provideGetModuleRegistrations
529 * @covers ResourceLoaderStartUpModule
530 * @covers ResourceLoader::makeLoaderRegisterScript
532 public function testGetModuleRegistrations( $case ) {
533 $extraQuery = $case['extraQuery'] ??
[];
534 $context = $this->getResourceLoaderContext( $extraQuery );
535 $rl = $context->getResourceLoader();
536 if ( isset( $case['sources'] ) ) {
537 $rl->addSource( $case['sources'] );
539 $rl->register( $case['modules'] );
540 $module = new ResourceLoaderStartUpModule();
541 $out = ltrim( $case['out'], "\n" );
543 // Disable log from getModuleRegistrations via MWExceptionHandler
544 // for case where getVersionHash() is expected to throw.
545 $this->setLogger( 'exception', new Psr\Log\
NullLogger() );
548 self
::expandPlaceholders( $out ),
549 $module->getModuleRegistrations( $context ),
554 public static function provideRegistrations() {
557 'test.blank' => new ResourceLoaderTestModule(),
558 'test.min' => new ResourceLoaderTestModule( [
574 * @covers ResourceLoaderStartUpModule::getModuleRegistrations
575 * @dataProvider provideRegistrations
577 public function testRegistrationsMinified( $modules ) {
578 $this->setMwGlobals( 'wgResourceLoaderDebug', false );
580 $context = $this->getResourceLoaderContext();
581 $rl = $context->getResourceLoader();
582 $rl->register( $modules );
583 $module = new ResourceLoaderStartUpModule();
584 $out = 'mw.loader.addSource({"local":"/w/load.php"});' . "\n"
585 . 'mw.loader.register(['
586 . '["test.blank","{blankVer}"],'
587 . '["test.min","{blankVer}",[0],null,null,'
588 . '"return!!(window.JSON\u0026\u0026JSON.parse\u0026\u0026JSON.stringify);"'
592 self
::expandPlaceholders( $out ),
593 $module->getModuleRegistrations( $context ),
599 * @covers ResourceLoaderStartUpModule::getModuleRegistrations
600 * @dataProvider provideRegistrations
602 public function testRegistrationsUnminified( $modules ) {
603 $context = $this->getResourceLoaderContext();
604 $rl = $context->getResourceLoader();
605 $rl->register( $modules );
606 $module = new ResourceLoaderStartUpModule();
608 'mw.loader.addSource( {
609 "local": "/w/load.php"
611 mw.loader.register( [
624 "return !!( window.JSON \u0026\u0026 JSON.parse \u0026\u0026 JSON.stringify);"
629 self
::expandPlaceholders( $out ),
630 $module->getModuleRegistrations( $context ),
636 * @covers ResourceLoaderStartupModule::getDefinitionSummary
638 public function testGetVersionHash_varyConfig() {
639 $context = $this->getResourceLoaderContext();
641 $this->setMwGlobals( 'wgArticlePath', '/w1' );
642 $module = new ResourceLoaderStartupModule();
643 $version1 = $module->getVersionHash( $context );
644 $module = new ResourceLoaderStartupModule();
645 $version2 = $module->getVersionHash( $context );
647 $this->setMwGlobals( 'wgArticlePath', '/w3' );
648 $module = new ResourceLoaderStartupModule();
649 $version3 = $module->getVersionHash( $context );
654 'Deterministic version hash'
657 $this->assertNotEquals(
660 'Config change impacts version hash'
665 * @covers ResourceLoaderStartupModule
667 public function testGetVersionHash_varyModule() {
668 $context1 = $this->getResourceLoaderContext();
669 $rl1 = $context1->getResourceLoader();
671 'test.a' => new ResourceLoaderTestModule(),
672 'test.b' => new ResourceLoaderTestModule(),
674 $module = new ResourceLoaderStartupModule();
675 $version1 = $module->getVersionHash( $context1 );
677 $context2 = $this->getResourceLoaderContext();
678 $rl2 = $context2->getResourceLoader();
680 'test.b' => new ResourceLoaderTestModule(),
681 'test.c' => new ResourceLoaderTestModule(),
683 $module = new ResourceLoaderStartupModule();
684 $version2 = $module->getVersionHash( $context2 );
686 $context3 = $this->getResourceLoaderContext();
687 $rl3 = $context3->getResourceLoader();
689 'test.a' => new ResourceLoaderTestModule(),
690 'test.b' => new ResourceLoaderTestModule( [ 'script' => 'different' ] ),
692 $module = new ResourceLoaderStartupModule();
693 $version3 = $module->getVersionHash( $context3 );
695 // Module name *is* significant (T201686)
696 $this->assertNotEquals(
699 'Module name is significant'
702 $this->assertNotEquals(
705 'Hash change of any module impacts startup hash'
710 * @covers ResourceLoaderStartupModule
712 public function testGetVersionHash_varyDeps() {
713 $context = $this->getResourceLoaderContext();
714 $rl = $context->getResourceLoader();
716 'test.a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'x', 'y' ] ] ),
718 $module = new ResourceLoaderStartupModule();
719 $version1 = $module->getVersionHash( $context );
721 $context = $this->getResourceLoaderContext();
722 $rl = $context->getResourceLoader();
724 'test.a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'x', 'z' ] ] ),
726 $module = new ResourceLoaderStartupModule();
727 $version2 = $module->getVersionHash( $context );
729 // Dependencies *are* significant (T201686)
730 $this->assertNotEquals(
733 'Dependencies are significant'