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 // Regression test for T223402.
112 'msg' => 'Optimise the dependency tree (indirect circular dependency)',
114 'top' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'middle1', 'util' ] ] ),
115 'middle1' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'middle2', 'util' ] ] ),
116 'middle2' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'bottom' ] ] ),
117 'bottom' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'top' ] ] ),
118 'util' => new ResourceLoaderTestModule( [ 'dependencies' => [] ] ),
121 mw.loader.addSource( {
122 "local": "/w/load.php"
124 mw.loader.register( [
162 // Regression test for T223402.
163 'msg' => 'Optimise the dependency tree (direct circular dependency)',
165 'top' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'util', 'top' ] ] ),
166 'util' => new ResourceLoaderTestModule( [ 'dependencies' => [] ] ),
169 mw.loader.addSource( {
170 "local": "/w/load.php"
172 mw.loader.register( [
188 'msg' => 'Omit raw modules from registry',
190 'test.raw' => new ResourceLoaderTestModule( [ 'isRaw' => true ] ),
191 'test.blank' => new ResourceLoaderTestModule(),
194 mw.loader.addSource( {
195 "local": "/w/load.php"
197 mw.loader.register( [
205 'msg' => 'Version falls back gracefully if getVersionHash throws',
208 ( $mock = $this->getMockBuilder( ResourceLoaderTestModule
::class )
209 ->setMethods( [ 'getVersionHash' ] )->getMock() )
210 && $mock->method( 'getVersionHash' )->will(
211 $this->throwException( new Exception
)
216 mw.loader.addSource( {
217 "local": "/w/load.php"
219 mw.loader.register( [
230 'msg' => 'Use version from getVersionHash',
233 ( $mock = $this->getMockBuilder( ResourceLoaderTestModule
::class )
234 ->setMethods( [ 'getVersionHash' ] )->getMock() )
235 && $mock->method( 'getVersionHash' )->willReturn( '1234567' )
239 mw.loader.addSource( {
240 "local": "/w/load.php"
242 mw.loader.register( [
250 'msg' => 'Re-hash version from getVersionHash if too long',
253 ( $mock = $this->getMockBuilder( ResourceLoaderTestModule
::class )
254 ->setMethods( [ 'getVersionHash' ] )->getMock() )
255 && $mock->method( 'getVersionHash' )->willReturn( '12345678' )
259 mw.loader.addSource( {
260 "local": "/w/load.php"
262 mw.loader.register( [
270 'msg' => 'Group signature',
272 'test.blank' => new ResourceLoaderTestModule(),
273 'test.group.foo' => new ResourceLoaderTestModule( [ 'group' => 'x-foo' ] ),
274 'test.group.bar' => new ResourceLoaderTestModule( [ 'group' => 'x-bar' ] ),
277 mw.loader.addSource( {
278 "local": "/w/load.php"
280 mw.loader.register( [
300 'msg' => 'Different target (non-test should not be registered)',
302 'test.blank' => new ResourceLoaderTestModule(),
303 'test.target.foo' => new ResourceLoaderTestModule( [ 'targets' => [ 'x-foo' ] ] ),
306 mw.loader.addSource( {
307 "local": "/w/load.php"
309 mw.loader.register( [
317 'msg' => 'Safemode disabled (default; register all modules)',
319 // Default origin: ORIGIN_CORE_SITEWIDE
320 'test.blank' => new ResourceLoaderTestModule(),
321 'test.core-generated' => new ResourceLoaderTestModule( [
322 'origin' => ResourceLoaderModule
::ORIGIN_CORE_INDIVIDUAL
324 'test.sitewide' => new ResourceLoaderTestModule( [
325 'origin' => ResourceLoaderModule
::ORIGIN_USER_SITEWIDE
327 'test.user' => new ResourceLoaderTestModule( [
328 'origin' => ResourceLoaderModule
::ORIGIN_USER_INDIVIDUAL
332 mw.loader.addSource( {
333 "local": "/w/load.php"
335 mw.loader.register( [
341 "test.core-generated",
355 'msg' => 'Safemode enabled (filter modules with user/site origin)',
356 'extraQuery' => [ 'safemode' => '1' ],
358 // Default origin: ORIGIN_CORE_SITEWIDE
359 'test.blank' => new ResourceLoaderTestModule(),
360 'test.core-generated' => new ResourceLoaderTestModule( [
361 'origin' => ResourceLoaderModule
::ORIGIN_CORE_INDIVIDUAL
363 'test.sitewide' => new ResourceLoaderTestModule( [
364 'origin' => ResourceLoaderModule
::ORIGIN_USER_SITEWIDE
366 'test.user' => new ResourceLoaderTestModule( [
367 'origin' => ResourceLoaderModule
::ORIGIN_USER_INDIVIDUAL
371 mw.loader.addSource( {
372 "local": "/w/load.php"
374 mw.loader.register( [
380 "test.core-generated",
386 'msg' => 'Foreign source',
389 'loadScript' => 'http://example.org/w/load.php',
390 'apiScript' => 'http://example.org/w/api.php',
394 'test.blank' => new ResourceLoaderTestModule( [ 'source' => 'example' ] ),
397 mw.loader.addSource( {
398 "local": "/w/load.php",
399 "example": "http://example.org/w/load.php"
401 mw.loader.register( [
412 'msg' => 'Conditional dependency function',
414 'test.x.core' => new ResourceLoaderTestModule(),
415 'test.x.polyfill' => new ResourceLoaderTestModule( [
416 'skipFunction' => 'return true;'
418 'test.y.polyfill' => new ResourceLoaderTestModule( [
426 'test.z.foo' => new ResourceLoaderTestModule( [
435 mw.loader.addSource( {
436 "local": "/w/load.php"
438 mw.loader.register( [
457 "return !!( window.JSON \u0026\u0026 JSON.parse \u0026\u0026 JSON.stringify);"
471 // This may seem like an edge case, but a plain MediaWiki core install
472 // with a few extensions installed is likely far more complex than this
473 // even, not to mention an install like Wikipedia.
474 // TODO: Make this even more realistic.
475 'msg' => 'Advanced (everything combined)',
478 'loadScript' => 'http://example.org/w/load.php',
479 'apiScript' => 'http://example.org/w/api.php',
483 'test.blank' => new ResourceLoaderTestModule(),
484 'test.x.core' => new ResourceLoaderTestModule(),
485 'test.x.util' => new ResourceLoaderTestModule( [
490 'test.x.foo' => new ResourceLoaderTestModule( [
495 'test.x.bar' => new ResourceLoaderTestModule( [
501 'test.x.quux' => new ResourceLoaderTestModule( [
509 'test.group.foo.1' => new ResourceLoaderTestModule( [
512 'test.group.foo.2' => new ResourceLoaderTestModule( [
515 'test.group.bar.1' => new ResourceLoaderTestModule( [
518 'test.group.bar.2' => new ResourceLoaderTestModule( [
520 'source' => 'example',
522 'test.target.foo' => new ResourceLoaderTestModule( [
523 'targets' => [ 'x-foo' ],
525 'test.target.bar' => new ResourceLoaderTestModule( [
526 'source' => 'example',
527 'targets' => [ 'x-foo' ],
531 mw.loader.addSource( {
532 "local": "/w/load.php",
533 "example": "http://example.org/w/load.php"
535 mw.loader.register( [
605 * @dataProvider provideGetModuleRegistrations
606 * @covers ResourceLoaderStartUpModule
607 * @covers ResourceLoader::makeLoaderRegisterScript
609 public function testGetModuleRegistrations( $case ) {
610 $extraQuery = $case['extraQuery'] ??
[];
611 $context = $this->getResourceLoaderContext( $extraQuery );
612 $rl = $context->getResourceLoader();
613 if ( isset( $case['sources'] ) ) {
614 $rl->addSource( $case['sources'] );
616 $rl->register( $case['modules'] );
617 $module = new ResourceLoaderStartUpModule();
618 $out = ltrim( $case['out'], "\n" );
620 // Disable log from getModuleRegistrations via MWExceptionHandler
621 // for case where getVersionHash() is expected to throw.
622 $this->setLogger( 'exception', new Psr\Log\
NullLogger() );
625 self
::expandPlaceholders( $out ),
626 $module->getModuleRegistrations( $context ),
631 public static function provideRegistrations() {
634 'test.blank' => new ResourceLoaderTestModule(),
635 'test.min' => new ResourceLoaderTestModule( [
651 * @covers ResourceLoaderStartUpModule::getModuleRegistrations
652 * @dataProvider provideRegistrations
654 public function testRegistrationsMinified( $modules ) {
655 $this->setMwGlobals( 'wgResourceLoaderDebug', false );
657 $context = $this->getResourceLoaderContext();
658 $rl = $context->getResourceLoader();
659 $rl->register( $modules );
660 $module = new ResourceLoaderStartUpModule();
661 $out = 'mw.loader.addSource({"local":"/w/load.php"});' . "\n"
662 . 'mw.loader.register(['
663 . '["test.blank","{blankVer}"],'
664 . '["test.min","{blankVer}",[0],null,null,'
665 . '"return!!(window.JSON\u0026\u0026JSON.parse\u0026\u0026JSON.stringify);"'
669 self
::expandPlaceholders( $out ),
670 $module->getModuleRegistrations( $context ),
676 * @covers ResourceLoaderStartUpModule::getModuleRegistrations
677 * @dataProvider provideRegistrations
679 public function testRegistrationsUnminified( $modules ) {
680 $context = $this->getResourceLoaderContext();
681 $rl = $context->getResourceLoader();
682 $rl->register( $modules );
683 $module = new ResourceLoaderStartUpModule();
685 'mw.loader.addSource( {
686 "local": "/w/load.php"
688 mw.loader.register( [
701 "return !!( window.JSON \u0026\u0026 JSON.parse \u0026\u0026 JSON.stringify);"
706 self
::expandPlaceholders( $out ),
707 $module->getModuleRegistrations( $context ),
713 * @covers ResourceLoaderStartupModule::getDefinitionSummary
715 public function testGetVersionHash_varyConfig() {
716 $context = $this->getResourceLoaderContext();
718 $this->setMwGlobals( 'wgArticlePath', '/w1' );
719 $module = new ResourceLoaderStartupModule();
720 $version1 = $module->getVersionHash( $context );
721 $module = new ResourceLoaderStartupModule();
722 $version2 = $module->getVersionHash( $context );
724 $this->setMwGlobals( 'wgArticlePath', '/w3' );
725 $module = new ResourceLoaderStartupModule();
726 $version3 = $module->getVersionHash( $context );
731 'Deterministic version hash'
734 $this->assertNotEquals(
737 'Config change impacts version hash'
742 * @covers ResourceLoaderStartupModule
744 public function testGetVersionHash_varyModule() {
745 $context1 = $this->getResourceLoaderContext();
746 $rl1 = $context1->getResourceLoader();
748 'test.a' => new ResourceLoaderTestModule(),
749 'test.b' => new ResourceLoaderTestModule(),
751 $module = new ResourceLoaderStartupModule();
752 $version1 = $module->getVersionHash( $context1 );
754 $context2 = $this->getResourceLoaderContext();
755 $rl2 = $context2->getResourceLoader();
757 'test.b' => new ResourceLoaderTestModule(),
758 'test.c' => new ResourceLoaderTestModule(),
760 $module = new ResourceLoaderStartupModule();
761 $version2 = $module->getVersionHash( $context2 );
763 $context3 = $this->getResourceLoaderContext();
764 $rl3 = $context3->getResourceLoader();
766 'test.a' => new ResourceLoaderTestModule(),
767 'test.b' => new ResourceLoaderTestModule( [ 'script' => 'different' ] ),
769 $module = new ResourceLoaderStartupModule();
770 $version3 = $module->getVersionHash( $context3 );
772 // Module name *is* significant (T201686)
773 $this->assertNotEquals(
776 'Module name is significant'
779 $this->assertNotEquals(
782 'Hash change of any module impacts startup hash'
787 * @covers ResourceLoaderStartupModule
789 public function testGetVersionHash_varyDeps() {
790 $context = $this->getResourceLoaderContext();
791 $rl = $context->getResourceLoader();
793 'test.a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'x', 'y' ] ] ),
795 $module = new ResourceLoaderStartupModule();
796 $version1 = $module->getVersionHash( $context );
798 $context = $this->getResourceLoaderContext();
799 $rl = $context->getResourceLoader();
801 'test.a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'x', 'z' ] ] ),
803 $module = new ResourceLoaderStartupModule();
804 $version2 = $module->getVersionHash( $context );
806 // Dependencies *are* significant (T201686)
807 $this->assertNotEquals(
810 'Dependencies are significant'