2017-07-08 03:34:56 +00:00
|
|
|
<?php
|
|
|
|
|
|
2022-05-06 09:09:56 +00:00
|
|
|
namespace MediaWiki\Tests\ResourceLoader;
|
|
|
|
|
|
|
|
|
|
use Generator;
|
|
|
|
|
use InvalidArgumentException;
|
2023-09-20 07:54:42 +00:00
|
|
|
use MediaWiki\Config\HashConfig;
|
2023-06-19 19:21:47 +00:00
|
|
|
use MediaWiki\MainConfigNames;
|
2022-05-06 09:09:56 +00:00
|
|
|
use MediaWiki\ResourceLoader\Context;
|
|
|
|
|
use MediaWiki\ResourceLoader\FilePath;
|
|
|
|
|
use MediaWiki\ResourceLoader\SkinModule;
|
|
|
|
|
use ReflectionClass;
|
2018-08-20 23:58:41 +00:00
|
|
|
use Wikimedia\TestingAccessWrapper;
|
|
|
|
|
|
2017-07-08 03:34:56 +00:00
|
|
|
/**
|
|
|
|
|
* @group ResourceLoader
|
2022-08-08 15:22:31 +00:00
|
|
|
* @covers \MediaWiki\ResourceLoader\SkinModule
|
2017-07-08 03:34:56 +00:00
|
|
|
*/
|
2022-05-06 09:09:56 +00:00
|
|
|
class SkinModuleTest extends ResourceLoaderTestCase {
|
2021-03-18 03:20:36 +00:00
|
|
|
public static function provideApplyFeaturesCompatibility() {
|
2021-04-20 22:15:29 +00:00
|
|
|
return [
|
2024-09-09 15:59:44 +00:00
|
|
|
'Alias for unset target (content-thumbnails)' => [
|
2021-05-13 23:13:52 +00:00
|
|
|
[
|
|
|
|
|
'content-thumbnails' => true,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'content-media' => true,
|
|
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
true
|
2021-05-13 23:13:52 +00:00
|
|
|
],
|
2024-09-09 20:27:42 +00:00
|
|
|
'Alias with conflict (content-thumbnails)' => [
|
|
|
|
|
[
|
|
|
|
|
'content-thumbnails' => true,
|
|
|
|
|
'content-media' => false,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'content-media' => false,
|
|
|
|
|
],
|
|
|
|
|
true
|
|
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
'Alias that no-ops (legacy)' => [
|
2024-09-09 15:54:07 +00:00
|
|
|
[
|
|
|
|
|
'toc' => true,
|
|
|
|
|
'legacy' => true,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'toc' => true,
|
|
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
true
|
2021-04-20 22:15:29 +00:00
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
'content-links enables content-links-external if unset' => [
|
2021-04-20 22:15:29 +00:00
|
|
|
[
|
2021-03-18 03:20:36 +00:00
|
|
|
'content-links' => true,
|
2021-04-20 22:15:29 +00:00
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'content-links-external' => true,
|
|
|
|
|
'content-links' => true,
|
|
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
true
|
2021-04-20 22:15:29 +00:00
|
|
|
],
|
2024-09-09 20:39:11 +00:00
|
|
|
'elements enables content-links if unset' => [
|
2021-04-20 22:15:29 +00:00
|
|
|
[
|
2024-09-09 20:39:11 +00:00
|
|
|
'elements' => true,
|
2021-04-20 22:15:29 +00:00
|
|
|
],
|
|
|
|
|
[
|
2024-09-09 20:39:11 +00:00
|
|
|
'elements' => true,
|
2021-04-20 22:15:29 +00:00
|
|
|
'content-links' => true,
|
|
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
true
|
2021-04-20 22:15:29 +00:00
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
'content-links does not change content-links-external if set' => [
|
2021-04-20 22:15:29 +00:00
|
|
|
[
|
2021-03-18 03:20:36 +00:00
|
|
|
'content-links-external' => false,
|
|
|
|
|
'content-links' => true,
|
2021-04-20 22:15:29 +00:00
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'content-links-external' => false,
|
|
|
|
|
'content-links' => true,
|
|
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
true
|
2021-04-20 22:15:29 +00:00
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
'list-form does not add unwanted defaults (aliases)' => [
|
2022-01-25 16:26:14 +00:00
|
|
|
[
|
|
|
|
|
'content-links' => true,
|
|
|
|
|
'content-thumbnails' => true,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'content-links' => true,
|
|
|
|
|
'content-media' => true,
|
|
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
false
|
2022-01-25 16:26:14 +00:00
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
'list-form does not add unwanted defaults (no aliases)' => [
|
2022-01-25 16:26:14 +00:00
|
|
|
[
|
2024-09-09 15:59:44 +00:00
|
|
|
'elements' => true,
|
2022-01-25 16:26:14 +00:00
|
|
|
],
|
|
|
|
|
[
|
2024-09-09 15:59:44 +00:00
|
|
|
'elements' => true,
|
2022-01-25 16:26:14 +00:00
|
|
|
],
|
2024-09-09 15:59:44 +00:00
|
|
|
false
|
2022-01-25 16:26:14 +00:00
|
|
|
],
|
2021-04-20 22:15:29 +00:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2021-03-18 03:20:36 +00:00
|
|
|
* @dataProvider provideApplyFeaturesCompatibility
|
2021-04-20 22:15:29 +00:00
|
|
|
*/
|
2024-09-09 15:59:44 +00:00
|
|
|
public function testApplyFeaturesCompatibility( array $features, array $expected, bool $optInPolicy ) {
|
2021-03-18 03:20:36 +00:00
|
|
|
// Test protected method
|
2022-05-06 09:09:56 +00:00
|
|
|
$class = TestingAccessWrapper::newFromClass( SkinModule::class );
|
2022-01-25 16:26:14 +00:00
|
|
|
$actual = $class->applyFeaturesCompatibility( $features, $optInPolicy );
|
2024-09-09 15:59:44 +00:00
|
|
|
$this->assertEquals( $expected, $actual );
|
2021-04-20 22:15:29 +00:00
|
|
|
}
|
2017-07-08 03:34:56 +00:00
|
|
|
|
2020-01-07 19:18:51 +00:00
|
|
|
public static function provideGetAvailableLogos() {
|
|
|
|
|
return [
|
|
|
|
|
[
|
|
|
|
|
[
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::Logos => [],
|
|
|
|
|
MainConfigNames::Logo => '/logo.png',
|
2020-01-07 19:18:51 +00:00
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'1x' => '/logo.png',
|
|
|
|
|
]
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
[
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::Logos => [
|
2020-01-07 19:18:51 +00:00
|
|
|
'svg' => '/logo.svg',
|
|
|
|
|
'2x' => 'logo-2x.png'
|
|
|
|
|
],
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::Logo => '/logo.png',
|
2020-01-07 19:18:51 +00:00
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'svg' => '/logo.svg',
|
|
|
|
|
'2x' => 'logo-2x.png',
|
|
|
|
|
'1x' => '/logo.png',
|
|
|
|
|
]
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
[
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::Logos => [
|
2021-09-08 20:40:51 +00:00
|
|
|
'wordmark' => [
|
|
|
|
|
'src' => '/logo-wordmark.png',
|
|
|
|
|
'width' => 100,
|
|
|
|
|
'height' => 15,
|
|
|
|
|
],
|
2020-01-07 19:18:51 +00:00
|
|
|
'1x' => '/logo.png',
|
|
|
|
|
'svg' => '/logo.svg',
|
|
|
|
|
'2x' => 'logo-2x.png'
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
[
|
2021-09-08 20:40:51 +00:00
|
|
|
'wordmark' => [
|
|
|
|
|
'src' => '/logo-wordmark.png',
|
|
|
|
|
'width' => 100,
|
|
|
|
|
'height' => 15,
|
|
|
|
|
'style' => 'width: 6.25em; height: 0.9375em;',
|
|
|
|
|
],
|
2020-01-07 19:18:51 +00:00
|
|
|
'1x' => '/logo.png',
|
|
|
|
|
'svg' => '/logo.svg',
|
|
|
|
|
'2x' => 'logo-2x.png',
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-28 14:32:23 +00:00
|
|
|
public static function provideGetLogoStyles() {
|
2017-07-08 03:34:56 +00:00
|
|
|
return [
|
|
|
|
|
[
|
2024-02-28 14:32:23 +00:00
|
|
|
'features' => [],
|
2017-05-22 18:12:26 +00:00
|
|
|
'logo' => '/logo.png',
|
2017-07-08 03:34:56 +00:00
|
|
|
'expected' => [
|
|
|
|
|
'all' => [ '.mw-wiki-logo { background-image: url(/logo.png); }' ],
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
[
|
2024-02-28 14:32:23 +00:00
|
|
|
'features' => [
|
2017-07-08 03:34:56 +00:00
|
|
|
'screen' => '.example {}',
|
|
|
|
|
],
|
2017-05-22 18:12:26 +00:00
|
|
|
'logo' => '/logo.png',
|
2017-07-08 03:34:56 +00:00
|
|
|
'expected' => [
|
2024-02-28 14:32:23 +00:00
|
|
|
'screen' => '.example {}',
|
2017-07-08 03:34:56 +00:00
|
|
|
'all' => [ '.mw-wiki-logo { background-image: url(/logo.png); }' ],
|
|
|
|
|
],
|
|
|
|
|
],
|
2017-05-22 18:12:26 +00:00
|
|
|
[
|
2024-02-28 14:32:23 +00:00
|
|
|
'features' => [],
|
2017-05-22 18:12:26 +00:00
|
|
|
'logo' => [
|
|
|
|
|
'1x' => '/logo.png',
|
|
|
|
|
'1.5x' => '/logo@1.5x.png',
|
|
|
|
|
'2x' => '/logo@2x.png',
|
|
|
|
|
],
|
|
|
|
|
'expected' => [
|
2023-02-07 23:33:53 +00:00
|
|
|
'all' => [
|
|
|
|
|
'.mw-wiki-logo { background-image: url(/logo.png); }',
|
2017-05-22 18:12:26 +00:00
|
|
|
],
|
2023-02-07 23:33:53 +00:00
|
|
|
'(-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx), (min-resolution: 144dpi)' => [
|
|
|
|
|
'.mw-wiki-logo { background-image: url(/logo@1.5x.png);background-size: 135px auto; }',
|
2017-05-22 18:12:26 +00:00
|
|
|
],
|
2023-02-07 23:33:53 +00:00
|
|
|
'(-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx), (min-resolution: 192dpi)' => [
|
|
|
|
|
'.mw-wiki-logo { background-image: url(/logo@2x.png);background-size: 135px auto; }',
|
2017-05-22 18:12:26 +00:00
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
[
|
2024-02-28 14:32:23 +00:00
|
|
|
'features' => [],
|
2017-05-22 18:12:26 +00:00
|
|
|
'logo' => [
|
|
|
|
|
'1x' => '/logo.png',
|
|
|
|
|
'svg' => '/logo.svg',
|
|
|
|
|
],
|
|
|
|
|
'expected' => [
|
2023-02-07 23:33:53 +00:00
|
|
|
'all' => [
|
|
|
|
|
'.mw-wiki-logo { background-image: url(/logo.svg); }',
|
|
|
|
|
'.mw-wiki-logo { background-size: 135px auto; }',
|
2017-05-22 18:12:26 +00:00
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
],
|
2017-07-08 03:34:56 +00:00
|
|
|
];
|
2018-01-01 13:10:16 +00:00
|
|
|
// phpcs:enable
|
2017-07-08 03:34:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2024-02-28 14:32:23 +00:00
|
|
|
* @dataProvider provideGetLogoStyles
|
2017-07-08 03:34:56 +00:00
|
|
|
*/
|
2024-02-28 14:32:23 +00:00
|
|
|
public function testGenerateAndAppendLogoStyles( $features, $logo, $expected ) {
|
2022-05-06 09:09:56 +00:00
|
|
|
$module = $this->getMockBuilder( SkinModule::class )
|
2024-02-28 14:32:23 +00:00
|
|
|
->onlyMethods( [ 'getLogoData' ] )
|
2017-07-08 03:34:56 +00:00
|
|
|
->getMock();
|
2024-02-28 14:32:23 +00:00
|
|
|
$module->expects( $this->atLeast( 1 ) )->method( 'getLogoData' )
|
2017-05-22 18:12:26 +00:00
|
|
|
->willReturn( $logo );
|
2021-03-18 03:20:36 +00:00
|
|
|
$module->setConfig( new HashConfig( [
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::ParserEnableLegacyMediaDOM => false,
|
2021-03-18 04:08:05 +00:00
|
|
|
] + self::getSettings() ) );
|
2017-07-08 03:34:56 +00:00
|
|
|
|
2022-07-14 12:42:07 +00:00
|
|
|
$ctx = $this->createMock( Context::class );
|
2017-07-08 03:34:56 +00:00
|
|
|
|
|
|
|
|
$this->assertEquals(
|
2017-05-22 18:12:26 +00:00
|
|
|
$expected,
|
2024-02-28 14:32:23 +00:00
|
|
|
$module->generateAndAppendLogoStyles( $features, $ctx )
|
2017-07-08 03:34:56 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-07 19:18:51 +00:00
|
|
|
/**
|
|
|
|
|
* @dataProvider provideGetAvailableLogos
|
|
|
|
|
*/
|
|
|
|
|
public function testGetAvailableLogos( $config, $expected ) {
|
2022-05-06 09:09:56 +00:00
|
|
|
$logos = SkinModule::getAvailableLogos( new HashConfig( $config ) );
|
2022-02-08 05:12:43 +00:00
|
|
|
$this->assertSame( $expected, $logos );
|
2020-01-07 19:18:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testGetAvailableLogosRuntimeException() {
|
2022-05-06 09:09:56 +00:00
|
|
|
$logos = SkinModule::getAvailableLogos( new HashConfig( [
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::Logo => false,
|
|
|
|
|
MainConfigNames::Logos => false,
|
2020-01-07 19:18:51 +00:00
|
|
|
] ) );
|
2022-02-10 00:37:10 +00:00
|
|
|
$this->assertSame( [], $logos );
|
2020-01-07 19:18:51 +00:00
|
|
|
}
|
|
|
|
|
|
2017-07-08 03:34:56 +00:00
|
|
|
public function testIsKnownEmpty() {
|
2022-08-05 10:52:01 +00:00
|
|
|
$module = new SkinModule();
|
|
|
|
|
$ctx = $this->createMock( Context::class );
|
2017-07-08 03:34:56 +00:00
|
|
|
|
|
|
|
|
$this->assertFalse( $module->isKnownEmpty( $ctx ) );
|
|
|
|
|
}
|
2017-05-22 18:12:26 +00:00
|
|
|
|
|
|
|
|
/**
|
2018-08-20 23:58:41 +00:00
|
|
|
* @dataProvider provideGetLogoData
|
2017-05-22 18:12:26 +00:00
|
|
|
*/
|
2022-01-27 20:24:12 +00:00
|
|
|
public function testGetLogoData( $config, $expected ) {
|
2018-08-20 23:58:41 +00:00
|
|
|
// Allow testing of protected method
|
2022-05-06 09:09:56 +00:00
|
|
|
$module = TestingAccessWrapper::newFromObject( new SkinModule() );
|
2017-05-22 18:12:26 +00:00
|
|
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
$expected,
|
2018-08-20 23:58:41 +00:00
|
|
|
$module->getLogoData( new HashConfig( $config ) )
|
2017-05-22 18:12:26 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-23 11:36:19 +00:00
|
|
|
public static function provideGetLogoData() {
|
2017-05-22 18:12:26 +00:00
|
|
|
return [
|
2020-02-05 21:12:02 +00:00
|
|
|
'wordmark' => [
|
|
|
|
|
'config' => [
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::BaseDirectory => MW_INSTALL_PATH,
|
|
|
|
|
MainConfigNames::ResourceBasePath => '/w',
|
|
|
|
|
MainConfigNames::Logos => [
|
2020-02-05 21:12:02 +00:00
|
|
|
'1x' => '/img/default.png',
|
2021-09-08 20:40:51 +00:00
|
|
|
'wordmark' => [
|
|
|
|
|
'src' => '/img/wordmark.png',
|
|
|
|
|
'width' => 120,
|
|
|
|
|
'height' => 20,
|
|
|
|
|
],
|
2020-02-05 21:12:02 +00:00
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'expected' => '/img/default.png',
|
|
|
|
|
],
|
2017-05-22 18:12:26 +00:00
|
|
|
'simple' => [
|
|
|
|
|
'config' => [
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::BaseDirectory => MW_INSTALL_PATH,
|
|
|
|
|
MainConfigNames::ResourceBasePath => '/w',
|
|
|
|
|
MainConfigNames::Logos => [
|
2020-01-07 19:18:51 +00:00
|
|
|
'1x' => '/img/default.png',
|
|
|
|
|
],
|
2017-05-22 18:12:26 +00:00
|
|
|
],
|
|
|
|
|
'expected' => '/img/default.png',
|
|
|
|
|
],
|
|
|
|
|
'default and 2x' => [
|
|
|
|
|
'config' => [
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::BaseDirectory => MW_INSTALL_PATH,
|
|
|
|
|
MainConfigNames::ResourceBasePath => '/w',
|
|
|
|
|
MainConfigNames::Logos => [
|
2020-01-07 19:18:51 +00:00
|
|
|
'1x' => '/img/default.png',
|
2017-05-22 18:12:26 +00:00
|
|
|
'2x' => '/img/two-x.png',
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'expected' => [
|
|
|
|
|
'1x' => '/img/default.png',
|
|
|
|
|
'2x' => '/img/two-x.png',
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'default and all HiDPIs' => [
|
|
|
|
|
'config' => [
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::BaseDirectory => MW_INSTALL_PATH,
|
|
|
|
|
MainConfigNames::ResourceBasePath => '/w',
|
|
|
|
|
MainConfigNames::Logos => [
|
2020-01-07 19:18:51 +00:00
|
|
|
'1x' => '/img/default.png',
|
2017-05-22 18:12:26 +00:00
|
|
|
'1.5x' => '/img/one-point-five.png',
|
|
|
|
|
'2x' => '/img/two-x.png',
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'expected' => [
|
|
|
|
|
'1x' => '/img/default.png',
|
|
|
|
|
'1.5x' => '/img/one-point-five.png',
|
|
|
|
|
'2x' => '/img/two-x.png',
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'default and SVG' => [
|
|
|
|
|
'config' => [
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::BaseDirectory => MW_INSTALL_PATH,
|
|
|
|
|
MainConfigNames::ResourceBasePath => '/w',
|
|
|
|
|
MainConfigNames::Logos => [
|
2020-01-07 19:18:51 +00:00
|
|
|
'1x' => '/img/default.png',
|
2017-05-22 18:12:26 +00:00
|
|
|
'svg' => '/img/vector.svg',
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'expected' => [
|
|
|
|
|
'1x' => '/img/default.png',
|
|
|
|
|
'svg' => '/img/vector.svg',
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'everything' => [
|
|
|
|
|
'config' => [
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::BaseDirectory => MW_INSTALL_PATH,
|
|
|
|
|
MainConfigNames::ResourceBasePath => '/w',
|
|
|
|
|
MainConfigNames::Logos => [
|
2020-01-07 19:18:51 +00:00
|
|
|
'1x' => '/img/default.png',
|
2017-05-22 18:12:26 +00:00
|
|
|
'1.5x' => '/img/one-point-five.png',
|
|
|
|
|
'2x' => '/img/two-x.png',
|
|
|
|
|
'svg' => '/img/vector.svg',
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'expected' => [
|
|
|
|
|
'1x' => '/img/default.png',
|
|
|
|
|
'svg' => '/img/vector.svg',
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'versioned url' => [
|
|
|
|
|
'config' => [
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::BaseDirectory => dirname( dirname( __DIR__ ) ) . '/data/media',
|
|
|
|
|
MainConfigNames::ResourceBasePath => '/w',
|
|
|
|
|
MainConfigNames::UploadPath => '/w/images',
|
|
|
|
|
MainConfigNames::Logos => [
|
2020-01-07 19:18:51 +00:00
|
|
|
'1x' => '/w/test.jpg',
|
|
|
|
|
],
|
2017-05-22 18:12:26 +00:00
|
|
|
],
|
|
|
|
|
'expected' => '/w/test.jpg?edcf2',
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
}
|
2018-08-20 23:58:41 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider providePreloadLinks
|
|
|
|
|
*/
|
2022-03-26 15:23:57 +00:00
|
|
|
public function testPreloadLinkHeaders( $config, $lang, $result ) {
|
2022-07-14 12:42:07 +00:00
|
|
|
$ctx = $this->createMock( Context::class );
|
2022-03-26 15:23:57 +00:00
|
|
|
$ctx->method( 'getLanguage' )->willReturn( $lang );
|
2022-05-06 09:09:56 +00:00
|
|
|
$module = new SkinModule();
|
2022-03-26 16:01:03 +00:00
|
|
|
$module->setConfig( new HashConfig( $config + [
|
2023-06-19 19:21:47 +00:00
|
|
|
MainConfigNames::BaseDirectory => '/dummy',
|
|
|
|
|
MainConfigNames::ResourceBasePath => '/w',
|
|
|
|
|
MainConfigNames::Logo => false,
|
2022-03-26 16:01:03 +00:00
|
|
|
] + self::getSettings() ) );
|
2018-08-20 23:58:41 +00:00
|
|
|
|
|
|
|
|
$this->assertEquals( [ $result ], $module->getHeaders( $ctx ) );
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-23 11:36:19 +00:00
|
|
|
public static function providePreloadLinks() {
|
2018-08-20 23:58:41 +00:00
|
|
|
return [
|
|
|
|
|
[
|
|
|
|
|
[
|
2024-07-09 15:36:08 +00:00
|
|
|
MainConfigNames::Logos => [
|
2020-01-07 19:18:51 +00:00
|
|
|
'1x' => '/img/default.png',
|
2018-08-20 23:58:41 +00:00
|
|
|
'1.5x' => '/img/one-point-five.png',
|
|
|
|
|
'2x' => '/img/two-x.png',
|
|
|
|
|
],
|
|
|
|
|
],
|
2022-03-26 15:23:57 +00:00
|
|
|
'en',
|
2018-08-20 23:58:41 +00:00
|
|
|
'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)'
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
[
|
2024-07-09 15:36:08 +00:00
|
|
|
MainConfigNames::Logos => [ '1x' => '/img/default.png' ],
|
2018-08-20 23:58:41 +00:00
|
|
|
],
|
2022-03-26 15:23:57 +00:00
|
|
|
'en',
|
2018-08-20 23:58:41 +00:00
|
|
|
'Link: </img/default.png>;rel=preload;as=image'
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
[
|
2024-07-09 15:36:08 +00:00
|
|
|
MainConfigNames::Logos => [
|
2020-01-07 19:18:51 +00:00
|
|
|
'1x' => '/img/default.png',
|
2018-08-20 23:58:41 +00:00
|
|
|
'2x' => '/img/two-x.png',
|
|
|
|
|
],
|
|
|
|
|
],
|
2022-03-26 15:23:57 +00:00
|
|
|
'en',
|
2018-08-20 23:58:41 +00:00
|
|
|
'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)'
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
[
|
2024-07-09 15:36:08 +00:00
|
|
|
MainConfigNames::Logos => [
|
2020-01-07 19:18:51 +00:00
|
|
|
'1x' => '/img/default.png',
|
2018-08-20 23:58:41 +00:00
|
|
|
'svg' => '/img/vector.svg',
|
|
|
|
|
],
|
|
|
|
|
],
|
2022-03-26 15:23:57 +00:00
|
|
|
'en',
|
2018-08-20 23:58:41 +00:00
|
|
|
'Link: </img/vector.svg>;rel=preload;as=image'
|
|
|
|
|
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
[
|
2024-07-09 15:36:08 +00:00
|
|
|
MainConfigNames::BaseDirectory => dirname( dirname( __DIR__ ) ) . '/data/media',
|
|
|
|
|
MainConfigNames::Logos => [ '1x' => '/w/test.jpg' ],
|
|
|
|
|
MainConfigNames::UploadPath => '/w/images',
|
2018-08-20 23:58:41 +00:00
|
|
|
],
|
2022-03-26 15:23:57 +00:00
|
|
|
'en',
|
2018-08-20 23:58:41 +00:00
|
|
|
'Link: </w/test.jpg?edcf2>;rel=preload;as=image',
|
|
|
|
|
],
|
2022-03-26 15:23:57 +00:00
|
|
|
[
|
|
|
|
|
[
|
2024-07-09 15:36:08 +00:00
|
|
|
MainConfigNames::Logos => [
|
2022-03-26 15:23:57 +00:00
|
|
|
'1x' => '/img/default.png',
|
|
|
|
|
'1.5x' => '/img/one-point-five.png',
|
|
|
|
|
'2x' => '/img/two-x.png',
|
|
|
|
|
'variants' => [
|
|
|
|
|
'zh-hans' => [
|
|
|
|
|
'1x' => '/img/default-zh-hans.png',
|
|
|
|
|
'1.5x' => '/img/one-point-five-zh-hans.png',
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'zh-hans',
|
|
|
|
|
'Link: </img/default-zh-hans.png>;rel=preload;as=image;media=' .
|
|
|
|
|
'not all and (min-resolution: 1.5dppx),' .
|
|
|
|
|
'</img/one-point-five-zh-hans.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)'
|
|
|
|
|
],
|
2018-08-20 23:58:41 +00:00
|
|
|
];
|
|
|
|
|
}
|
2020-06-10 14:09:09 +00:00
|
|
|
|
2020-10-18 20:16:37 +00:00
|
|
|
public function testNoPreloadLogos() {
|
2022-05-06 09:09:56 +00:00
|
|
|
$module = new SkinModule( [ 'features' => [ 'logo' => false ] ] );
|
2020-10-18 20:16:37 +00:00
|
|
|
$context =
|
2022-07-14 12:42:07 +00:00
|
|
|
$this->createMock( Context::class );
|
2020-10-18 20:16:37 +00:00
|
|
|
$preloadLinks = $module->getPreloadLinks( $context );
|
|
|
|
|
$this->assertArrayEquals( [], $preloadLinks );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testPreloadLogos() {
|
2022-05-06 09:09:56 +00:00
|
|
|
$module = new SkinModule();
|
2021-03-18 04:08:05 +00:00
|
|
|
$module->setConfig( self::getMinimalConfig() );
|
2022-07-14 12:42:07 +00:00
|
|
|
$context = $this->createMock( Context::class );
|
2021-03-18 04:08:05 +00:00
|
|
|
|
2020-10-18 20:16:37 +00:00
|
|
|
$preloadLinks = $module->getPreloadLinks( $context );
|
|
|
|
|
$this->assertNotSameSize( [], $preloadLinks );
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-10 14:09:09 +00:00
|
|
|
/**
|
2022-05-06 09:09:56 +00:00
|
|
|
* Covers SkinModule::FEATURE_FILES, but not annotatable.
|
2020-06-10 14:09:09 +00:00
|
|
|
*
|
|
|
|
|
* @dataProvider provideFeatureFiles
|
|
|
|
|
* @param string $file
|
|
|
|
|
*/
|
2021-07-22 03:11:47 +00:00
|
|
|
public function testFeatureFilesExist( string $file ): void {
|
2020-06-10 14:09:09 +00:00
|
|
|
$this->assertFileExists( $file );
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-23 11:36:19 +00:00
|
|
|
public static function provideFeatureFiles(): Generator {
|
2020-06-10 14:09:09 +00:00
|
|
|
global $IP;
|
|
|
|
|
|
2022-05-06 09:09:56 +00:00
|
|
|
$featureFiles = ( new ReflectionClass( SkinModule::class ) )
|
2020-06-10 14:09:09 +00:00
|
|
|
->getConstant( 'FEATURE_FILES' );
|
|
|
|
|
|
|
|
|
|
foreach ( $featureFiles as $feature => $files ) {
|
|
|
|
|
foreach ( $files as $media => $stylesheets ) {
|
|
|
|
|
foreach ( $stylesheets as $stylesheet ) {
|
|
|
|
|
yield "$feature: $media: $stylesheet" => [ "$IP/$stylesheet" ];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-24 11:37:11 +00:00
|
|
|
|
2024-02-28 14:32:23 +00:00
|
|
|
public static function getSkinFeaturePath( $feature, $mediaType ) {
|
2021-03-18 04:08:05 +00:00
|
|
|
global $IP;
|
2024-02-28 14:32:23 +00:00
|
|
|
$featureFiles = ( new ReflectionClass( SkinModule::class ) )->getConstant( 'FEATURE_FILES' );
|
|
|
|
|
return new FilePath( $featureFiles[ $feature ][ $mediaType ][ 0 ], $IP, '/w' );
|
|
|
|
|
}
|
2021-01-08 21:23:29 +00:00
|
|
|
|
2024-02-28 14:32:23 +00:00
|
|
|
public static function provideGetFeatureFilePathsOrder() {
|
2021-01-08 21:23:29 +00:00
|
|
|
return [
|
2024-03-10 22:26:24 +00:00
|
|
|
[
|
|
|
|
|
'The "logo" skin-feature is loaded when the "features" key is absent',
|
|
|
|
|
[],
|
2024-02-19 18:46:13 +00:00
|
|
|
[
|
2024-03-10 22:26:24 +00:00
|
|
|
'all' => [ self::getSkinFeaturePath( 'logo', 'all' ) ],
|
|
|
|
|
'print' => [ self::getSkinFeaturePath( 'logo', 'print' ) ],
|
2020-12-07 19:02:58 +00:00
|
|
|
],
|
2024-03-10 22:26:24 +00:00
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'The "normalize" skin-feature is always output first',
|
2024-02-19 18:46:13 +00:00
|
|
|
[
|
2024-03-10 22:26:24 +00:00
|
|
|
'features' => [ 'elements', 'normalize' ],
|
|
|
|
|
],
|
2024-02-19 18:46:13 +00:00
|
|
|
[
|
2024-03-10 22:26:24 +00:00
|
|
|
'all' => [ self::getSkinFeaturePath( 'normalize', 'all' ) ],
|
|
|
|
|
'screen' => [ self::getSkinFeaturePath( 'elements', 'screen' ) ],
|
|
|
|
|
'print' => [ self::getSkinFeaturePath( 'elements', 'print' ) ],
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'Empty media query blocks are not included in output',
|
|
|
|
|
[
|
|
|
|
|
'features' => [
|
|
|
|
|
'accessibility' => false,
|
|
|
|
|
'content-body' => false,
|
|
|
|
|
'interface-core' => false,
|
|
|
|
|
'toc' => false
|
2024-02-28 14:32:23 +00:00
|
|
|
],
|
2021-05-24 23:11:32 +00:00
|
|
|
],
|
2024-03-10 22:26:24 +00:00
|
|
|
[],
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'Empty "features" key outputs default skin-features',
|
|
|
|
|
[
|
|
|
|
|
'features' => [],
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'all' => [
|
|
|
|
|
self::getSkinFeaturePath( 'accessibility', 'all' ),
|
|
|
|
|
self::getSkinFeaturePath( 'toc', 'all' )
|
2024-02-28 14:32:23 +00:00
|
|
|
],
|
2024-03-10 22:26:24 +00:00
|
|
|
'screen' => [
|
|
|
|
|
self::getSkinFeaturePath( 'content-body', 'screen' ),
|
|
|
|
|
self::getSkinFeaturePath( 'interface-core', 'screen' ),
|
|
|
|
|
self::getSkinFeaturePath( 'toc', 'screen' ),
|
2024-02-28 14:32:23 +00:00
|
|
|
],
|
2024-03-10 22:26:24 +00:00
|
|
|
'print' => [
|
|
|
|
|
self::getSkinFeaturePath( 'content-body', 'print' ),
|
|
|
|
|
self::getSkinFeaturePath( 'interface-core', 'print' ),
|
|
|
|
|
self::getSkinFeaturePath( 'toc', 'print' )
|
|
|
|
|
]
|
2021-05-24 23:11:32 +00:00
|
|
|
],
|
2024-03-10 22:26:24 +00:00
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'skin-features are output in the order defined in SkinModule.php',
|
|
|
|
|
[
|
|
|
|
|
'features' => [ 'interface-message-box', 'normalize', 'accessibility' ],
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'all' => [
|
|
|
|
|
self::getSkinFeaturePath( 'accessibility', 'all' ),
|
|
|
|
|
self::getSkinFeaturePath( 'normalize', 'all' ),
|
|
|
|
|
self::getSkinFeaturePath( 'interface-message-box', 'all' )
|
2024-02-28 14:32:23 +00:00
|
|
|
],
|
|
|
|
|
]
|
|
|
|
|
]
|
2020-08-24 11:37:11 +00:00
|
|
|
];
|
2021-01-08 21:23:29 +00:00
|
|
|
}
|
2020-08-24 11:37:11 +00:00
|
|
|
|
2021-01-08 21:23:29 +00:00
|
|
|
/**
|
2024-02-28 14:32:23 +00:00
|
|
|
* @dataProvider provideGetFeatureFilePathsOrder
|
2021-01-08 21:23:29 +00:00
|
|
|
* @param string $msg to show for debugging
|
2024-02-28 14:32:23 +00:00
|
|
|
* @param array $skinModuleConfig
|
|
|
|
|
* @param array $expectedStyleOrder
|
2021-01-08 21:23:29 +00:00
|
|
|
*/
|
2024-02-28 14:32:23 +00:00
|
|
|
public function testGetFeatureFilePathsOrder(
|
|
|
|
|
$msg, $skinModuleConfig, $expectedStyleOrder
|
2021-07-22 03:11:47 +00:00
|
|
|
): void {
|
2024-02-28 14:32:23 +00:00
|
|
|
$module = new SkinModule( $skinModuleConfig );
|
2021-03-18 04:08:05 +00:00
|
|
|
$module->setConfig( self::getMinimalConfig() );
|
2020-12-07 19:02:58 +00:00
|
|
|
|
2024-02-28 14:32:23 +00:00
|
|
|
$actual = $module->getFeatureFilePaths();
|
2024-02-14 01:52:01 +00:00
|
|
|
|
2020-08-24 11:37:11 +00:00
|
|
|
$this->assertEquals(
|
2024-02-28 14:32:23 +00:00
|
|
|
array_values( $expectedStyleOrder ),
|
2021-01-08 21:23:29 +00:00
|
|
|
array_values( $actual )
|
2020-08-24 11:37:11 +00:00
|
|
|
);
|
|
|
|
|
}
|
resourceloader: Restore feedback for SkinModule invalid argument
This was added in 381499a675 in response to the issue that when a skin
adopts a feature that was new in MW 1.36, it caused an exception when
that version of the skin is then installed on MW 1.35. That's expected,
and generally helpful because the default support policy requires
like-for-like (MW 1.35 with REL1_35, this applies to all skins and
extensions, except for a few like Translate and SemanticMediaWiki).
However, while supporting LTS within master is unusual, there are
indeed the Translate/SemanticMediaWiki projects, and this problem has
already been solved years ago there by using a conditional with
$wgVersion. The proposed approach on T271441 actually also involves
such a conditional, but late at runtime instead of in the module
definition. Anyway, the way it was fixed in Timeless already solves
the problem by not passing down the invalid feature in the first
place, thus making the 381499a675 patch obsolete. I'm not aware of
any skin in Gerrit having such a compat policy, but if they exist,
they can fix it the same way, by defining the module in code with
a condition, just as Translate/SemanticMediaWiki do.
Bug: T271441
Change-Id: If97b3d04ac1e3355ee4f229db11e524d24ebd27a
2021-03-18 17:22:37 +00:00
|
|
|
|
|
|
|
|
public static function provideInvalidFeatures() {
|
|
|
|
|
yield 'listed unknown' => [
|
|
|
|
|
[ 'logo', 'unknown' ],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
yield 'enabled unknown' => [
|
|
|
|
|
[
|
|
|
|
|
'logo' => true,
|
|
|
|
|
'toc' => false,
|
|
|
|
|
'unknown' => true,
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
|
2024-02-28 14:32:23 +00:00
|
|
|
yield 'disabled unknown' => [
|
resourceloader: Restore feedback for SkinModule invalid argument
This was added in 381499a675 in response to the issue that when a skin
adopts a feature that was new in MW 1.36, it caused an exception when
that version of the skin is then installed on MW 1.35. That's expected,
and generally helpful because the default support policy requires
like-for-like (MW 1.35 with REL1_35, this applies to all skins and
extensions, except for a few like Translate and SemanticMediaWiki).
However, while supporting LTS within master is unusual, there are
indeed the Translate/SemanticMediaWiki projects, and this problem has
already been solved years ago there by using a conditional with
$wgVersion. The proposed approach on T271441 actually also involves
such a conditional, but late at runtime instead of in the module
definition. Anyway, the way it was fixed in Timeless already solves
the problem by not passing down the invalid feature in the first
place, thus making the 381499a675 patch obsolete. I'm not aware of
any skin in Gerrit having such a compat policy, but if they exist,
they can fix it the same way, by defining the module in code with
a condition, just as Translate/SemanticMediaWiki do.
Bug: T271441
Change-Id: If97b3d04ac1e3355ee4f229db11e524d24ebd27a
2021-03-18 17:22:37 +00:00
|
|
|
[
|
|
|
|
|
'logo' => true,
|
|
|
|
|
'toc' => false,
|
|
|
|
|
'unknown' => false,
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideInvalidFeatures
|
|
|
|
|
*/
|
|
|
|
|
public function testConstructInvalidFeatures( array $features ) {
|
|
|
|
|
$this->expectException( InvalidArgumentException::class );
|
|
|
|
|
$this->expectExceptionMessage( "Feature 'unknown' is not recognised" );
|
2022-05-06 09:09:56 +00:00
|
|
|
$module = new SkinModule( [
|
resourceloader: Restore feedback for SkinModule invalid argument
This was added in 381499a675 in response to the issue that when a skin
adopts a feature that was new in MW 1.36, it caused an exception when
that version of the skin is then installed on MW 1.35. That's expected,
and generally helpful because the default support policy requires
like-for-like (MW 1.35 with REL1_35, this applies to all skins and
extensions, except for a few like Translate and SemanticMediaWiki).
However, while supporting LTS within master is unusual, there are
indeed the Translate/SemanticMediaWiki projects, and this problem has
already been solved years ago there by using a conditional with
$wgVersion. The proposed approach on T271441 actually also involves
such a conditional, but late at runtime instead of in the module
definition. Anyway, the way it was fixed in Timeless already solves
the problem by not passing down the invalid feature in the first
place, thus making the 381499a675 patch obsolete. I'm not aware of
any skin in Gerrit having such a compat policy, but if they exist,
they can fix it the same way, by defining the module in code with
a condition, just as Translate/SemanticMediaWiki do.
Bug: T271441
Change-Id: If97b3d04ac1e3355ee4f229db11e524d24ebd27a
2021-03-18 17:22:37 +00:00
|
|
|
'features' => $features,
|
|
|
|
|
] );
|
|
|
|
|
}
|
2017-07-08 03:34:56 +00:00
|
|
|
}
|