Completed
Push — eslint-bump ( 58178a )
by Sam
09:57
created

RequirementsTest::assertFileNotIncluded()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 24
Code Lines 18

Duplication

Lines 24
Ratio 100 %

Importance

Changes 0
Metric Value
cc 4
eloc 18
nc 4
nop 3
dl 24
loc 24
rs 8.6845
c 0
b 0
f 0
1
<?php
2
3
use SilverStripe\Core\Injector\Injector;
4
use SilverStripe\Dev\SapphireTest;
5
use SilverStripe\Control\Director;
6
use SilverStripe\View\Requirements;
7
use SilverStripe\View\ArrayData;
8
9
10
11
12
/**
13
 * @package framework
14
 * @subpackage tests
15
 *
16
 * @todo Test that order of combine_files() is correct
17
 * @todo Figure out how to clear the modified state of Requirements class - might affect other tests.
18
 */
19
class RequirementsTest extends SapphireTest {
20
21
	static $html_template = '<html><head></head><body></body></html>';
22
23
	public function setUp() {
24
		parent::setUp();
25
		AssetStoreTest_SpyStore::activate('RequirementsTest'); // Set backend root to /RequirementsTest
26
	}
27
28
	public function tearDown() {
29
		AssetStoreTest_SpyStore::reset();
30
		parent::tearDown();
31
	}
32
33
	public function testExternalUrls() {
34
		/** @var Requirements_Backend $backend */
35
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
36
		$backend->setCombinedFilesEnabled(true);
37
38
		$backend->javascript('http://www.mydomain.com/test.js');
39
		$backend->javascript('https://www.mysecuredomain.com/test.js');
40
		$backend->javascript('//scheme-relative.example.com/test.js');
41
		$backend->css('http://www.mydomain.com/test.css');
42
		$backend->css('https://www.mysecuredomain.com/test.css');
43
		$backend->css('//scheme-relative.example.com/test.css');
44
45
		$html = $backend->includeInHTML(self::$html_template);
46
47
		$this->assertTrue(
48
			(strpos($html, 'http://www.mydomain.com/test.js') !== false),
49
			'Load external javascript URL'
50
		);
51
		$this->assertTrue(
52
			(strpos($html, 'https://www.mysecuredomain.com/test.js') !== false),
53
			'Load external secure javascript URL'
54
		);
55
		$this->assertTrue(
56
			(strpos($html, '//scheme-relative.example.com/test.js') !== false),
57
			'Load external scheme-relative javascript URL'
58
		);
59
		$this->assertTrue(
60
			(strpos($html, 'http://www.mydomain.com/test.css') !== false),
61
			'Load external CSS URL'
62
		);
63
		$this->assertTrue(
64
			(strpos($html, 'https://www.mysecuredomain.com/test.css') !== false),
65
			'Load external secure CSS URL'
66
		);
67
		$this->assertTrue(
68
			(strpos($html, '//scheme-relative.example.com/test.css') !== false),
69
			'Load scheme-relative CSS URL'
70
		);
71
	}
72
73
	/**
74
	 * Setup new backend
75
	 *
76
	 * @param Requirements_Backend $backend
77
	 */
78
	protected function setupRequirements($backend) {
79
		// Flush requirements
80
		$backend->clear();
81
		$backend->clearCombinedFiles();
82
		$backend->setCombinedFilesFolder('_combinedfiles');
83
		$backend->setMinifyCombinedJSFiles(false);
84
		Requirements::flush();
85
	}
86
87
	/**
88
	 * Setup combined and non-combined js with the backend
89
	 *
90
	 * @param Requirements_Backend $backend
91
	 */
92
	protected function setupCombinedRequirements($backend) {
93
		$basePath = $this->getCurrentRelativePath();
94
		$this->setupRequirements($backend);
95
96
		// require files normally (e.g. called from a FormField instance)
97
		$backend->javascript($basePath . '/RequirementsTest_a.js');
98
		$backend->javascript($basePath . '/RequirementsTest_b.js');
99
		$backend->javascript($basePath . '/RequirementsTest_c.js');
100
101
		// require two of those files as combined includes
102
		$backend->combineFiles(
103
			'RequirementsTest_bc.js',
104
			array(
105
				$basePath . '/RequirementsTest_b.js',
106
				$basePath . '/RequirementsTest_c.js'
107
			)
108
		);
109
	}
110
111
	/**
112
	 * Setup combined files with the backend
113
	 *
114
	 * @param Requirements_Backend $backend
115
	 */
116
	protected function setupCombinedNonrequiredRequirements($backend) {
117
		$basePath = $this->getCurrentRelativePath();
118
		$this->setupRequirements($backend);
119
120
		// require files as combined includes
121
		$backend->combineFiles(
122
			'RequirementsTest_bc.js',
123
			array(
124
				$basePath . '/RequirementsTest_b.js',
125
				$basePath . '/RequirementsTest_c.js'
126
			)
127
		);
128
	}
129
130
	protected function setupCombinedRequirementsJavascriptAsyncDefer($backend, $async, $defer) {
131
        $basePath = $this->getCurrentRelativePath();
132
        $this->setupRequirements($backend);
133
134
        // require files normally (e.g. called from a FormField instance)
135
        $backend->javascript($basePath . '/RequirementsTest_a.js');
136
        $backend->javascript($basePath . '/RequirementsTest_b.js');
137
        $backend->javascript($basePath . '/RequirementsTest_c.js');
138
139
        // require two of those files as combined includes
140
        $backend->combineFiles(
141
            'RequirementsTest_bc.js',
142
            array(
143
                $basePath . '/RequirementsTest_b.js',
144
                $basePath . '/RequirementsTest_c.js'
145
            ),
146
            array(
147
                'async' => $async,
148
                'defer' => $defer,
149
            )
150
        );
151
    }
152
153 View Code Duplication
    public function testCustomType() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
154
		/** @var Requirements_Backend $backend */
155
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
156
		$basePath = $this->getCurrentRelativePath();
157
		$this->setupRequirements($backend);
158
159
		// require files normally (e.g. called from a FormField instance)
160
		$backend->javascript($basePath . '/RequirementsTest_a.js', [
161
			'type' => 'application/json'
162
		]);
163
		$backend->javascript($basePath . '/RequirementsTest_b.js');
164
		$result = $backend->includeInHTML(self::$html_template);
165
		$this->assertRegexp(
166
			'#<script type="application/json" src=".*/tests/forms/RequirementsTest_a.js#',
167
			$result
168
		);
169
		$this->assertRegexp(
170
			'#<script type="application/javascript" src=".*/tests/forms/RequirementsTest_b.js#',
171
			$result
172
		);
173
	}
174
175
	public function testCombinedJavascript() {
176
		/** @var Requirements_Backend $backend */
177
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
178
		$this->setupCombinedRequirements($backend);
179
180
		$combinedFileName = '/_combinedfiles/RequirementsTest_bc-2a55d56.js';
181
		$combinedFilePath = AssetStoreTest_SpyStore::base_path() . $combinedFileName;
182
183
		$html = $backend->includeInHTML(self::$html_template);
184
185
		/* COMBINED JAVASCRIPT FILE IS INCLUDED IN HTML HEADER */
186
		$this->assertRegExp(
187
			'/src=".*' . preg_quote($combinedFileName, '/') . '/',
188
			$html,
189
			'combined javascript file is included in html header'
190
		);
191
192
		/* COMBINED JAVASCRIPT FILE EXISTS */
193
		$this->assertTrue(
194
			file_exists($combinedFilePath),
195
			'combined javascript file exists'
196
		);
197
198
		/* COMBINED JAVASCRIPT HAS CORRECT CONTENT */
199
		$this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false),
200
			'combined javascript has correct content');
201
		$this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false),
202
			'combined javascript has correct content');
203
204
		/* COMBINED FILES ARE NOT INCLUDED TWICE */
205
		$this->assertNotRegExp(
206
			'/src=".*\/RequirementsTest_b\.js/',
207
			$html,
208
			'combined files are not included twice'
209
		);
210
		$this->assertNotRegExp(
211
			'/src=".*\/RequirementsTest_c\.js/',
212
			$html,
213
			'combined files are not included twice'
214
		);
215
216
		/* NORMAL REQUIREMENTS ARE STILL INCLUDED */
217
		$this->assertRegExp(
218
			'/src=".*\/RequirementsTest_a\.js/',
219
			$html,
220
			'normal requirements are still included'
221
		);
222
223
		// Then do it again, this time not requiring the files beforehand
224
		unlink($combinedFilePath);
225
		/** @var Requirements_Backend $backend */
226
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
227
		$this->setupCombinedNonrequiredRequirements($backend);
228
		$html = $backend->includeInHTML(self::$html_template);
229
230
		/* COMBINED JAVASCRIPT FILE IS INCLUDED IN HTML HEADER */
231
		$this->assertRegExp(
232
			'/src=".*' . preg_quote($combinedFileName, '/') . '/',
233
			$html,
234
			'combined javascript file is included in html header'
235
		);
236
237
		/* COMBINED JAVASCRIPT FILE EXISTS */
238
		$this->assertTrue(
239
			file_exists($combinedFilePath),
240
			'combined javascript file exists'
241
		);
242
243
		/* COMBINED JAVASCRIPT HAS CORRECT CONTENT */
244
		$this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false),
245
			'combined javascript has correct content');
246
		$this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false),
247
			'combined javascript has correct content');
248
249
		/* COMBINED FILES ARE NOT INCLUDED TWICE */
250
		$this->assertNotRegExp(
251
			'/src=".*\/RequirementsTest_b\.js/',
252
			$html,
253
			'combined files are not included twice'
254
		);
255
		$this->assertNotRegExp(
256
			'/src=".*\/RequirementsTest_c\.js/',
257
			$html,
258
			'combined files are not included twice'
259
		);
260
	}
261
262
	public function testCombinedJavascriptAsyncDefer() {
263
	    /** @var Requirements_Backend $backend */
264
	    $backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
265
266
	    $this->setupCombinedRequirementsJavascriptAsyncDefer($backend, true, false);
267
268
	    $combinedFileName = '/_combinedfiles/RequirementsTest_bc-2a55d56.js';
269
	    $combinedFilePath = AssetStoreTest_SpyStore::base_path() . $combinedFileName;
270
271
	    $html = $backend->includeInHTML(false, self::$html_template);
272
273
	    /* ASYNC IS INCLUDED IN SCRIPT TAG */
274
	    $this->assertRegExp(
275
	        '/src=".*' . preg_quote($combinedFileName, '/') . '" async/',
276
	        $html,
277
	        'async is included in script tag'
278
	    );
279
280
	    /* DEFER IS NOT INCLUDED IN SCRIPT TAG */
281
	    $this->assertNotContains('defer', $html, 'defer is not included');
282
283
	    /* COMBINED JAVASCRIPT FILE EXISTS */
284
	    clearstatcache(); // needed to get accurate file_exists() results
285
	    $this->assertFileExists($combinedFilePath,
286
	        'combined javascript file exists');
287
288
	    /* COMBINED JAVASCRIPT HAS CORRECT CONTENT */
289
	    $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false),
290
	        'combined javascript has correct content');
291
	    $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false),
292
	        'combined javascript has correct content');
293
294
	    /* COMBINED FILES ARE NOT INCLUDED TWICE */
295
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_b\.js/', $html,
296
	        'combined files are not included twice');
297
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_c\.js/', $html,
298
	        'combined files are not included twice');
299
300
	    /* NORMAL REQUIREMENTS ARE STILL INCLUDED */
301
	    $this->assertRegExp('/src=".*\/RequirementsTest_a\.js/', $html,
302
	        'normal requirements are still included');
303
304
	    /* NORMAL REQUIREMENTS DON'T HAVE ASYNC/DEFER */
305
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async/', $html,
306
	        'normal requirements don\'t have async');
307
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" defer/', $html,
308
	        'normal requirements don\'t have defer');
309
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async defer/', $html,
310
	        'normal requirements don\'t have async/defer');
311
312
	    // setup again for testing defer
313
	    unlink($combinedFilePath);
314
	    /** @var Requirements_Backend $backend */
315
	    $backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
316
317
	    $this->setupCombinedRequirementsJavascriptAsyncDefer($backend, false, true);
318
319
	    $html = $backend->includeInHTML(self::$html_template);
320
321
	    /* DEFER IS INCLUDED IN SCRIPT TAG */
322
	    $this->assertRegExp(
323
	        '/src=".*' . preg_quote($combinedFileName, '/') . '" defer/',
324
	        $html,
325
	        'defer is included in script tag'
326
	    );
327
328
	    /* ASYNC IS NOT INCLUDED IN SCRIPT TAG */
329
	    $this->assertNotContains('async', $html, 'async is not included');
330
331
	    /* COMBINED JAVASCRIPT FILE EXISTS */
332
	    clearstatcache(); // needed to get accurate file_exists() results
333
	    $this->assertFileExists($combinedFilePath,
334
	        'combined javascript file exists');
335
336
	    /* COMBINED JAVASCRIPT HAS CORRECT CONTENT */
337
	    $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false),
338
	        'combined javascript has correct content');
339
	    $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false),
340
	        'combined javascript has correct content');
341
342
	    /* COMBINED FILES ARE NOT INCLUDED TWICE */
343
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_b\.js/', $html,
344
	        'combined files are not included twice');
345
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_c\.js/', $html,
346
	        'combined files are not included twice');
347
348
	    /* NORMAL REQUIREMENTS ARE STILL INCLUDED */
349
	    $this->assertRegExp('/src=".*\/RequirementsTest_a\.js/', $html,
350
	        'normal requirements are still included');
351
352
	    /* NORMAL REQUIREMENTS DON'T HAVE ASYNC/DEFER */
353
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async/', $html,
354
	        'normal requirements don\'t have async');
355
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" defer/', $html,
356
	        'normal requirements don\'t have defer');
357
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async defer/', $html,
358
	        'normal requirements don\'t have async/defer');
359
360
	    // setup again for testing async and defer
361
	    unlink($combinedFilePath);
362
	    /** @var Requirements_Backend $backend */
363
	    $backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
364
365
	    $this->setupCombinedRequirementsJavascriptAsyncDefer($backend, true, true);
366
367
	    $html = $backend->includeInHTML(self::$html_template);
368
369
	    /* ASYNC/DEFER IS INCLUDED IN SCRIPT TAG */
370
	    $this->assertRegExp(
371
	        '/src=".*' . preg_quote($combinedFileName, '/') . '" async defer/',
372
	        $html,
373
	        'async and defer are included in script tag'
374
	    );
375
376
	    /* COMBINED JAVASCRIPT FILE EXISTS */
377
	    clearstatcache(); // needed to get accurate file_exists() results
378
	    $this->assertFileExists($combinedFilePath,
379
	        'combined javascript file exists');
380
381
	    /* COMBINED JAVASCRIPT HAS CORRECT CONTENT */
382
	    $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false),
383
	        'combined javascript has correct content');
384
	    $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false),
385
	        'combined javascript has correct content');
386
387
	    /* COMBINED FILES ARE NOT INCLUDED TWICE */
388
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_b\.js/', $html,
389
	        'combined files are not included twice');
390
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_c\.js/', $html,
391
	        'combined files are not included twice');
392
393
	    /* NORMAL REQUIREMENTS ARE STILL INCLUDED */
394
	    $this->assertRegExp('/src=".*\/RequirementsTest_a\.js/', $html,
395
	        'normal requirements are still included');
396
397
	    /* NORMAL REQUIREMENTS DON'T HAVE ASYNC/DEFER */
398
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async/', $html,
399
	        'normal requirements don\'t have async');
400
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" defer/', $html,
401
	        'normal requirements don\'t have defer');
402
	    $this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async defer/', $html,
403
	        'normal requirements don\'t have async/defer');
404
405
	    unlink($combinedFilePath);
406
	}
407
408
	public function testCombinedCss() {
409
		$basePath = $this->getCurrentRelativePath();
410
		/** @var Requirements_Backend $backend */
411
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
412
		$this->setupRequirements($backend);
413
414
		$backend->combineFiles(
415
			'print.css',
416
			array(
417
				$basePath . '/RequirementsTest_print_a.css',
418
				$basePath . '/RequirementsTest_print_b.css'
419
			),
420
			array(
421
			    'media' => 'print'
422
			)
423
		);
424
425
		$html = $backend->includeInHTML(self::$html_template);
426
427
		$this->assertRegExp(
428
			'/href=".*\/print\-94e723d\.css/',
429
			$html,
430
			'Print stylesheets have been combined.'
431
		);
432
		$this->assertRegExp(
433
			'/media="print/',
434
			$html,
435
			'Combined print stylesheet retains the media parameter'
436
		);
437
438
		// Test that combining a file multiple times doesn't trigger an error
439
		/** @var Requirements_Backend $backend */
440
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
441
		$this->setupRequirements($backend);
442
		$backend->combineFiles(
443
			'style.css',
444
			array(
445
				$basePath . '/RequirementsTest_b.css',
446
				$basePath . '/RequirementsTest_c.css'
447
			)
448
		);
449
		$backend->combineFiles(
450
			'style.css',
451
			array(
452
				$basePath . '/RequirementsTest_b.css',
453
				$basePath . '/RequirementsTest_c.css'
454
			)
455
		);
456
457
		$html = $backend->includeInHTML(self::$html_template);
458
		$this->assertRegExp(
459
			'/href=".*\/style\-bcd90f5\.css/',
460
			$html,
461
			'Stylesheets have been combined.'
462
		);
463
	}
464
465
	public function testBlockedCombinedJavascript() {
466
		$basePath = $this->getCurrentRelativePath();
467
		/** @var Requirements_Backend $backend */
468
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
469
		$this->setupCombinedRequirements($backend);
470
		$combinedFileName = '/_combinedfiles/RequirementsTest_bc-2a55d56.js';
471
		$combinedFilePath = AssetStoreTest_SpyStore::base_path() . $combinedFileName;
472
473
		/* BLOCKED COMBINED FILES ARE NOT INCLUDED */
474
		$backend->block('RequirementsTest_bc.js');
475
476
		clearstatcache(); // needed to get accurate file_exists() results
477
		$html = $backend->includeInHTML(self::$html_template);
478
		$this->assertFileNotExists($combinedFilePath);
479
		$this->assertNotRegExp(
480
			'/src=".*\/RequirementsTest_bc\.js/',
481
			$html,
482
			'blocked combined files are not included'
483
		);
484
		$backend->unblock('RequirementsTest_bc.js');
485
486
		/* BLOCKED UNCOMBINED FILES ARE NOT INCLUDED */
487
		$this->setupCombinedRequirements($backend);
488
		$backend->block($basePath .'/RequirementsTest_b.js');
489
		$combinedFileName2 = '/_combinedfiles/RequirementsTest_bc-3748f67.js'; // SHA1 without file b included
490
		$combinedFilePath2 = AssetStoreTest_SpyStore::base_path() . $combinedFileName2;
491
		clearstatcache(); // needed to get accurate file_exists() results
492
		$html = $backend->includeInHTML(self::$html_template);
0 ignored issues
show
Unused Code introduced by
$html is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
493
		$this->assertFileExists($combinedFilePath2);
494
		$this->assertTrue(
495
			strpos(file_get_contents($combinedFilePath2), "alert('b')") === false,
496
			'blocked uncombined files are not included'
497
		);
498
		$backend->unblock($basePath . '/RequirementsTest_b.js');
499
500
		/* A SINGLE FILE CAN'T BE INCLUDED IN TWO COMBINED FILES */
501
		$this->setupCombinedRequirements($backend);
502
		clearstatcache(); // needed to get accurate file_exists() results
503
504
		// Exception generated from including invalid file
505
		$this->setExpectedException(
506
			'InvalidArgumentException',
507
			sprintf(
508
				"Requirements_Backend::combine_files(): Already included file(s) %s in combined file '%s'",
509
				$basePath . '/RequirementsTest_c.js',
510
				'RequirementsTest_bc.js'
511
			)
512
		);
513
		$backend->combineFiles(
514
			'RequirementsTest_ac.js',
515
			array(
516
				$basePath . '/RequirementsTest_a.js',
517
				$basePath . '/RequirementsTest_c.js'
518
			)
519
		);
520
	}
521
522 View Code Duplication
	public function testArgsInUrls() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
523
		$basePath = $this->getCurrentRelativePath();
524
525
		/** @var Requirements_Backend $backend */
526
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
527
		$this->setupRequirements($backend);
528
529
		$backend->javascript($basePath . '/RequirementsTest_a.js?test=1&test=2&test=3');
530
		$backend->css($basePath . '/RequirementsTest_a.css?test=1&test=2&test=3');
531
		$html = $backend->includeInHTML(self::$html_template);
532
533
		/* Javascript has correct path */
534
		$this->assertRegExp(
535
			'/src=".*\/RequirementsTest_a\.js\?m=\d\d+&amp;test=1&amp;test=2&amp;test=3/',
536
			$html,
537
			'javascript has correct path'
538
		);
539
540
		/* CSS has correct path */
541
		$this->assertRegExp(
542
			'/href=".*\/RequirementsTest_a\.css\?m=\d\d+&amp;test=1&amp;test=2&amp;test=3/',
543
			$html,
544
			'css has correct path'
545
		);
546
	}
547
548
	public function testRequirementsBackend() {
549
		$basePath = $this->getCurrentRelativePath();
550
551
		/** @var Requirements_Backend $backend */
552
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
553
		$this->setupRequirements($backend);
554
		$backend->javascript($basePath . '/a.js');
555
556
		$this->assertTrue(count($backend->getJavascript()) == 1,
557
			"There should be only 1 file included in required javascript.");
558
		$this->assertArrayHasKey($basePath . '/a.js', $backend->getJavascript(),
559
			"a.js should be included in required javascript.");
560
561
		$backend->javascript($basePath . '/b.js');
562
		$this->assertTrue(count($backend->getJavascript()) == 2,
563
			"There should be 2 files included in required javascript.");
564
565
		$backend->block($basePath . '/a.js');
566
		$this->assertTrue(count($backend->getJavascript()) == 1,
567
			"There should be only 1 file included in required javascript.");
568
		$this->assertArrayNotHasKey($basePath . '/a.js', $backend->getJavascript(),
569
			"a.js should not be included in required javascript after it has been blocked.");
570
		$this->assertArrayHasKey($basePath . '/b.js', $backend->getJavascript(),
571
			"b.js should be included in required javascript.");
572
573
		$backend->css($basePath . '/a.css');
574
		$this->assertTrue(count($backend->getCSS()) == 1,
575
			"There should be only 1 file included in required css.");
576
		$this->assertArrayHasKey($basePath . '/a.css', $backend->getCSS(),
577
			"a.css should be in required css.");
578
579
		$backend->block($basePath . '/a.css');
580
		$this->assertTrue(count($backend->getCSS()) == 0,
581
			"There should be nothing in required css after file has been blocked.");
582
	}
583
584
	public function testConditionalTemplateRequire() {
585
		$testPath = ltrim(preg_replace('#^' . BASE_PATH . '#', '', dirname(__DIR__)), '/');
586
587
		/** @var Requirements_Backend $backend */
588
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
589
		$this->setupRequirements($backend);
590
		$holder = Requirements::backend();
591
		Requirements::set_backend($backend);
592
		$data = new ArrayData(array(
593
			'FailTest' => true,
594
		));
595
		$data->renderWith('RequirementsTest_Conditionals');
596
		$this->assertFileIncluded($backend, 'css', $testPath .'/css/forms/RequirementsTest_a.css');
597
		$this->assertFileIncluded($backend, 'js',
598
			array(
599
				$testPath .'/javascript/forms/RequirementsTest_b.js',
600
				$testPath .'/javascript/forms/RequirementsTest_c.js'
601
			)
602
		);
603
		$this->assertFileNotIncluded($backend, 'js', $testPath .'/javascript/forms/RequirementsTest_a.js');
604
		$this->assertFileNotIncluded($backend, 'css',
605
			array(
606
				$testPath .'/css/forms/RequirementsTest_b.css',
607
				$testPath .'/css/forms/RequirementsTest_c.css'
608
			)
609
		);
610
		$backend->clear();
611
		$data = new ArrayData(array(
612
			'FailTest' => false,
613
		));
614
		$data->renderWith('RequirementsTest_Conditionals');
615
		$this->assertFileNotIncluded($backend, 'css', $testPath .'/css/forms/RequirementsTest_a.css');
616
		$this->assertFileNotIncluded($backend, 'js',
617
			array(
618
				$testPath .'/javascript/forms/RequirementsTest_b.js',
619
				$testPath .'/javascript/forms/RequirementsTest_c.js'
620
			)
621
		);
622
		$this->assertFileIncluded($backend, 'js', $testPath .'/javascript/forms/RequirementsTest_a.js');
623
		$this->assertFileIncluded($backend, 'css',
624
			array(
625
				$testPath .'/css/forms/RequirementsTest_b.css',
626
				$testPath .'/css/forms/RequirementsTest_c.css'
627
			)
628
		);
629
		Requirements::set_backend($holder);
630
	}
631
632
	public function testJsWriteToBody() {
633
		/** @var Requirements_Backend $backend */
634
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
635
		$this->setupRequirements($backend);
636
		$backend->javascript('http://www.mydomain.com/test.js');
637
638
		// Test matching with HTML5 <header> tags as well
639
		$template = '<html><head></head><body><header>My header</header><p>Body</p></body></html>';
640
641
		$backend->setWriteJavascriptToBody(false);
642
		$html = $backend->includeInHTML($template);
643
		$this->assertContains('<head><script', $html);
644
645
		$backend->setWriteJavascriptToBody(true);
646
		$html = $backend->includeInHTML($template);
647
		$this->assertNotContains('<head><script', $html);
648
		$this->assertContains('</script></body>', $html);
649
	}
650
651
	public function testIncludedJsIsNotCommentedOut() {
652
		$template = '<html><head></head><body><!--<script>alert("commented out");</script>--></body></html>';
653
		/** @var Requirements_Backend $backend */
654
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
655
		$this->setupRequirements($backend);
656
		$backend->javascript($this->getCurrentRelativePath() . '/RequirementsTest_a.js');
657
		$html = $backend->includeInHTML($template);
658
		//wiping out commented-out html
659
		$html = preg_replace('/<!--(.*)-->/Uis', '', $html);
660
		$this->assertContains("RequirementsTest_a.js", $html);
661
	}
662
663
	public function testCommentedOutScriptTagIsIgnored() {
664
		$template = '<html><head></head><body><!--<script>alert("commented out");</script>-->'
665
			. '<h1>more content</h1></body></html>';
666
		/** @var Requirements_Backend $backend */
667
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
668
		$this->setupRequirements($backend);
669
		$backend->setSuffixRequirements(false);
670
		$src = $this->getCurrentRelativePath() . '/RequirementsTest_a.js';
671
		$urlSrc = ControllerTest_ContainerController::join_links(Director::baseURL(), $src);
672
		$backend->javascript($src);
673
		$html = $backend->includeInHTML($template);
674
		$this->assertEquals('<html><head></head><body><!--<script>alert("commented out");</script>-->'
675
			. '<h1>more content</h1><script type="application/javascript" src="' . $urlSrc . '"></script></body></html>', $html);
676
	}
677
678
	public function testForceJsToBottom() {
679
		/** @var Requirements_Backend $backend */
680
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
681
		$this->setupRequirements($backend);
682
		$backend->javascript('http://www.mydomain.com/test.js');
683
		$backend->customScript(
684
<<<'EOS'
685
var globalvar = {
686
	pattern: '\\$custom\\1'
687
};
688
EOS
689
		);
690
691
		// Test matching with HTML5 <header> tags as well
692
		$template = '<html><head></head><body><header>My header</header><p>Body<script></script></p></body></html>';
693
694
		// The expected outputs
695
		$expectedScripts = "<script type=\"application/javascript\" src=\"http://www.mydomain.com/test.js\">"
696
			. "</script><script type=\"application/javascript\">//<![CDATA[\n"
697
			. "var globalvar = {\n\tpattern: '\\\\\$custom\\\\1'\n};\n"
698
			. "//]]></script>";
699
		$JsInHead = "<html><head>$expectedScripts</head><body><header>My header</header><p>Body<script></script></p></body></html>";
700
		$JsInBody = "<html><head></head><body><header>My header</header><p>Body$expectedScripts<script></script></p></body></html>";
701
		$JsAtEnd  = "<html><head></head><body><header>My header</header><p>Body<script></script></p>$expectedScripts</body></html>";
702
703
704
		// Test if the script is before the head tag, not before the body.
705
		// Expected: $JsInHead
706
		$backend->setWriteJavascriptToBody(false);
707
		$backend->setForceJSToBottom(false);
708
		$html = $backend->includeInHTML($template);
709
		$this->assertNotEquals($JsInBody, $html);
710
		$this->assertNotEquals($JsAtEnd, $html);
711
		$this->assertEquals($JsInHead, $html);
712
713
		// Test if the script is before the first <script> tag, not before the body.
714
		// Expected: $JsInBody
715
		$backend->setWriteJavascriptToBody(true);
716
		$backend->setForceJSToBottom(false);
717
		$html = $backend->includeInHTML($template);
718
		$this->assertNotEquals($JsAtEnd, $html);
719
		$this->assertEquals($JsInBody, $html);
720
721
		// Test if the script is placed just before the closing bodytag, with write-to-body false.
722
		// Expected: $JsAtEnd
723
		$backend->setWriteJavascriptToBody(false);
724
		$backend->setForceJSToBottom(true);
725
		$html = $backend->includeInHTML($template);
726
		$this->assertNotEquals($JsInHead, $html);
727
		$this->assertNotEquals($JsInBody, $html);
728
		$this->assertEquals($JsAtEnd, $html);
729
730
		// Test if the script is placed just before the closing bodytag, with write-to-body true.
731
		// Expected: $JsAtEnd
732
		$backend->setWriteJavascriptToBody(true);
733
		$backend->setForceJSToBottom(true);
734
		$html = $backend->includeInHTML($template);
735
		$this->assertNotEquals($JsInHead, $html);
736
		$this->assertNotEquals($JsInBody, $html);
737
		$this->assertEquals($JsAtEnd, $html);
738
	}
739
740
	public function testSuffix() {
741
		$template = '<html><head></head><body><header>My header</header><p>Body</p></body></html>';
742
		$basePath = $this->getCurrentRelativePath();
743
744
		/** @var Requirements_Backend $backend */
745
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
746
		$this->setupRequirements($backend);
747
748
		$backend->javascript($basePath .'/RequirementsTest_a.js');
749
		$backend->javascript($basePath .'/RequirementsTest_b.js?foo=bar&bla=blubb');
750
		$backend->css($basePath .'/RequirementsTest_a.css');
751
		$backend->css($basePath .'/RequirementsTest_b.css?foo=bar&bla=blubb');
752
753
		$backend->setSuffixRequirements(true);
754
		$html = $backend->includeInHTML($template);
755
		$this->assertRegexp('/RequirementsTest_a\.js\?m=[\d]*"/', $html);
756
		$this->assertRegexp('/RequirementsTest_b\.js\?m=[\d]*&amp;foo=bar&amp;bla=blubb"/', $html);
757
		$this->assertRegexp('/RequirementsTest_a\.css\?m=[\d]*"/', $html);
758
		$this->assertRegexp('/RequirementsTest_b\.css\?m=[\d]*&amp;foo=bar&amp;bla=blubb"/', $html);
759
760
		$backend->setSuffixRequirements(false);
761
		$html = $backend->includeInHTML($template);
762
		$this->assertNotContains('RequirementsTest_a.js=', $html);
763
		$this->assertNotRegexp('/RequirementsTest_a\.js\?m=[\d]*"/', $html);
764
		$this->assertNotRegexp('/RequirementsTest_b\.js\?m=[\d]*&amp;foo=bar&amp;bla=blubb"/', $html);
765
		$this->assertNotRegexp('/RequirementsTest_a\.css\?m=[\d]*"/', $html);
766
		$this->assertNotRegexp('/RequirementsTest_b\.css\?m=[\d]*&amp;foo=bar&amp;bla=blubb"/', $html);
767
	}
768
769
	/**
770
	 * Tests that provided files work
771
	 */
772
	public function testProvidedFiles() {
773
		/** @var Requirements_Backend $backend */
774
		$template = '<html><head></head><body><header>My header</header><p>Body</p></body></html>';
775
		$basePath = $this->getCurrentRelativePath();
776
777
		// Test that provided files block subsequent files
778
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
779
		$this->setupRequirements($backend);
780
		$backend->javascript($basePath . '/RequirementsTest_a.js');
781
		$backend->javascript($basePath . '/RequirementsTest_b.js', [
782
			'provides' => [
783
				$basePath . '/RequirementsTest_a.js',
784
				$basePath . '/RequirementsTest_c.js'
785
			]
786
		]);
787
		$backend->javascript($basePath . '/RequirementsTest_c.js');
788
		// Note that _a.js isn't considered provided because it was included
789
		// before it was marked as provided
790
		$this->assertEquals([
791
			$basePath . '/RequirementsTest_c.js' => $basePath . '/RequirementsTest_c.js'
792
		], $backend->getProvidedScripts());
793
		$html = $backend->includeInHTML($template);
794
		$this->assertRegExp('/src=".*\/RequirementsTest_a\.js/', $html);
795
		$this->assertRegExp('/src=".*\/RequirementsTest_b\.js/', $html);
796
		$this->assertNotRegExp('/src=".*\/RequirementsTest_c\.js/', $html);
797
798
		// Test that provided files block subsequent combined files
799
		$backend = Injector::inst()->create('SilverStripe\\View\\Requirements_Backend');
800
		$this->setupRequirements($backend);
801
		$backend->combineFiles('combined_a.js', [$basePath . '/RequirementsTest_a.js']);
802
		$backend->javascript($basePath . '/RequirementsTest_b.js', [
803
			'provides' => [
804
				$basePath . '/RequirementsTest_a.js',
805
				$basePath . '/RequirementsTest_c.js'
806
			]
807
		]);
808
		$backend->combineFiles('combined_c.js', [$basePath . '/RequirementsTest_c.js']);
809
		$this->assertEquals([
810
			$basePath . '/RequirementsTest_c.js' => $basePath . '/RequirementsTest_c.js'
811
		], $backend->getProvidedScripts());
812
		$html = $backend->includeInHTML($template);
813
		$this->assertRegExp('/src=".*\/combined_a/', $html);
814
		$this->assertRegExp('/src=".*\/RequirementsTest_b\.js/', $html);
815
		$this->assertNotRegExp('/src=".*\/combined_c/', $html);
816
		$this->assertNotRegExp('/src=".*\/RequirementsTest_c\.js/', $html);
817
	}
818
819
	/**
820
	 * Verify that the given backend includes the given files
821
	 *
822
	 * @param Requirements_Backend $backend
823
	 * @param string $type js or css
824
	 * @param array|string $files Files or list of files to check
825
	 */
826 View Code Duplication
	public function assertFileIncluded($backend, $type, $files) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
827
		$includedFiles = $this->getBackendFiles($backend, $type);
828
829
		if(is_array($files)) {
830
			$failedMatches = array();
831
			foreach ($files as $file) {
832
				if(!array_key_exists($file, $includedFiles)) {
833
					$failedMatches[] = $file;
834
				}
835
			}
836
			$this->assertTrue(
837
				(count($failedMatches) == 0),
838
				"Failed asserting the $type files '"
839
				. implode("', '", $failedMatches)
840
				. "' have exact matches in the required elements:\n'"
841
				. implode("'\n'", array_keys($includedFiles)) . "'"
842
			);
843
		} else {
844
			$this->assertTrue(
845
				(array_key_exists($files, $includedFiles)),
846
				"Failed asserting the $type file '$files' has an exact match in the required elements:\n'"
847
				. implode("'\n'", array_keys($includedFiles)) . "'"
848
			);
849
		}
850
	}
851
852 View Code Duplication
	public function assertFileNotIncluded($backend, $type, $files) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
853
		$includedFiles = $this->getBackendFiles($backend, $type);
854
		if(is_array($files)) {
855
			$failedMatches = array();
856
			foreach ($files as $file) {
857
				if(array_key_exists($file, $includedFiles)) {
858
					$failedMatches[] = $file;
859
				}
860
			}
861
			$this->assertTrue(
862
				(count($failedMatches) == 0),
863
				"Failed asserting the $type files '"
864
				. implode("', '", $failedMatches)
865
				. "' do not have exact matches in the required elements:\n'"
866
				. implode("'\n'", array_keys($includedFiles)) . "'"
867
			);
868
		} else {
869
			$this->assertFalse(
870
				(array_key_exists($files, $includedFiles)),
871
				"Failed asserting the $type file '$files' does not have an exact match in the required elements:"
872
						. "\n'" . implode("'\n'", array_keys($includedFiles)) . "'"
873
			);
874
		}
875
	}
876
877
878
	/**
879
	 * Get files of the given type from the backend
880
	 *
881
	 * @param Requirements_Backend $backend
882
	 * @param string $type js or css
883
	 * @return array
884
	 */
885
	protected function getBackendFiles($backend, $type) {
886
		$type = strtolower($type);
887
		switch (strtolower($type)) {
888
			case 'css':
889
				return $backend->getCSS();
890
			case 'js':
891
			case 'javascript':
892
			case 'script':
893
				return $backend->getJavascript();
894
		}
895
		return array();
896
	}
897
}
898