Passed
Pull Request — master (#50)
by Alexander
02:52
created

AssetBundleTest::positionProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types = 1);
3
4
namespace Yiisoft\Asset\Tests;
5
6
use Yiisoft\Asset\AssetBundle;
7
use Yiisoft\Asset\Tests\Stubs\TestAssetLevel3;
8
use Yiisoft\Asset\Tests\Stubs\TestAssetCircleA;
9
use Yiisoft\Asset\Tests\Stubs\TestPosBeginAsset;
10
use Yiisoft\Asset\Tests\Stubs\TestPosBeginConflictAsset;
11
use Yiisoft\Asset\Tests\Stubs\TestPosEndAsset;
12
use Yiisoft\Asset\Tests\Stubs\TestPosHeadAsset;
13
use Yiisoft\Asset\Tests\Stubs\TestJqueryAsset;
14
use Yiisoft\Asset\Tests\Stubs\TestJqueryConflictAsset;
15
use Yiisoft\Asset\Tests\Stubs\TestAssetPerFileOptions;
16
use Yiisoft\Asset\Tests\Stubs\TestSimpleAsset;
17
use Yiisoft\Asset\Tests\Stubs\TestSourceAsset;
18
use Yiisoft\Files\FileHelper;
19
use Yiisoft\Tests\TestCase;
20
use Yiisoft\View\WebView;
21
22
/**
23
 * AssetBundleTest.
24
 */
25
final class AssetBundleTest extends TestCase
26
{
27
    public function testCircularDependency(): void
28
    {
29
        $this->expectException(\RuntimeException::class);
30
        TestAssetCircleA::register($this->webView);
31
    }
32
33
    public function testDuplicateAssetFile(): void
34
    {
35
        $view = $this->webView;
36
37
        $this->assertEmpty($view->getAssetBundles());
38
39
        TestSimpleAsset::register($view);
40
41
        $this->assertCount(1, $view->getAssetBundles());
42
        $this->assertArrayHasKey(TestSimpleAsset::class, $view->getAssetBundles());
43
        $this->assertInstanceOf(AssetBundle::class, $view->getAssetBundles()[TestSimpleAsset::class]);
44
        // register TestJqueryAsset which also has the jquery.js
45
46
        TestJqueryAsset::register($view);
47
48
        $expected = <<<'EOF'
49
123<script src="/baseUrl/js/jquery.js"></script>4
50
EOF;
51
        $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

51
        $this->assertEquals($expected, $view->renderFile(/** @scrutinizer ignore-type */ $this->aliases->get('@view/rawlayout.php')));
Loading history...
52
    }
53
54
    public function testPerFileOptions(): void
55
    {
56
        $view = $this->webView;
57
58
        $this->assertEmpty($view->getAssetBundles());
59
60
        TestAssetPerFileOptions::register($view);
61
62
        $expected = <<<'EOF'
63
1<link href="/baseUrl/default_options.css" rel="stylesheet" media="screen" hreflang="en">
64
<link href="/baseUrl/tv.css" rel="stylesheet" media="tv" hreflang="en">
65
<link href="/baseUrl/screen_and_print.css" rel="stylesheet" media="screen, print" hreflang="en">23<script src="/baseUrl/normal.js" charset="utf-8"></script>
66
<script src="/baseUrl/defered.js" charset="utf-8" defer></script>4
67
EOF;
68
        $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

68
        $this->assertEqualsWithoutLE($expected, $view->renderFile(/** @scrutinizer ignore-type */ $this->aliases->get('@view/rawlayout.php')));
Loading history...
69
    }
70
71
    public function positionProvider(): array
72
    {
73
        return [
74
            [TestPosHeadAsset::class, WebView::POS_HEAD, true],
75
            [TestPosHeadAsset::class, WebView::POS_HEAD, false],
76
            [TestPosBeginAsset::class, WebView::POS_BEGIN, true],
77
            [TestPosBeginAsset::class, WebView::POS_BEGIN, false],
78
            [TestPosEndAsset::class, WebView::POS_END, true],
79
            [TestPosEndAsset::class, WebView::POS_END, false],
80
        ];
81
    }
82
83
    /**
84
     * @dataProvider positionProvider
85
     *
86
     * @param string $assetBundle
87
     * @param int $pos
88
     * @param bool $jqAlreadyRegistered
89
     */
90
    public function testPositionDependencyPos(string $assetBundle, int $pos, bool $jqAlreadyRegistered): void
91
    {
92
        $view = $this->webView;
93
94
        $this->assertEmpty($view->getAssetBundles());
95
96
        if ($jqAlreadyRegistered) {
97
            TestJqueryAsset::register($view);
98
        }
99
100
        $assetBundle::register($view);
101
102
        $this->assertCount(3, $view->getAssetBundles());
103
104
        $this->assertArrayHasKey($assetBundle, $view->getAssetBundles());
105
        $this->assertArrayHasKey(TestJqueryAsset::class, $view->getAssetBundles());
106
        $this->assertArrayHasKey(TestAssetLevel3::class, $view->getAssetBundles());
107
108
        $this->assertInstanceOf(AssetBundle::class, $view->getAssetBundles()[$assetBundle]);
109
        $this->assertInstanceOf(AssetBundle::class, $view->getAssetBundles()[TestJqueryAsset::class]);
110
        $this->assertInstanceOf(AssetBundle::class, $view->getAssetBundles()[TestAssetLevel3::class]);
111
112
        $this->assertArrayHasKey('position', $view->getAssetBundles()[$assetBundle]->jsOptions);
113
        $this->assertEquals($pos, $view->getAssetBundles()[$assetBundle]->jsOptions['position']);
114
        $this->assertArrayHasKey('position', $view->getAssetBundles()[TestJqueryAsset::class]->jsOptions);
115
        $this->assertEquals($pos, $view->getAssetBundles()[TestJqueryAsset::class]->jsOptions['position']);
116
        $this->assertArrayHasKey('position', $view->getAssetBundles()[TestAssetLevel3::class]->jsOptions);
117
        $this->assertEquals($pos, $view->getAssetBundles()[TestAssetLevel3::class]->jsOptions['position']);
118
119
        switch ($pos) {
120
            case WebView::POS_HEAD:
121
                $expected = <<<'EOF'
122
1<link href="/baseUrl/files/cssFile.css" rel="stylesheet">
123
<script src="/baseUrl/js/jquery.js"></script>
124
<script src="/baseUrl/files/jsFile.js"></script>234
125
EOF;
126
                break;
127
            case WebView::POS_BEGIN:
128
                $expected = <<<'EOF'
129
1<link href="/baseUrl/files/cssFile.css" rel="stylesheet">2<script src="/baseUrl/js/jquery.js"></script>
130
<script src="/baseUrl/files/jsFile.js"></script>34
131
EOF;
132
                break;
133
            default:
134
            case WebView::POS_END:
135
                $expected = <<<'EOF'
136
1<link href="/baseUrl/files/cssFile.css" rel="stylesheet">23<script src="/baseUrl/js/jquery.js"></script>
137
<script src="/baseUrl/files/jsFile.js"></script>4
138
EOF;
139
                break;
140
        }
141
        $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

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

333
        $this->aliases->set('@web', /** @scrutinizer ignore-type */ $webAlias);
Loading history...
334
335
        $path = $this->aliases->get($path);
336
        $view = $this->webView;
337
        $am = $this->webView->getAssetManager();
338
        $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

338
        $am->setAppendTimestamp(/** @scrutinizer ignore-type */ $appendTimestamp);
Loading history...
339
340
        $method = 'register' . ucfirst($type) . 'File';
341
342
        $view->$method($path);
343
344
        $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

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