parent::setUp();
$this->setMwGlobals( [
- 'wgResourceLoaderLESSImportPaths' => [],
- 'wgResourceLoaderLESSVars' => [
- 'foo' => '2px',
- 'Foo' => '#eeeeee',
- 'bar' => 5,
- ],
- // Clear ResourceLoaderGetConfigVars hooks (called by StartupModule)
- // to avoid notices during testMakeModuleResponse for missing
- // wgResourceLoaderLESSVars keys in extension hooks.
- 'wgHooks' => [],
'wgShowExceptionDetails' => true,
] );
}
);
}
- /**
- * @covers ResourceLoaderFileModule::compileLessFile
- */
- public function testLessFileCompilation() {
- $context = $this->getResourceLoaderContext();
- $basePath = __DIR__ . '/../../data/less/module';
- $module = new ResourceLoaderFileModule( [
- 'localBasePath' => $basePath,
- 'styles' => [ 'styles.less' ],
- ] );
- $module->setName( 'test.less' );
- $styles = $module->getStyles( $context );
- $this->assertStringEqualsFile( $basePath . '/styles.css', $styles['all'] );
- }
-
/**
* @covers ResourceLoader::getLessCompiler
*/
public function testLessImportDirs() {
$rl = new EmptyResourceLoader();
- $lc = $rl->getLessCompiler();
+ $lc = $rl->getLessCompiler( [ 'foo' => '2px', 'Foo' => '#eeeeee' ] );
$basePath = dirname( dirname( __DIR__ ) ) . '/data/less';
$lc->SetImportDirs( [
"$basePath/common" => '',
}
}
- protected function getFailFerryMock() {
+ protected function getFailFerryMock( $getter = 'getScript' ) {
$mock = $this->getMockBuilder( ResourceLoaderTestModule::class )
- ->setMethods( [ 'getScript' ] )
+ ->setMethods( [ $getter ] )
->getMock();
- $mock->method( 'getScript' )->will( $this->throwException(
+ $mock->method( $getter )->will( $this->throwException(
new Exception( 'Ferry not found' )
) );
return $mock;
return $mock;
}
+ protected function getSimpleStyleModuleMock( $styles = '' ) {
+ $mock = $this->getMockBuilder( ResourceLoaderTestModule::class )
+ ->setMethods( [ 'getStyles' ] )
+ ->getMock();
+ $mock->method( 'getStyles' )->willReturn( [ '' => $styles ] );
+ return $mock;
+ }
+
/**
* @covers ResourceLoader::getCombinedVersion
*/
$this->assertEquals( $expected, $response, $message ?: 'Response' );
}
+ /**
+ * @covers ResourceLoader::makeModuleResponse
+ */
+ public function testMakeModuleResponseEmpty() {
+ $rl = new EmptyResourceLoader();
+ $context = $this->getResourceLoaderContext(
+ [ 'modules' => '', 'only' => 'scripts' ],
+ $rl
+ );
+
+ $response = $rl->makeModuleResponse( $context, [] );
+ $this->assertSame( [], $rl->getErrors(), 'Errors' );
+ $this->assertRegExp( '/^\/\*.+no modules were requested.+\*\/$/ms', $response );
+ }
+
/**
* Verify that when building module content in a load.php response,
* an exception from one module will not break script output from
);
}
+ /**
+ * Verify that exceptions in PHP for one module will not break others
+ * (stylesheet response).
+ *
+ * @covers ResourceLoader::makeModuleResponse
+ */
+ public function testMakeModuleResponseErrorCSS() {
+ $modules = [
+ 'foo' => self::getSimpleStyleModuleMock( '.foo{}' ),
+ 'ferry' => self::getFailFerryMock( 'getStyles' ),
+ 'bar' => self::getSimpleStyleModuleMock( '.bar{}' ),
+ ];
+ $rl = new EmptyResourceLoader();
+ $rl->register( $modules );
+ $context = $this->getResourceLoaderContext(
+ [
+ 'modules' => 'foo|ferry|bar',
+ 'only' => 'styles',
+ 'debug' => 'false',
+ ],
+ $rl
+ );
+
+ // Disable log from makeModuleResponse via outputErrorAndLog
+ $this->setLogger( 'exception', new Psr\Log\NullLogger() );
+
+ $response = $rl->makeModuleResponse( $context, $modules );
+ $errors = $rl->getErrors();
+
+ $this->assertCount( 2, $errors );
+ $this->assertRegExp( '/Ferry not found/', $errors[0] );
+ $this->assertRegExp( '/Problem.+"ferry":\s*"error"/ms', $errors[1] );
+ $this->assertEquals(
+ '.foo{}.bar{}',
+ $response
+ );
+ }
/**
* Verify that when building the startup module response,
* an exception from one module class will not break the entire
/**
* @covers ResourceLoader::respond
*/
- public function testRespond() {
+ public function testRespondEmpty() {
$rl = $this->getMockBuilder( EmptyResourceLoader::class )
->setMethods( [
'tryRespondNotModified',
$rl->respond( $context );
}
+ /**
+ * @covers ResourceLoader::respond
+ */
+ public function testRespondSimple() {
+ $module = new ResourceLoaderTestModule( [ 'script' => 'foo();' ] );
+ $rl = $this->getMockBuilder( EmptyResourceLoader::class )
+ ->setMethods( [
+ 'measureResponseTime',
+ 'tryRespondNotModified',
+ 'sendResponseHeaders',
+ 'makeModuleResponse',
+ ] )
+ ->getMock();
+ $rl->register( 'test', $module );
+ $context = $this->getResourceLoaderContext(
+ [ 'modules' => 'test', 'only' => null ],
+ $rl
+ );
+
+ $rl->expects( $this->once() )->method( 'makeModuleResponse' )
+ ->with( $context, [ 'test' => $module ] )
+ ->willReturn( 'implement_foo;' );
+ $this->expectOutputRegex( '/^implement_foo;/' );
+
+ $rl->respond( $context );
+ }
+
+ /**
+ * @covers ResourceLoader::respond
+ */
+ public function testRespondInternalFailures() {
+ $module = new ResourceLoaderTestModule( [ 'script' => 'foo();' ] );
+ $rl = $this->getMockBuilder( EmptyResourceLoader::class )
+ ->setMethods( [
+ 'measureResponseTime',
+ 'preloadModuleInfo',
+ 'getCombinedVersion',
+ 'tryRespondNotModified',
+ 'makeModuleResponse',
+ 'sendResponseHeaders',
+ ] )
+ ->getMock();
+ $rl->register( 'test', $module );
+ $context = $this->getResourceLoaderContext( [ 'modules' => 'test' ], $rl );
+ // Disable logging from outputErrorAndLog
+ $this->setLogger( 'exception', new Psr\Log\NullLogger() );
+
+ $rl->expects( $this->once() )->method( 'preloadModuleInfo' )
+ ->willThrowException( new Exception( 'Preload error' ) );
+ $rl->expects( $this->once() )->method( 'getCombinedVersion' )
+ ->willThrowException( new Exception( 'Version error' ) );
+ $rl->expects( $this->once() )->method( 'makeModuleResponse' )
+ ->with( $context, [ 'test' => $module ] )
+ ->willReturn( 'foo;' );
+ // Internal errors should be caught and logged without affecting module output
+ $this->expectOutputRegex( '/^\/\*.+Preload error.+Version error.+\*\/.*foo;/ms' );
+
+ $rl->respond( $context );
+ }
+
/**
* @covers ResourceLoader::measureResponseTime
*/