<?php
+use Wikimedia\TestingAccessWrapper;
+
/**
*
* @author Matthew Flaschen
*
+ * @group Database
* @group Output
*
* @todo factor tests in this class into providers and test methods
$this->assertEquals( $expectedHtml, $actualHtml );
}
+ public static function provideBuildExemptModules() {
+ return [
+ 'empty' => [
+ 'exemptStyleModules' => [],
+ '<meta name="ResourceLoaderDynamicStyles" content=""/>',
+ ],
+ 'empty sets' => [
+ 'exemptStyleModules' => [ 'site' => [], 'noscript' => [], 'private' => [], 'user' => [] ],
+ '<meta name="ResourceLoaderDynamicStyles" content=""/>',
+ ],
+ // @codingStandardsIgnoreStart Generic.Files.LineLength
+ 'default logged-out' => [
+ 'exemptStyleModules' => [ 'site' => [ 'site.styles' ] ],
+ '<meta name="ResourceLoaderDynamicStyles" content=""/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=site.styles&only=styles&skin=fallback"/>',
+ ],
+ 'default logged-in' => [
+ 'exemptStyleModules' => [ 'site' => [ 'site.styles' ], 'user' => [ 'user.styles' ] ],
+ '<meta name="ResourceLoaderDynamicStyles" content=""/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=site.styles&only=styles&skin=fallback"/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=user.styles&only=styles&skin=fallback&version=1e9z0ox"/>',
+ ],
+ 'custom modules' => [
+ 'exemptStyleModules' => [
+ 'site' => [ 'site.styles', 'example.site.a', 'example.site.b' ],
+ 'user' => [ 'user.styles', 'example.user' ],
+ ],
+ '<meta name="ResourceLoaderDynamicStyles" content=""/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=example.site.a%2Cb&only=styles&skin=fallback"/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=site.styles&only=styles&skin=fallback"/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=example.user&only=styles&skin=fallback&version=0a56zyi"/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=user.styles&only=styles&skin=fallback&version=1e9z0ox"/>',
+ ],
+ // @codingStandardsIgnoreEnd Generic.Files.LineLength
+ ];
+ }
+
+ /**
+ * @dataProvider provideBuildExemptModules
+ * @covers OutputPage::buildExemptModules
+ */
+ public function testBuildExemptModules( array $exemptStyleModules, $expect ) {
+ $this->setMwGlobals( [
+ 'wgResourceLoaderDebug' => false,
+ 'wgLoadScript' => '/w/load.php',
+ // Stub wgCacheEpoch as it influences getVersionHash used for the
+ // urls in the expected HTML
+ 'wgCacheEpoch' => '20140101000000',
+ ] );
+
+ // Set up stubs
+ $ctx = new RequestContext();
+ $ctx->setSkin( SkinFactory::getDefaultInstance()->makeSkin( 'fallback' ) );
+ $ctx->setLanguage( 'en' );
+ $outputPage = $this->getMockBuilder( 'OutputPage' )
+ ->setConstructorArgs( [ $ctx ] )
+ ->setMethods( [ 'isUserCssPreview', 'buildCssLinksArray' ] )
+ ->getMock();
+ $outputPage->expects( $this->any() )
+ ->method( 'isUserCssPreview' )
+ ->willReturn( false );
+ $outputPage->expects( $this->any() )
+ ->method( 'buildCssLinksArray' )
+ ->willReturn( [] );
+ $rl = $outputPage->getResourceLoader();
+ $rl->setMessageBlobStore( new NullMessageBlobStore() );
+
+ // Register custom modules
+ $rl->register( [
+ 'example.site.a' => new ResourceLoaderTestModule( [ 'group' => 'site' ] ),
+ 'example.site.b' => new ResourceLoaderTestModule( [ 'group' => 'site' ] ),
+ 'example.user' => new ResourceLoaderTestModule( [ 'group' => 'user' ] ),
+ ] );
+
+ $outputPage = TestingAccessWrapper::newFromObject( $outputPage );
+ $outputPage->rlExemptStyleModules = $exemptStyleModules;
+ $this->assertEquals(
+ $expect,
+ strval( $outputPage->buildExemptModules() )
+ );
+ }
+
/**
* @dataProvider provideVaryHeaders
* @covers OutputPage::addVaryHeader
$this->assertEquals( [ 0 => 'Test' ], $outputPage->getCategories( 'hidden' ) );
}
+ /**
+ * @dataProvider provideLinkHeaders
+ * @covers OutputPage::addLinkHeader
+ * @covers OutputPage::getLinkHeader
+ */
+ public function testLinkHeaders( $headers, $result ) {
+ $outputPage = $this->newInstance();
+
+ foreach ( $headers as $header ) {
+ $outputPage->addLinkHeader( $header );
+ }
+
+ $this->assertEquals( $result, $outputPage->getLinkHeader() );
+ }
+
+ public function provideLinkHeaders() {
+ return [
+ [
+ [],
+ false
+ ],
+ [
+ [ '<https://foo/bar.jpg>;rel=preload;as=image' ],
+ 'Link: <https://foo/bar.jpg>;rel=preload;as=image',
+ ],
+ [
+ [ '<https://foo/bar.jpg>;rel=preload;as=image','<https://foo/baz.jpg>;rel=preload;as=image' ],
+ 'Link: <https://foo/bar.jpg>;rel=preload;as=image,<https://foo/baz.jpg>;rel=preload;as=image',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider providePreloadLinkHeaders
+ * @covers OutputPage::addLogoPreloadLinkHeaders
+ * @covers ResourceLoaderSkinModule::getLogo
+ */
+ public function testPreloadLinkHeaders( $config, $result, $baseDir = null ) {
+ if ( $baseDir ) {
+ $this->setMwGlobals( 'IP', $baseDir );
+ }
+ $out = TestingAccessWrapper::newFromObject( $this->newInstance( $config ) );
+ $out->addLogoPreloadLinkHeaders();
+
+ $this->assertEquals( $result, $out->getLinkHeader() );
+ }
+
+ public function providePreloadLinkHeaders() {
+ return [
+ [
+ [
+ 'ResourceBasePath' => '/w',
+ 'Logo' => '/img/default.png',
+ 'LogoHD' => [
+ '1.5x' => '/img/one-point-five.png',
+ '2x' => '/img/two-x.png',
+ ],
+ ],
+ 'Link: </img/default.png>;rel=preload;as=image;media=' .
+ 'not all and (min-resolution: 1.5dppx),' .
+ '</img/one-point-five.png>;rel=preload;as=image;media=' .
+ '(min-resolution: 1.5dppx) and (max-resolution: 1.999999dppx),' .
+ '</img/two-x.png>;rel=preload;as=image;media=(min-resolution: 2dppx)'
+ ],
+ [
+ [
+ 'ResourceBasePath' => '/w',
+ 'Logo' => '/img/default.png',
+ 'LogoHD' => false,
+ ],
+ 'Link: </img/default.png>;rel=preload;as=image'
+ ],
+ [
+ [
+ 'ResourceBasePath' => '/w',
+ 'Logo' => '/img/default.png',
+ 'LogoHD' => [
+ '2x' => '/img/two-x.png',
+ ],
+ ],
+ 'Link: </img/default.png>;rel=preload;as=image;media=' .
+ 'not all and (min-resolution: 2dppx),' .
+ '</img/two-x.png>;rel=preload;as=image;media=(min-resolution: 2dppx)'
+ ],
+ [
+ [
+ 'ResourceBasePath' => '/w',
+ 'Logo' => '/w/test.jpg',
+ 'LogoHD' => false,
+ 'UploadPath' => '/w/images',
+ ],
+ 'Link: </w/test.jpg?edcf2>;rel=preload;as=image',
+ 'baseDir' => dirname( __DIR__ ) . '/data/media',
+ ],
+ ];
+ }
+
/**
* @return OutputPage
*/
- private function newInstance() {
+ private function newInstance( $config = [] ) {
$context = new RequestContext();
- $context->setConfig( new HashConfig( [
+ $context->setConfig( new HashConfig( $config + [
'AppleTouchIcon' => false,
'DisableLangConversion' => true,
'EnableAPI' => false,