Passed
Pull Request — master (#50)
by Wilmer
01:42
created

AssetBundleTest::setUp()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 20
nc 5
nop 0
dl 0
loc 30
rs 8.6666
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A AssetBundleTest::testDuplicateAssetFile() 0 19 1
A AssetBundleTest::testCircularDependency() 0 4 1
1
<?php
2
declare(strict_types = 1);
3
4
namespace Yiisoft\Asset\Tests;
5
6
use \RuntimeException;
7
use Yiisoft\Asset\AssetBundle;
8
use Yiisoft\Asset\AssetManager;
9
use Yiisoft\Asset\Tests\Stubs\TestAssetLevel3;
10
use Yiisoft\Asset\Tests\Stubs\TestAssetCircleA;
11
use Yiisoft\Asset\Tests\Stubs\TestPosBeginAsset;
12
use Yiisoft\Asset\Tests\Stubs\TestPosBeginConflictAsset;
13
use Yiisoft\Asset\Tests\Stubs\TestPosEndAsset;
14
use Yiisoft\Asset\Tests\Stubs\TestPosHeadAsset;
15
use Yiisoft\Asset\Tests\Stubs\TestJqueryAsset;
16
use Yiisoft\Asset\Tests\Stubs\TestJqueryConflictAsset;
17
use Yiisoft\Asset\Tests\Stubs\TestAssetPerFileOptions;
18
use Yiisoft\Asset\Tests\Stubs\TestSimpleAsset;
19
use Yiisoft\Asset\Tests\Stubs\TestSourceAsset;
20
use Yiisoft\Files\FileHelper;
21
use Yiisoft\Tests\TestCase;
22
use Yiisoft\View\WebView;
23
24
/**
25
 * AssetBundleTest.
26
 */
27
final class AssetBundleTest extends TestCase
28
{
29
    public function testCircularDependency(): void
30
    {
31
        $this->expectException(\RuntimeException::class);
32
        TestAssetCircleA::register($this->webView);
33
    }
34
35
    public function testDuplicateAssetFile(): void
36
    {
37
        $view = $this->webView;
38
39
        $this->assertEmpty($view->getAssetBundles());
40
41
        TestSimpleAsset::register($view);
42
43
        $this->assertCount(1, $view->getAssetBundles());
44
        $this->assertArrayHasKey(TestSimpleAsset::class, $view->getAssetBundles());
45
        $this->assertInstanceOf(AssetBundle::class, $view->getAssetBundles()[TestSimpleAsset::class]);
46
        // register TestJqueryAsset which also has the jquery.js
47
48
        TestJqueryAsset::register($view);
49
50
        $expected = <<<'EOF'
51
123<script src="/baseUrl/js/jquery.js"></script>4
52
EOF;
53
        $this->assertEquals($expected, $view->renderFile($this->aliases->get('@view/rawlayout.php')));
0 ignored issues
show
Bug introduced by
It seems like $this->aliases->get('@view/rawlayout.php') can also be of type boolean; however, parameter $viewFile of Yiisoft\View\View::renderFile() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

53
        $this->assertEquals($expected, $view->renderFile(/** @scrutinizer ignore-type */ $this->aliases->get('@view/rawlayout.php')));
Loading history...
54
    }
55
56
    public function testPerFileOptions(): void
57
    {
58
        $view = $this->webView;
59
60
        $this->assertEmpty($view->getAssetBundles());
61
62
        TestAssetPerFileOptions::register($view);
63
64
        $expected = <<<'EOF'
65
1<link href="/baseUrl/default_options.css" rel="stylesheet" media="screen" hreflang="en">
66
<link href="/baseUrl/tv.css" rel="stylesheet" media="tv" hreflang="en">
67
<link href="/baseUrl/screen_and_print.css" rel="stylesheet" media="screen, print" hreflang="en">23<script src="/baseUrl/normal.js" charset="utf-8"></script>
68
<script src="/baseUrl/defered.js" charset="utf-8" defer></script>4
69
EOF;
70
        $this->assertEqualsWithoutLE($expected, $view->renderFile($this->aliases->get('@view/rawlayout.php')));
0 ignored issues
show
Bug introduced by
It seems like $this->aliases->get('@view/rawlayout.php') can also be of type boolean; however, parameter $viewFile of Yiisoft\View\View::renderFile() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

70
        $this->assertEqualsWithoutLE($expected, $view->renderFile(/** @scrutinizer ignore-type */ $this->aliases->get('@view/rawlayout.php')));
Loading history...
71
    }
72
73
    public function positionProvider(): array
74
    {
75
        return [
76
            [TestPosHeadAsset::class, WebView::POS_HEAD, true],
77
            [TestPosHeadAsset::class, WebView::POS_HEAD, false],
78
            [TestPosBeginAsset::class, WebView::POS_BEGIN, true],
79
            [TestPosBeginAsset::class, WebView::POS_BEGIN, false],
80
            [TestPosEndAsset::class, WebView::POS_END, true],
81
            [TestPosEndAsset::class, WebView::POS_END, false],
82
        ];
83
    }
84
85
    /**
86
     * @dataProvider positionProvider
87
     *
88
     * @param string $assetBundle
89
     * @param int $pos
90
     * @param bool $jqAlreadyRegistered
91
     */
92
    public function testPositionDependencyPos(string $assetBundle, int $pos, bool $jqAlreadyRegistered): void
93
    {
94
        $view = $this->webView;
95
96
        $this->assertEmpty($view->getAssetBundles());
97
98
        if ($jqAlreadyRegistered) {
99
            TestJqueryAsset::register($view);
100
        }
101
102
        $assetBundle::register($view);
103
104
        $this->assertCount(3, $view->getAssetBundles());
105
106
        $this->assertArrayHasKey($assetBundle, $view->getAssetBundles());
107
        $this->assertArrayHasKey(TestJqueryAsset::class, $view->getAssetBundles());
108
        $this->assertArrayHasKey(TestAssetLevel3::class, $view->getAssetBundles());
109
110
        $this->assertInstanceOf(AssetBundle::class, $view->getAssetBundles()[$assetBundle]);
111
        $this->assertInstanceOf(AssetBundle::class, $view->getAssetBundles()[TestJqueryAsset::class]);
112
        $this->assertInstanceOf(AssetBundle::class, $view->getAssetBundles()[TestAssetLevel3::class]);
113
114
        $this->assertArrayHasKey('position', $view->getAssetBundles()[$assetBundle]->jsOptions);
115
        $this->assertEquals($pos, $view->getAssetBundles()[$assetBundle]->jsOptions['position']);
116
        $this->assertArrayHasKey('position', $view->getAssetBundles()[TestJqueryAsset::class]->jsOptions);
117
        $this->assertEquals($pos, $view->getAssetBundles()[TestJqueryAsset::class]->jsOptions['position']);
118
        $this->assertArrayHasKey('position', $view->getAssetBundles()[TestAssetLevel3::class]->jsOptions);
119
        $this->assertEquals($pos, $view->getAssetBundles()[TestAssetLevel3::class]->jsOptions['position']);
120
121
        switch ($pos) {
122
            case WebView::POS_HEAD:
123
                $expected = <<<'EOF'
124
1<link href="/baseUrl/files/cssFile.css" rel="stylesheet">
125
<script src="/baseUrl/js/jquery.js"></script>
126
<script src="/baseUrl/files/jsFile.js"></script>234
127
EOF;
128
                break;
129
            case WebView::POS_BEGIN:
130
                $expected = <<<'EOF'
131
1<link href="/baseUrl/files/cssFile.css" rel="stylesheet">2<script src="/baseUrl/js/jquery.js"></script>
132
<script src="/baseUrl/files/jsFile.js"></script>34
133
EOF;
134
                break;
135
            default:
136
            case WebView::POS_END:
137
                $expected = <<<'EOF'
138
1<link href="/baseUrl/files/cssFile.css" rel="stylesheet">23<script src="/baseUrl/js/jquery.js"></script>
139
<script src="/baseUrl/files/jsFile.js"></script>4
140
EOF;
141
                break;
142
        }
143
        $this->assertEqualsWithoutLE($expected, $view->renderFile($this->aliases->get('@view/rawlayout.php')));
0 ignored issues
show
Bug introduced by
It seems like $this->aliases->get('@view/rawlayout.php') can also be of type boolean; however, parameter $viewFile of Yiisoft\View\View::renderFile() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

143
        $this->assertEqualsWithoutLE($expected, $view->renderFile(/** @scrutinizer ignore-type */ $this->aliases->get('@view/rawlayout.php')));
Loading history...
144
    }
145
146
    public function positionProvider2(): array
147
    {
148
        return [
149
            [TestPosBeginConflictAsset::class, WebView::POS_BEGIN, true],
150
            [TestPosBeginConflictAsset::class, WebView::POS_BEGIN, false],
151
        ];
152
    }
153
154
    /**
155
     * @dataProvider positionProvider2
156
     *
157
     * @param string $assetBundle
158
     * @param int  $pos
159
     * @param bool $jqAlreadyRegistered
160
     */
161
    public function testPositionDependencyConflict(string $assetBundle, int $pos, bool $jqAlreadyRegistered): void
162
    {
163
        $view = $this->webView;
164
165
        $this->assertEmpty($view->getAssetBundles());
166
167
        if ($jqAlreadyRegistered) {
168
            TestJqueryConflictAsset::register($view);
169
        }
170
171
        $this->expectException(\RuntimeException::class);
172
        $assetBundle::register($this->webView);
173
    }
174
175
    public function testSourcesPublishedBySymlinkIssue9333(): void
176
    {
177
        $this->assetManager->setLinkAssets(true);
178
        $this->assetManager->setHashCallback(
179
            function ($path) {
180
                return sprintf('%x/%x', crc32($path), crc32('3.0-dev'));
181
            }
182
        );
183
        $bundle = $this->verifySourcesPublishedBySymlink($this->webView);
184
        $this->assertTrue(is_dir(dirname($bundle->basePath)));
185
    }
186
187
    public function testSourcesPublishOptionsOnly(): void
188
    {
189
        $am = $this->webView->getAssetManager();
190
191
        $bundle = new TestSourceAsset();
192
193
        $bundle->publishOptions = [
194
            'only' => [
195
                'js/*'
196
            ],
197
        ];
198
199
        $bundle->publish($am);
200
201
        $notNeededFilesDir = dirname($bundle->basePath . DIRECTORY_SEPARATOR . $bundle->css[0]);
202
203
        $this->assertFileNotExists($notNeededFilesDir);
204
205
        foreach ($bundle->js as $filename) {
206
            $publishedFile = $bundle->basePath . DIRECTORY_SEPARATOR . $filename;
207
            $this->assertFileExists($publishedFile);
208
        }
209
210
        $this->assertTrue(is_dir(dirname($bundle->basePath . DIRECTORY_SEPARATOR . $bundle->js[0])));
211
        $this->assertTrue(is_dir($bundle->basePath));
212
    }
213
214
    public function registerFileDataProvider(): array
215
    {
216
        return [
217
            // Custom alias repeats in the asset URL
218
            [
219
                'css', '@web/assetSources/repeat/css/stub.css', false,
220
                '1<link href="/repeat/assetSources/repeat/css/stub.css" rel="stylesheet">234',
221
                '/repeat',
222
            ],
223
            [
224
                'js', '@web/assetSources/repeat/js/jquery.js', false,
225
                '123<script src="/repeat/assetSources/repeat/js/jquery.js"></script>4',
226
                '/repeat',
227
            ],
228
229
            // JS files registration
230
            [
231
                'js', '@web/assetSources/js/missing-file.js', true,
232
                '123<script src="/baseUrl/assetSources/js/missing-file.js"></script>4',
233
            ],
234
            [
235
                'js', '@web/assetSources/js/jquery.js', false,
236
                '123<script src="/baseUrl/assetSources/js/jquery.js"></script>4',
237
            ],
238
            [
239
                'js', 'http://example.com/assetSources/js/jquery.js', false,
240
                '123<script src="http://example.com/assetSources/js/jquery.js"></script>4',
241
            ],
242
            [
243
                'js', '//example.com/assetSources/js/jquery.js', false,
244
                '123<script src="//example.com/assetSources/js/jquery.js"></script>4',
245
            ],
246
            [
247
                'js', 'assetSources/js/jquery.js', false,
248
                '123<script src="assetSources/js/jquery.js"></script>4',
249
            ],
250
            [
251
                'js', '/assetSources/js/jquery.js', false,
252
                '123<script src="/assetSources/js/jquery.js"></script>4',
253
            ],
254
255
            // CSS file registration
256
            [
257
                'css', '@web/assetSources/css/missing-file.css', true,
258
                '1<link href="/baseUrl/assetSources/css/missing-file.css" rel="stylesheet">234',
259
            ],
260
            [
261
                'css', '@web/assetSources/css/stub.css', false,
262
                '1<link href="/baseUrl/assetSources/css/stub.css" rel="stylesheet">234',
263
            ],
264
            [
265
                'css', 'http://example.com/assetSources/css/stub.css', false,
266
                '1<link href="http://example.com/assetSources/css/stub.css" rel="stylesheet">234',
267
            ],
268
            [
269
                'css', '//example.com/assetSources/css/stub.css', false,
270
                '1<link href="//example.com/assetSources/css/stub.css" rel="stylesheet">234',
271
            ],
272
            [
273
                'css', 'assetSources/css/stub.css', false,
274
                '1<link href="assetSources/css/stub.css" rel="stylesheet">234',
275
            ],
276
            [
277
                'css', '/assetSources/css/stub.css', false,
278
                '1<link href="/assetSources/css/stub.css" rel="stylesheet">234',
279
            ],
280
281
            // Custom `@web` aliases
282
            [
283
                'js', '@web/assetSources/js/missing-file1.js', true,
284
                '123<script src="/backend/assetSources/js/missing-file1.js"></script>4',
285
                '/backend',
286
            ],
287
            [
288
                'js', 'http://full-url.example.com/backend/assetSources/js/missing-file.js', true,
289
                '123<script src="http://full-url.example.com/backend/assetSources/js/missing-file.js"></script>4',
290
                '/backend',
291
            ],
292
            [
293
                'css', '//backend/backend/assetSources/js/missing-file.js', true,
294
                '1<link href="//backend/backend/assetSources/js/missing-file.js" rel="stylesheet">234',
295
                '/backend',
296
            ],
297
            [
298
                'css', '@web/assetSources/css/stub.css', false,
299
                '1<link href="/en/blog/backend/assetSources/css/stub.css" rel="stylesheet">234',
300
                '/en/blog/backend',
301
            ],
302
303
            // UTF-8 chars
304
            [
305
                'css', '@web/assetSources/css/stub.css', false,
306
                '1<link href="/рус/сайт/assetSources/css/stub.css" rel="stylesheet">234',
307
                '/рус/сайт',
308
            ],
309
            [
310
                'js', '@web/assetSources/js/jquery.js', false,
311
                '123<script src="/汉语/漢語/assetSources/js/jquery.js"></script>4',
312
                '/汉语/漢語',
313
            ],
314
        ];
315
    }
316
317
    /**
318
     * @dataProvider registerFileDataProvider
319
     *
320
     * @param string      $type            either `js` or `css`
321
     * @param string      $path
322
     * @param string|bool $appendTimestamp
323
     * @param string      $expected
324
     * @param string|null $webAlias
325
     */
326
    public function testRegisterFileAppendTimestamp($type, $path, $appendTimestamp, $expected, $webAlias = null): void
327
    {
328
        $originalAlias = $this->aliases->get('@web');
329
330
        if ($webAlias === null) {
331
            $webAlias = $originalAlias;
332
        }
333
334
        $this->aliases->set('@web', $webAlias);
0 ignored issues
show
Bug introduced by
It seems like $webAlias can also be of type boolean; however, parameter $path of Yiisoft\Aliases\Aliases::set() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

334
        $this->aliases->set('@web', /** @scrutinizer ignore-type */ $webAlias);
Loading history...
335
336
        $path = $this->aliases->get($path);
337
        $view = $this->webView;
338
        $am = $this->webView->getAssetManager();
339
        $am->setAppendTimestamp($appendTimestamp);
0 ignored issues
show
Bug introduced by
It seems like $appendTimestamp can also be of type string; however, parameter $value of Yiisoft\Asset\AssetManager::setAppendTimestamp() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

339
        $am->setAppendTimestamp(/** @scrutinizer ignore-type */ $appendTimestamp);
Loading history...
340
341
        $method = 'register' . ucfirst($type) . 'File';
342
343
        $view->$method($path);
344
345
        $this->assertEquals($expected, $view->renderFile($this->aliases->get('@view/rawlayout.php')));
0 ignored issues
show
Bug introduced by
It seems like $this->aliases->get('@view/rawlayout.php') can also be of type boolean; however, parameter $viewFile of Yiisoft\View\View::renderFile() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

345
        $this->assertEquals($expected, $view->renderFile(/** @scrutinizer ignore-type */ $this->aliases->get('@view/rawlayout.php')));
Loading history...
346
    }
347
348
    /**
349
     * @param WebView $view
350
     *
351
     * @return AssetBundle
352
     */
353
    public function verifySourcesPublishedBySymlink($view): AssetBundle
354
    {
355
        $am = $view->getAssetManager();
356
357
        $bundle = TestSourceAsset::register($view);
358
        $bundle->publish($am);
359
360
        $this->assertTrue(is_dir($bundle->basePath));
361
362
        foreach ($bundle->js as $filename) {
363
            $publishedFile = $bundle->basePath . DIRECTORY_SEPARATOR . $filename;
364
            $sourceFile = $bundle->basePath . DIRECTORY_SEPARATOR . $filename;
365
366
            $this->assertTrue(is_link($bundle->basePath));
367
            $this->assertFileExists($publishedFile);
368
            $this->assertFileEquals($publishedFile, $sourceFile);
369
        }
370
371
        $this->assertTrue(FileHelper::unlink($bundle->basePath));
372
373
        return $bundle;
374
    }
375
}
376