3 namespace MediaWiki\Tests\ResourceLoader
;
6 use MediaWiki\Config\HashConfig
;
7 use MediaWiki\MainConfigNames
;
8 use MediaWiki\Message\Message
;
9 use MediaWiki\Request\FauxRequest
;
10 use MediaWiki\Request\WebRequest
;
11 use MediaWiki\ResourceLoader\Context
;
12 use MediaWiki\ResourceLoader\ResourceLoader
;
13 use MediaWiki\User\User
;
14 use MediaWikiCoversValidator
;
15 use MediaWikiTestCaseTrait
;
16 use PHPUnit\Framework\TestCase
;
17 use Psr\Log\LoggerInterface
;
21 * - ImageModuleTest::testContext
23 * @group ResourceLoader
24 * @covers \MediaWiki\ResourceLoader\Context
26 class ContextTest
extends TestCase
{
28 use MediaWikiCoversValidator
;
29 use MediaWikiTestCaseTrait
;
31 protected static function getResourceLoader() {
32 return new EmptyResourceLoader( new HashConfig( [
33 MainConfigNames
::ResourceLoaderDebug
=> false,
34 MainConfigNames
::LoadScript
=> '/w/load.php',
38 public function testEmpty() {
39 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( [] ) );
42 $this->assertEquals( [], $ctx->getModules() );
43 $this->assertEquals( 'qqx', $ctx->getLanguage() );
44 $this->assertSame( 0, $ctx->getDebug() );
45 $this->assertNull( $ctx->getOnly() );
46 $this->assertEquals( 'fallback', $ctx->getSkin() );
47 $this->assertNull( $ctx->getUser() );
48 $this->assertNull( $ctx->getContentOverrideCallback() );
51 $this->assertEquals( 'ltr', $ctx->getDirection() );
52 $this->assertEquals( 'qqx|fallback|0|||||||', $ctx->getHash() );
53 $this->assertSame( [], $ctx->getReqBase() );
54 $this->assertInstanceOf( User
::class, $ctx->getUserObj() );
55 $this->assertNull( $ctx->getUserIdentity() );
58 public function testDummy() {
59 $this->assertInstanceOf(
61 Context
::newDummyContext()
65 public function testAccessors() {
66 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( [] ) );
67 $this->assertInstanceOf( ResourceLoader
::class, $ctx->getResourceLoader() );
68 $this->assertInstanceOf( WebRequest
::class, $ctx->getRequest() );
69 $this->assertInstanceOf( LoggerInterface
::class, $ctx->getLogger() );
72 public function testTypicalRequest() {
73 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( [
76 'modules' => 'foo|foo.quux,baz,bar|baz.quux',
83 [ 'foo', 'foo.quux', 'foo.baz', 'foo.bar', 'baz.quux' ],
86 $this->assertSame( 0, $ctx->getDebug() );
87 $this->assertEquals( 'zh', $ctx->getLanguage() );
88 $this->assertEquals( 'styles', $ctx->getOnly() );
89 $this->assertEquals( 'fallback', $ctx->getSkin() );
90 $this->assertNull( $ctx->getUser() );
93 $this->assertEquals( 'ltr', $ctx->getDirection() );
94 $this->assertEquals( 'zh|fallback|0||styles|||||', $ctx->getHash() );
95 $this->assertSame( [ 'lang' => 'zh' ], $ctx->getReqBase() );
98 public static function provideDirection() {
99 yield
'LTR language' => [
103 yield
'RTL language' => [
107 yield
'explicit LTR' => [
108 [ 'lang' => 'he', 'dir' => 'ltr' ],
111 yield
'explicit RTL' => [
112 [ 'lang' => 'en', 'dir' => 'rtl' ],
115 // Not supported, but tested to cover the case and detect change
116 yield
'invalid dir' => [
117 [ 'lang' => 'he', 'dir' => 'xyz' ],
123 * @dataProvider provideDirection
125 public function testDirection( array $params, $expected ) {
126 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( $params ) );
127 $this->assertEquals( $expected, $ctx->getDirection() );
130 public function testShouldInclude() {
131 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( [] ) );
132 $this->assertTrue( $ctx->shouldIncludeScripts(), 'Scripts in combined' );
133 $this->assertTrue( $ctx->shouldIncludeStyles(), 'Styles in combined' );
134 $this->assertTrue( $ctx->shouldIncludeMessages(), 'Messages in combined' );
136 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( [
139 $this->assertFalse( $ctx->shouldIncludeScripts(), 'Scripts not in styles-only' );
140 $this->assertTrue( $ctx->shouldIncludeStyles(), 'Styles in styles-only' );
141 $this->assertFalse( $ctx->shouldIncludeMessages(), 'Messages not in styles-only' );
143 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( [
146 $this->assertTrue( $ctx->shouldIncludeScripts(), 'Scripts in scripts-only' );
147 $this->assertFalse( $ctx->shouldIncludeStyles(), 'Styles not in scripts-only' );
148 $this->assertFalse( $ctx->shouldIncludeMessages(), 'Messages not in scripts-only' );
151 public function testGetUser() {
152 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( [] ) );
153 $this->assertSame( null, $ctx->getUser() );
154 $this->assertFalse( $ctx->getUserObj()->isRegistered() );
155 $this->assertNull( $ctx->getUserIdentity() );
157 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( [
160 $this->assertSame( 'Example', $ctx->getUser() );
161 $this->assertEquals( 'Example', $ctx->getUserObj()->getName() );
162 $this->assertEquals( 'Example', $ctx->getUserIdentity()->getName() );
165 public function testMsg() {
166 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( [
169 $msg = $ctx->msg( 'mainpage' );
170 $this->assertInstanceOf( Message
::class, $msg );
171 $this->assertSame( 'Main Page', $msg->useDatabase( false )->plain() );
174 public function testEncodeJson() {
175 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( [] ) );
177 $json = $ctx->encodeJson( [ 'x' => 'A' ] );
178 $this->assertSame( '{"x":"A"}', $json );
180 // Regression: https://phabricator.wikimedia.org/T329330
181 $json = @$ctx->encodeJson( [
183 'y' => "Foo\x80\xf0Bar",
186 $this->assertSame( '{"x":"A","y":null,"z":"C"}', $json, 'Ignore invalid UTF-8' );
189 public function testEncodeJsonWarning() {
190 $ctx = new Context( self
::getResourceLoader(), new FauxRequest( [] ) );
192 $this->expectPHPError(
194 static function () use ( $ctx ) {
197 'y' => "Foo\x80\xf0Bar",
201 'encodeJson partially failed: Malformed UTF-8'
205 public static function skinsProvider(): Generator
{
206 // expected skin, supplied skin, installed skins
207 yield
'keep validated' => [
209 [ 'skin' => 'example' ],
210 [ 'example', 'foo', 'bar' ]
213 yield
'fallback invalid' => [
215 [ 'skin' => 'not-example' ],
216 [ 'example', 'foo', 'bar' ]
219 yield
'keep anything without validation' => [
221 [ 'skin' => 'not-example' ],
227 * @dataProvider skinsProvider
229 public function testContextWithSkinsValidation(
230 string $expectedSkin, array $suppliedSkin, ?
array $installedSkins
232 $context = new Context(
233 self
::getResourceLoader(), new FauxRequest( $suppliedSkin ), $installedSkins
236 $this->assertSame( $expectedSkin, $context->getSkin() );