Completed
Push — master ( a440d3...fc9fa3 )
by
unknown
08:37 queued 13s
created

testOutputPageBeforeHTMLHookHandlerShouldNotWorkOnNonEntityViewPages()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.6
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Wikibase\Repo\Tests\Hooks;
4
5
use FauxRequest;
6
use Language;
7
use MediaWikiIntegrationTestCase;
8
use OutputPage;
9
use PHPUnit\Framework\MockObject\MockObject;
10
use RequestContext;
11
use Title;
12
use User;
13
use Wikibase\DataModel\Entity\Item;
14
use Wikibase\DataModel\Entity\ItemId;
15
use Wikibase\Lib\EntityFactory;
16
use Wikibase\Lib\LanguageNameLookup;
17
use Wikibase\Lib\StaticContentLanguages;
18
use Wikibase\Lib\Store\EntityRevision;
19
use Wikibase\Lib\Store\EntityRevisionLookup;
20
use Wikibase\Lib\UserLanguageLookup;
21
use Wikibase\Repo\Hooks\Helpers\OutputPageEditability;
22
use Wikibase\Repo\Hooks\Helpers\OutputPageEntityViewChecker;
23
use Wikibase\Repo\Hooks\Helpers\UserPreferredContentLanguagesLookup;
24
use Wikibase\Repo\Hooks\OutputPageBeforeHTMLHookHandler;
25
use Wikibase\Repo\Hooks\OutputPageEntityIdReader;
26
use Wikibase\Repo\ParserOutput\TermboxView;
27
use Wikibase\View\Template\TemplateFactory;
28
29
/**
30
 * @covers \Wikibase\Repo\Hooks\OutputPageBeforeHTMLHookHandler
31
 *
32
 * @group Wikibase
33
 *
34
 * @license GPL-2.0-or-later
35
 * @author Marius Hoch < [email protected] >
36
 */
37
class OutputPageBeforeHTMLHookHandlerTest extends MediaWikiIntegrationTestCase {
38
39
	private $editability;
40
	private $uiLanguageCode;
41
	private $userLanguageLookup;
42
	private $entityRevisionLookup;
43
	private $outputPageEntityIdReader;
44
	private $entityFactory;
45
46
	/**
47
	 * @var ItemId
48
	 */
49
	private $itemId;
50
	private $languageNameLookup;
51
	private $preferredLanguageLookup;
52
53
	/**
54
	 * @var StaticContentLanguages
55
	 */
56
	private $contentLanguages;
57
58
	/**
59
	 * @var bool
60
	 */
61
	private $isExternallyRendered;
62
63
	/**
64
	 * @var MockObject|OutputPageEntityViewChecker
65
	 */
66
	private $entityViewChecker;
67
68
	protected function setUp(): void {
69
		parent::setUp();
70
		$this->itemId = new ItemId( 'Q1' );
71
		$this->uiLanguageCode = 'en';
72
73
		$this->userLanguageLookup = $this->createMock( UserLanguageLookup::class );
74
		$this->contentLanguages = new StaticContentLanguages( [ 'en', 'es', 'ru' ] );
75
		$this->entityRevisionLookup = $this->createMock( EntityRevisionLookup::class );
76
		$this->languageNameLookup = $this->createMock( LanguageNameLookup::class );
77
		$this->outputPageEntityIdReader = $this->createMock( OutputPageEntityIdReader::class );
78
		$this->entityFactory = $this->createMock( EntityFactory::class );
79
		$this->editability = $this->mockEditability();
80
		$this->isExternallyRendered = false;
81
82
		$this->preferredLanguageLookup = $this->createMock( UserPreferredContentLanguagesLookup::class );
83
		$this->preferredLanguageLookup->method( 'getLanguages' )
84
			->willReturn( [ [ $this->uiLanguageCode, 'de', 'es', 'ru' ] ] );
85
86
		$this->entityViewChecker = $this->createMock( OutputPageEntityViewChecker::class );
87
		$this->entityViewChecker->expects( $this->any() )
88
			->method( 'hasEntityView' )
89
			->willReturn( true );
90
	}
91
92
	/**
93
	 * @return OutputPage
94
	 */
95
	private function newOutputPage() {
96
		$mockContext = $this->createMock( RequestContext::class );
97
		$mockContext->method( 'getLanguage' )
98
			->willReturn( Language::factory( $this->uiLanguageCode ) );
99
		$mockContext->method( 'getUser' )->willReturn( new User() );
100
		$mockContext->method( 'getRequest' )->willReturn( new FauxRequest() );
101
		$mockContext->method( 'getConfig' )->willReturn( RequestContext::getMain()->getConfig() );
102
		$outputPage = new OutputPage( $mockContext );
103
		$outputPage->setTitle( $this->createMock( Title::class ) );
104
		$outputPage->setArticleFlag( true );
105
106
		return $outputPage;
107
	}
108
109
	private function getHookHandler() {
110
		return new OutputPageBeforeHTMLHookHandler(
111
			TemplateFactory::getDefaultInstance(),
112
			$this->userLanguageLookup,
113
			$this->contentLanguages,
114
			$this->entityRevisionLookup,
115
			$this->languageNameLookup,
116
			$this->outputPageEntityIdReader,
117
			$this->entityFactory,
118
			'',
119
			$this->editability,
120
			$this->isExternallyRendered,
121
			$this->preferredLanguageLookup,
122
			$this->entityViewChecker
123
		);
124
	}
125
126
	/**
127
	 * Integration test mostly testing that things don't fatal/ throw.
128
	 */
129
	public function testOutputPageBeforeHTMLHookHandler() {
130
		$out = $this->newOutputPage();
131
132
		$this->userLanguageLookup = $this->getUserLanguageLookupReturnsSpecifiedLangs();
133
		$this->languageNameLookup->expects( $this->never() )
134
			->method( 'getName' );
135
136
		$this->outputPageEntityIdReader = $this->getOutputPageEntityIdReaderReturningEntity( $this->itemId );
137
		$this->entityRevisionLookup = $this->getEntityRevisionLookupReturningEntity( $this->itemId );
138
139
		$this->preferredLanguageLookup->expects( $this->once() )
140
			->method( 'getLanguages' )
141
			->with( $this->uiLanguageCode, $out->getUser() )
142
			->willReturn( [ [ $this->uiLanguageCode, 'de', 'es', 'ru' ] ] );
143
144
		$outputPageBeforeHTMLHookHandler = $this->getHookHandler();
145
146
		$html = '';
147
		$out->setTitle( Title::makeTitle( 0, 'OutputPageBeforeHTMLHookHandlerTest' ) );
148
		$out->setProperty(
149
			'wikibase-view-chunks',
150
			[ '$1' => [ 'entityViewPlaceholder-entitytermsview-entitytermsforlanguagelistview-class' ] ]
151
		);
152
		$out->setArticleFlag( true );
153
154
		$outputPageBeforeHTMLHookHandler->onOutputPageBeforeHTML( $out, $html );
155
156
		// Verify the wbUserSpecifiedLanguages JS variable
157
		$jsConfigVars = $out->getJsConfigVars();
158
		$wbUserSpecifiedLanguages = $jsConfigVars['wbUserSpecifiedLanguages'];
159
160
		$this->assertSame( [ 'es', 'ru' ], $wbUserSpecifiedLanguages );
161
	}
162
163
	public function testOutputPageBeforeHTMLHookHandlerShouldNotWorkOnNonEntityViewPages() {
164
		$out = $this->newOutputPage();
165
		$out->setArticleFlag( false );
166
		$this->userLanguageLookup->expects( $this->never() )
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Wikibase\Lib\UserLanguageLookup>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
167
			->method( 'getUserSpecifiedLanguages' );
168
		$this->userLanguageLookup->expects( $this->never() )
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Wikibase\Lib\UserLanguageLookup>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
169
			->method( 'getAllUserLanguages' );
170
171
		$html = '';
172
		$this->entityViewChecker = $this->createMock( OutputPageEntityViewChecker::class );
173
		$this->entityViewChecker->expects( $this->once() )
174
			->method( 'hasEntityView' )
175
			->willReturn( false );
176
177
		$this->getHookHandler()->onOutputPageBeforeHTML( $out, $html );
178
179
		// Verify the wbUserSpecifiedLanguages JS variable
180
		$jsConfigVars = $out->getJsConfigVars();
181
		$this->assertFalse( isset( $jsConfigVars['wbUserSpecifiedLanguages'] ) );
182
	}
183
184
	public function testGivenDeletedRevision_hookHandlerDoesNotFail() {
185
		$this->outputPageEntityIdReader->expects( $this->once() )
186
			->method( 'getEntityIdFromOutputPage' )
187
			->will( $this->returnValue( null ) );
188
189
		$this->userLanguageLookup = $this->getUserLanguageLookupReturnsSpecifiedLangs();
190
191
		$out = $this->newOutputPage();
192
		$out->setProperty( 'wikibase-view-chunks', [ '$1' => [ 'termbox' ] ] );
193
		$out->setArticleFlag( true );
194
195
		$html = '$1';
196
		$this->getHookHandler()->onOutputPageBeforeHTML( $out, $html );
197
		$this->assertSame( '', $html );
198
	}
199
200
	public function testGivenExternallyRenderedMarkup_usesRespectivePlaceholderExpander() {
201
		$this->entityFactory->expects( $this->once() )
202
			->method( 'newEmpty' )
203
			->willReturn( new Item( $this->itemId ) );
204
		$this->userLanguageLookup->expects( $this->once() )
0 ignored issues
show
Bug introduced by
The method expects() does not seem to exist on object<Wikibase\Lib\UserLanguageLookup>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
205
			->method( 'getUserSpecifiedLanguages' )
206
			->will( $this->returnValue( [] ) );
207
		$this->isExternallyRendered = true;
208
209
		$this->outputPageEntityIdReader = $this->getOutputPageEntityIdReaderReturningEntity( $this->itemId );
210
211
		$expectedHtml = '<div>termbox</div>';
212
		$placeholder = '$1';
213
214
		$out = $this->newOutputPage();
215
		$out->setProperty( TermboxView::TERMBOX_MARKUP, $expectedHtml );
216
		$out->setProperty( 'wikibase-view-chunks', [ $placeholder => [ TermboxView::TERMBOX_PLACEHOLDER ] ] );
217
		$out->setArticleFlag( true );
218
219
		$html = $placeholder;
220
		$this->getHookHandler()->onOutputPageBeforeHTML( $out, $html );
221
222
		$this->assertSame( $expectedHtml, $html );
223
	}
224
225
	private function newUserLanguageLookup() {
226
		$userLanguageLookup = $this->createMock( UserLanguageLookup::class );
227
		$userLanguageLookup->expects( $this->any() )
228
			->method( 'getUserSpecifiedLanguages' )
229
			->will( $this->returnValue( [] ) );
230
		$userLanguageLookup->expects( $this->any() )
231
			->method( 'getAllUserLanguages' )
232
			->will( $this->returnValue( [] ) );
233
		return $userLanguageLookup;
234
	}
235
236
	/**
237
	 * @param $itemId
238
	 * @return \PHPUnit\Framework\MockObject\MockObject
239
	 */
240
	private function getOutputPageEntityIdReaderReturningEntity( $itemId ) {
241
		$outputPageEntityIdReader = $this->createMock( OutputPageEntityIdReader::class );
242
		$outputPageEntityIdReader->expects( $this->once() )
243
			->method( 'getEntityIdFromOutputPage' )
244
			->willReturn( $itemId );
245
246
		return $outputPageEntityIdReader;
247
	}
248
249
	/**
250
	 * @param $itemId
251
	 * @return MockObject
252
	 */
253
	private function getEntityRevisionLookupReturningEntity( $itemId ): EntityRevisionLookup {
254
		$entityRevisionLookup = $this->createMock( EntityRevisionLookup::class );
255
		$entityRevisionLookup->expects( $this->once() )
256
			->method( 'getEntityRevision' )
257
			->will( $this->returnValue( new EntityRevision( new Item( $itemId ) ) ) );
258
		return $entityRevisionLookup;
259
	}
260
261
	public function testGivenPageIsEditable_keepsEditButtonsAndRemovesSpecialMarkup() {
262
		$contentBetweenEditLinks = 'hello';
263
		$editLink1 = 'edit link 1';
264
		$editLink2 = 'edit link 2';
265
		$html = "<wb:sectionedit>$editLink1</wb:sectionedit> $contentBetweenEditLinks <wb:sectionedit>$editLink2</wb:sectionedit>";
266
		$out = $this->newOutputPage();
267
		$this->userLanguageLookup = $this->newUserLanguageLookup();
268
269
		$this->getHookHandler()->onOutputPageBeforeHTML( $out, $html );
270
271
		$this->assertEquals( "$editLink1 $contentBetweenEditLinks $editLink2", $html );
272
	}
273
274
	public function testGivenPageIsNotEditable_removesEditButtonsAndSpecialMarkup() {
275
		$contentBetweenEditLinks = 'hello';
276
		$html = "<wb:sectionedit>edit link 1</wb:sectionedit>$contentBetweenEditLinks<wb:sectionedit>edit link 2</wb:sectionedit>";
277
		$out = $this->newOutputPage();
278
		$this->userLanguageLookup = $this->newUserLanguageLookup();
279
		$this->editability = $this->mockEditabilityDismissive();
280
281
		$this->getHookHandler()->onOutputPageBeforeHTML( $out, $html );
282
283
		$this->assertSame( $contentBetweenEditLinks, $html );
284
	}
285
286
	public function testTermboxModulesEnabled() {
287
		$out = $this->newOutputPage();
288
		$this->isExternallyRendered = true;
289
		$this->userLanguageLookup = $this->newUserLanguageLookup();
290
		$html = '';
291
292
		$this->getHookHandler()->onOutputPageBeforeHTML( $out, $html );
293
294
		$this->assertSame( [ 'wikibase.termbox' ], $out->getModules() );
295
		$this->assertSame( [ 'wikibase.termbox.styles' ], $out->getModuleStyles() );
296
	}
297
298
	public function testTermboxModulesDisabled() {
299
		$out = $this->newOutputPage();
300
		$this->isExternallyRendered = false;
301
		$this->userLanguageLookup = $this->newUserLanguageLookup();
302
		$html = '';
303
304
		$this->getHookHandler()->onOutputPageBeforeHTML( $out, $html );
305
306
		$this->assertSame( [], $out->getModules() );
307
		$this->assertSame( [], $out->getModuleStyles() );
308
	}
309
310
	private function mockEditability( $permissive = true ) {
311
		$editability = $this->createMock( OutputPageEditability::class );
312
		$editability->method( 'validate' )->willReturn( $permissive );
313
		return $editability;
314
	}
315
316
	private function mockEditabilityDismissive() {
317
		return $this->mockEditability( false );
318
	}
319
320
	private function getUserLanguageLookupReturnsSpecifiedLangs() : UserLanguageLookup {
321
		$userLanguageLookup = $this->createMock( UserLanguageLookup::class );
322
		$userLanguageLookup->expects( $this->once() )
323
			->method( 'getUserSpecifiedLanguages' )
324
			->will( $this->returnValue( [ 'de', 'es', 'ru' ] ) );
325
		return $userLanguageLookup;
326
	}
327
328
}
329