Passed
Push — master ( f68db4...f935c2 )
by Alexander
01:36
created

AssetPublisherTest::testSourceSetHashCallback()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 39
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 21
nc 1
nop 0
dl 0
loc 39
c 1
b 0
f 0
cc 1
rs 9.584
1
<?php
2
declare(strict_types=1);
3
4
namespace Yiisoft\Assets\Tests;
5
6
use Yiisoft\Assets\Exception\InvalidConfigException;
7
use Yiisoft\Assets\Tests\stubs\BaseAsset;
8
use Yiisoft\Assets\Tests\stubs\JqueryAsset;
9
use Yiisoft\Assets\Tests\stubs\SourceAsset;
10
use Yiisoft\Files\FileHelper;
11
12
/**
13
 * AssetPublisherTest.
14
 */
15
final class AssetPublisherTest extends TestCase
16
{
17
    protected function tearDown(): void
18
    {
19
        parent::tearDown();
20
21
        $this->removeAssets('@basePath');
22
    }
23
24
    public function testBaseAppendtimestamp(): void
25
    {
26
        $bundle = new BaseAsset();
27
28
        $timestampCss = @filemtime($this->aliases->get($bundle->basePath) . '/' . $bundle->css[0]);
29
        $urlCss = "/baseUrl/css/basePath.css?v=$timestampCss";
30
31
        $timestampJs = @filemtime($this->aliases->get($bundle->basePath) . '/' . $bundle->js[0]);
32
        $urlJs = "/baseUrl/js/basePath.js?v=$timestampJs";
33
34
        $this->assertEmpty($this->assetManager->getAssetBundles());
35
36
        $this->publisher->setAppendTimestamp(true);
37
38
        $this->assetManager->register([BaseAsset::class]);
39
40
        $this->assertStringContainsString(
41
            $urlCss,
42
            $this->assetManager->getCssFiles()[$urlCss]['url']
43
        );
44
        $this->assertEquals(
45
            [
46
                'integrity' => 'integrity-hash',
47
                'crossorigin' => 'anonymous'
48
            ],
49
            $this->assetManager->getCssFiles()[$urlCss]['attributes']
50
        );
51
52
        $this->assertStringContainsString(
53
            $urlJs,
54
            $this->assetManager->getJsFiles()[$urlJs]['url']
55
        );
56
        $this->assertEquals(
57
            [
58
                'integrity' => 'integrity-hash',
59
                'crossorigin' => 'anonymous',
60
                'position' => 3
61
            ],
62
            $this->assetManager->getJsFiles()[$urlJs]['attributes']
63
        );
64
    }
65
66
    public function testPublisherSetAssetMap(): void
67
    {
68
        $urlJs = '//testme.css';
69
70
        $this->publisher->setAssetMap(
71
            [
72
                'jquery.js' => $urlJs,
73
            ]
74
        );
75
76
        $this->assertEmpty($this->assetManager->getAssetBundles());
77
78
        $this->assetManager->register([JqueryAsset::class]);
79
80
        $this->assertStringContainsString(
81
            $urlJs,
82
            $this->assetManager->getJsFiles()[$urlJs]['url']
83
        );
84
        $this->assertEquals(
85
            [
86
                'position' => 3
87
            ],
88
            $this->assetManager->getJsFiles()[$urlJs]['attributes']
89
        );
90
    }
91
92
    /**
93
     * @return array
94
     */
95
    public function registerFileDataProvider(): array
96
    {
97
        return [
98
            // Custom alias repeats in the asset URL
99
            [
100
                'css', '@web/assetSources/repeat/css/stub.css', false,
101
                '/repeat/assetSources/repeat/css/stub.css',
102
                '/repeat',
103
            ],
104
            [
105
                'js', '@web/assetSources/repeat/js/jquery.js', false,
106
                '/repeat/assetSources/repeat/js/jquery.js',
107
                '/repeat',
108
            ],
109
            // JS files registration
110
            [
111
                'js', '@web/assetSources/js/missing-file.js', true,
112
                '/baseUrl/assetSources/js/missing-file.js'
113
            ],
114
            [
115
                'js', '@web/assetSources/js/jquery.js', false,
116
                '/baseUrl/assetSources/js/jquery.js',
117
            ],
118
            [
119
                'js', 'http://example.com/assetSources/js/jquery.js', false,
120
                'http://example.com/assetSources/js/jquery.js',
121
            ],
122
            [
123
                'js', '//example.com/assetSources/js/jquery.js', false,
124
                '//example.com/assetSources/js/jquery.js',
125
            ],
126
            [
127
                'js', 'assetSources/js/jquery.js', false,
128
                'assetSources/js/jquery.js',
129
            ],
130
            [
131
                'js', '/assetSources/js/jquery.js', false,
132
                '/assetSources/js/jquery.js',
133
            ],
134
            // CSS file registration
135
            [
136
                'css', '@web/assetSources/css/missing-file.css', true,
137
                '/baseUrl/assetSources/css/missing-file.css',
138
            ],
139
            [
140
                'css', '@web/assetSources/css/stub.css', false,
141
                '/baseUrl/assetSources/css/stub.css',
142
            ],
143
            [
144
                'css', 'http://example.com/assetSources/css/stub.css', false,
145
                'http://example.com/assetSources/css/stub.css',
146
            ],
147
            [
148
                'css', '//example.com/assetSources/css/stub.css', false,
149
                '//example.com/assetSources/css/stub.css',
150
            ],
151
            [
152
                'css', 'assetSources/css/stub.css', false,
153
                'assetSources/css/stub.css',
154
            ],
155
            [
156
                'css', '/assetSources/css/stub.css', false,
157
                '/assetSources/css/stub.css',
158
            ],
159
            // Custom `@web` aliases
160
            [
161
                'js', '@web/assetSources/js/missing-file1.js', true,
162
                '/backend/assetSources/js/missing-file1.js',
163
                '/backend',
164
            ],
165
            [
166
                'js', 'http://full-url.example.com/backend/assetSources/js/missing-file.js', true,
167
                'http://full-url.example.com/backend/assetSources/js/missing-file.js',
168
                '/backend',
169
            ],
170
            [
171
                'css', '//backend/backend/assetSources/js/missing-file.js', true,
172
                '//backend/backend/assetSources/js/missing-file.js',
173
                '/backend',
174
            ],
175
            [
176
                'css', '@web/assetSources/css/stub.css', false,
177
                '/en/blog/backend/assetSources/css/stub.css',
178
                '/en/blog/backend',
179
            ],
180
            // UTF-8 chars
181
            [
182
                'css', '@web/assetSources/css/stub.css', false,
183
                '/рус/сайт/assetSources/css/stub.css',
184
                '/рус/сайт',
185
            ],
186
            [
187
                'js', '@web/assetSources/js/jquery.js', false,
188
                '/汉语/漢語/assetSources/js/jquery.js',
189
                '/汉语/漢語',
190
            ],
191
        ];
192
    }
193
194
    /**
195
     * @dataProvider registerFileDataProvider
196
     *
197
     * @param string $type either `js` or `css`
198
     * @param string $path
199
     * @param bool $appendTimestamp
200
     * @param string $expected
201
     * @param string|null $webAlias
202
     */
203
    public function testRegisterFileAppendTimestamp(
204
        string $type,
205
        string $path,
206
        bool $appendTimestamp,
207
        string $expected,
208
        ?string $webAlias = null
209
    ): void {
210
        $originalAlias = $this->aliases->get('@web');
211
212
        if ($webAlias === null) {
213
            $webAlias = $originalAlias;
214
        }
215
216
        $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

216
        $this->aliases->set('@web', /** @scrutinizer ignore-type */ $webAlias);
Loading history...
217
218
        $path = $this->aliases->get($path);
219
220
        $this->publisher->setAppendTimestamp($appendTimestamp);
221
222
        $method = 'register' . ucfirst($type) . 'File';
223
224
        $this->assetManager->$method($path, [], null);
225
226
        $this->assertStringContainsString(
227
            $expected,
228
            $type === 'css' ? $this->assetManager->getCssFiles()[$expected]['url']
229
                : $this->assetManager->getJsFiles()[$expected]['url']
230
        );
231
    }
232
233
    public function testSourcesCssJsDefaultOptions(): void
234
    {
235
        $bundle = new SourceAsset();
236
237
        $sourcePath = $this->aliases->get($bundle->sourcePath);
238
        $path = (is_file($sourcePath) ? \dirname($sourcePath) : $sourcePath) . @filemtime($sourcePath);
239
        $hash = sprintf('%x', crc32($path . '|' . $this->publisher->getLinkAssets()));
240
241
        $this->publisher->setCssDefaultOptions([
242
            'media' => 'none'
243
        ]);
244
245
        $this->publisher->setJsDefaultOptions([
246
            'position' => 2
247
        ]);
248
249
        $this->assertEmpty($this->assetManager->getAssetBundles());
250
251
        $this->assetManager->register([SourceAsset::class]);
252
253
        $this->assertEquals(
254
            [
255
                'media' => 'none'
256
            ],
257
            $this->assetManager->getCssFiles()["/baseUrl/$hash/css/stub.css"]['attributes']
258
        );
259
        $this->assertEquals(
260
            [
261
                'position' => 2
262
            ],
263
            $this->assetManager->getJsFiles()['/js/jquery.js']['attributes']
264
        );
265
        $this->assertEquals(
266
            [
267
                'position' => 2
268
            ],
269
            $this->assetManager->getJsFiles()["/baseUrl/$hash/js/stub.js"]['attributes']
270
        );
271
    }
272
273
    public function testSourceSetHashCallback(): void
274
    {
275
        $this->publisher->setHashCallback(function () {
276
            return 'HashCallback';
277
        });
278
279
        $this->assertEmpty($this->assetManager->getAssetBundles());
280
281
        $this->assetManager->register([SourceAsset::class]);
282
283
        $this->assertStringContainsString(
284
            '/baseUrl/HashCallback/css/stub.css',
285
            $this->assetManager->getCssFiles()['/baseUrl/HashCallback/css/stub.css']['url']
286
        );
287
        $this->assertEquals(
288
            [],
289
            $this->assetManager->getCssFiles()['/baseUrl/HashCallback/css/stub.css']['attributes']
290
        );
291
292
        $this->assertStringContainsString(
293
            '/js/jquery.js',
294
            $this->assetManager->getJsFiles()['/js/jquery.js']['url']
295
        );
296
        $this->assertEquals(
297
            [
298
                'position' => 3
299
            ],
300
            $this->assetManager->getJsFiles()['/js/jquery.js']['attributes']
301
        );
302
303
        $this->assertStringContainsString(
304
            '/baseUrl/HashCallback/js/stub.js',
305
            $this->assetManager->getJsFiles()['/baseUrl/HashCallback/js/stub.js']['url']
306
        );
307
        $this->assertEquals(
308
            [
309
                'position' => 3
310
            ],
311
            $this->assetManager->getJsFiles()['/baseUrl/HashCallback/js/stub.js']['attributes']
312
        );
313
    }
314
315
    public function testSourcesPublishOptionsOnlyRegex(): void
316
    {
317
        $bundle = new SourceAsset();
318
319
        $bundle->publishOptions = [
320
            'only' => [
321
                'js/*'
322
            ],
323
        ];
324
325
        [$bundle->basePath, $bundle->baseUrl] = $this->publisher->publish($bundle);
326
327
        $notNeededFilesDir = dirname($bundle->basePath . DIRECTORY_SEPARATOR . $bundle->css[0]);
328
329
        $this->assertFileNotExists($notNeededFilesDir);
330
331
        foreach ($bundle->js as $filename) {
332
            $publishedFile = $bundle->basePath . DIRECTORY_SEPARATOR . $filename;
333
334
            $this->assertFileExists($publishedFile);
335
        }
336
337
        $this->assertDirectoryExists(dirname($bundle->basePath . DIRECTORY_SEPARATOR . $bundle->js[0]));
338
        $this->assertDirectoryExists($bundle->basePath);
339
    }
340
341
    public function testSourcesPathException(): void
342
    {
343
        $bundle = new SourceAsset();
344
345
        $bundle->sourcePath = '/wrong';
346
347
        $message = "The sourcePath to be published does not exist: $bundle->sourcePath";
348
349
        $this->expectException(InvalidConfigException::class);
350
        $this->expectExceptionMessage($message);
351
352
        $this->publisher->publish($bundle);
353
    }
354
355
    public function testSourcesPublishedBySymlinkIssue9333(): void
356
    {
357
        $this->publisher->setLinkAssets(true);
358
359
        $this->publisher->setHashCallback(
360
            static function ($path) {
361
                return sprintf('%x/%x', crc32($path), crc32('3.0-dev'));
362
            }
363
        );
364
365
        $bundle = $this->verifySourcesPublishedBySymlink();
366
367
        $this->assertDirectoryExists(dirname($bundle->basePath));
368
    }
369
370
    private function verifySourcesPublishedBySymlink(): SourceAsset
371
    {
372
        $bundle = new SourceAsset();
373
374
        [$bundle->basePath, $bundle->baseUrl] = $this->publisher->publish($bundle);
375
376
        $this->assertDirectoryExists($bundle->basePath);
377
378
        foreach ($bundle->js as $filename) {
379
            $publishedFile = $bundle->basePath . DIRECTORY_SEPARATOR . $filename;
380
            $sourceFile = $bundle->basePath . DIRECTORY_SEPARATOR . $filename;
381
382
            $this->assertTrue(is_link($bundle->basePath));
383
            $this->assertFileExists($publishedFile);
384
            $this->assertFileEquals($publishedFile, $sourceFile);
385
        }
386
387
        $this->assertTrue(FileHelper::unlink($bundle->basePath));
388
389
        return $bundle;
390
    }
391
}
392