setMwGlobals( array( 'wgResourceLoaderLESSFunctions' => array( 'test-sum' => function ( $frame, $less ) { $sum = 0; foreach ( $frame[2] as $arg ) { $sum += (int)$arg[1]; } return $sum; }, ), 'wgResourceLoaderLESSImportPaths' => array( dirname( dirname( __DIR__ ) ) . '/data/less/common', ), 'wgResourceLoaderLESSVars' => array( 'foo' => '2px', 'Foo' => '#eeeeee', 'bar' => 5, ), ) ); } public static function provideValidModules() { return array( array( 'TEST.validModule1', new ResourceLoaderTestModule() ), ); } /** * Ensures that the ResourceLoaderRegisterModules hook is called when a new * ResourceLoader object is constructed. * @covers ResourceLoader::__construct */ public function testCreatingNewResourceLoaderCallsRegistrationHook() { $resourceLoaderRegisterModulesHook = false; $this->setMwGlobals( 'wgHooks', array( 'ResourceLoaderRegisterModules' => array( function ( &$resourceLoader ) use ( &$resourceLoaderRegisterModulesHook ) { $resourceLoaderRegisterModulesHook = true; } ) ) ); $resourceLoader = new ResourceLoader(); $this->assertTrue( $resourceLoaderRegisterModulesHook, 'Hook ResourceLoaderRegisterModules called' ); return $resourceLoader; } /** * @dataProvider provideValidModules * @depends testCreatingNewResourceLoaderCallsRegistrationHook * @covers ResourceLoader::register * @covers ResourceLoader::getModule */ public function testRegisteredValidModulesAreAccessible( $name, ResourceLoaderModule $module, ResourceLoader $resourceLoader ) { $resourceLoader->register( $name, $module ); $this->assertEquals( $module, $resourceLoader->getModule( $name ) ); } /** * @covers ResourceLoaderFileModule::compileLessFile */ public function testLessFileCompilation() { $context = $this->getResourceLoaderContext(); $basePath = __DIR__ . '/../../data/less/module'; $module = new ResourceLoaderFileModule( array( 'localBasePath' => $basePath, 'styles' => array( 'styles.less' ), ) ); $module->setName( 'test.less' ); $styles = $module->getStyles( $context ); $this->assertStringEqualsFile( $basePath . '/styles.css', $styles['all'] ); } /** * Strip @noflip annotations from CSS code. * @param string $css * @return string */ private static function stripNoflip( $css ) { return str_replace( '/*@noflip*/ ', '', $css ); } /** * @dataProvider providePackedModules * @covers ResourceLoader::makePackedModulesString */ public function testMakePackedModulesString( $desc, $modules, $packed ) { $this->assertEquals( $packed, ResourceLoader::makePackedModulesString( $modules ), $desc ); } /** * @dataProvider providePackedModules * @covers ResourceLoaderContext::expandModuleNames */ public function testexpandModuleNames( $desc, $modules, $packed ) { $this->assertEquals( $modules, ResourceLoaderContext::expandModuleNames( $packed ), $desc ); } public static function providePackedModules() { return array( array( 'Example from makePackedModulesString doc comment', array( 'foo.bar', 'foo.baz', 'bar.baz', 'bar.quux' ), 'foo.bar,baz|bar.baz,quux', ), array( 'Example from expandModuleNames doc comment', array( 'jquery.foo', 'jquery.bar', 'jquery.ui.baz', 'jquery.ui.quux' ), 'jquery.foo,bar|jquery.ui.baz,quux', ), array( 'Regression fixed in r88706 with dotless names', array( 'foo', 'bar', 'baz' ), 'foo,bar,baz', ), array( 'Prefixless modules after a prefixed module', array( 'single.module', 'foobar', 'foobaz' ), 'single.module|foobar,foobaz', ), ); } public static function provideAddSource() { return array( array( 'examplewiki', '//example.org/w/load.php', 'examplewiki' ), array( 'example2wiki', array( 'loadScript' => '//example.com/w/load.php' ), 'example2wiki' ), array( array( 'foowiki' => '//foo.org/w/load.php', 'bazwiki' => '//baz.org/w/load.php' ), null, array( 'foowiki', 'bazwiki' ) ), array( array( 'foowiki' => '//foo.org/w/load.php' ), null, false, ), ); } /** * @dataProvider provideAddSource * @covers ResourceLoader::addSource * @covers ResourceLoader::getSources */ public function testAddSource( $name, $info, $expected ) { $rl = new ResourceLoader; if ( $expected === false ) { $this->setExpectedException( 'MWException', 'ResourceLoader duplicate source addition error' ); $rl->addSource( $name, $info ); } $rl->addSource( $name, $info ); if ( is_array( $expected ) ) { foreach ( $expected as $source ) { $this->assertArrayHasKey( $source, $rl->getSources() ); } } else { $this->assertArrayHasKey( $expected, $rl->getSources() ); } } public static function fakeSources() { return array( 'examplewiki' => array( 'loadScript' => '//example.org/w/load.php', 'apiScript' => '//example.org/w/api.php', ), 'example2wiki' => array( 'loadScript' => '//example.com/w/load.php', 'apiScript' => '//example.com/w/api.php', ), ); } public static function provideLoaderImplement() { return array( array( array( 'title' => 'Implement scripts, styles and messages', 'name' => 'test.example', 'scripts' => 'mw.example();', 'styles' => array( 'css' => array( '.mw-example {}' ) ), 'messages' => array( 'example' => '' ), 'templates' => array(), 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) { mw.example(); }, { "css": [ ".mw-example {}" ] }, { "example": "" } );', ) ), array( array( 'title' => 'Implement scripts', 'name' => 'test.example', 'scripts' => 'mw.example();', 'styles' => array(), 'messages' => new XmlJsCode( '{}' ), 'templates' => array(), 'title' => 'scripts, styles and messags', 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) { mw.example(); } );', ) ), array( array( 'title' => 'Implement styles', 'name' => 'test.example', 'scripts' => array(), 'styles' => array( 'css' => array( '.mw-example {}' ) ), 'messages' => new XmlJsCode( '{}' ), 'templates' => array(), 'expected' => 'mw.loader.implement( "test.example", [], { "css": [ ".mw-example {}" ] } );', ) ), array( array( 'title' => 'Implement scripts and messages', 'name' => 'test.example', 'scripts' => 'mw.example();', 'styles' => array(), 'messages' => array( 'example' => '' ), 'templates' => array(), 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) { mw.example(); }, {}, { "example": "" } );', ) ), array( array( 'title' => 'Implement scripts and templates', 'name' => 'test.example', 'scripts' => 'mw.example();', 'styles' => array(), 'messages' => new XmlJsCode( '{}' ), 'templates' => array( 'example.html' => '' ), 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) { mw.example(); }, {}, {}, { "example.html": "" } );', ) ), ); } /** * @dataProvider provideLoaderImplement * @covers ResourceLoader::makeLoaderImplementScript */ public function testMakeLoaderImplementScript( $case ) { $this->assertEquals( $case['expected'], ResourceLoader::makeLoaderImplementScript( $case['name'], $case['scripts'], $case['styles'], $case['messages'], $case['templates'] ) ); } /** * @covers ResourceLoader::getLoadScript */ public function testGetLoadScript() { $this->setMwGlobals( 'wgResourceLoaderSources', array() ); $rl = new ResourceLoader(); $sources = self::fakeSources(); $rl->addSource( $sources ); foreach ( array( 'examplewiki', 'example2wiki' ) as $name ) { $this->assertEquals( $rl->getLoadScript( $name ), $sources[$name]['loadScript'] ); } try { $rl->getLoadScript( 'thiswasneverreigstered' ); $this->assertTrue( false, 'ResourceLoader::getLoadScript should have thrown an exception' ); } catch ( MWException $e ) { $this->assertTrue( true ); } } /** * @covers ResourceLoader::isModuleRegistered */ public function testIsModuleRegistered() { $rl = new ResourceLoader(); $rl->register( 'test.module', new ResourceLoaderTestModule() ); $this->assertTrue( $rl->isModuleRegistered( 'test.module' ) ); $this->assertFalse( $rl->isModuleRegistered( 'test.modulenotregistered' ) ); } }