7
7
8
8
namespace Magento \Framework \Css \Test \Unit \PreProcessor \Adapter \Less ;
9
9
10
+ use Magento \Framework \App \Filesystem \DirectoryList ;
10
11
use Magento \Framework \App \State ;
11
12
use Magento \Framework \Css \PreProcessor \Adapter \Less \Processor ;
12
13
use Magento \Framework \Css \PreProcessor \File \Temporary ;
18
19
19
20
class ProcessorTest extends TestCase
20
21
{
21
- const TEST_CONTENT = 'test-content ' ;
22
+ private const TEST_CONTENT = 'test-content ' ;
22
23
23
- const ASSET_PATH = 'test-path ' ;
24
+ private const ASSET_PATH = 'test-path ' ;
24
25
25
- const TMP_PATH_LESS = '_file/test.less ' ;
26
+ private const TMP_PATH_LESS = '_file/test.less ' ;
27
+ private const TMP_PATH_CSS_PRODUCTION = '_file/test-production.css ' ;
28
+ private const TMP_PATH_CSS_DEVELOPER = '_file/test-developer.css ' ;
26
29
27
- const TMP_PATH_CSS = '_file/test.css ' ;
28
-
29
- const ERROR_MESSAGE = 'Test exception ' ;
30
+ private const ERROR_MESSAGE = 'Test exception ' ;
30
31
31
32
/**
32
33
* @var Processor
@@ -52,6 +53,10 @@ class ProcessorTest extends TestCase
52
53
* @var Temporary|MockObject
53
54
*/
54
55
private $ temporaryFileMock ;
56
+ /**
57
+ * @var DirectoryList|MockObject
58
+ */
59
+ private $ directoryListMock ;
55
60
56
61
/**
57
62
* Set up
@@ -69,12 +74,16 @@ protected function setUp(): void
69
74
$ this ->temporaryFileMock = $ this ->getMockBuilder (Temporary::class)
70
75
->disableOriginalConstructor ()
71
76
->getMock ();
77
+ $ this ->directoryListMock = $ this ->getMockBuilder (DirectoryList::class)
78
+ ->disableOriginalConstructor ()
79
+ ->getMock ();
72
80
73
81
$ this ->processor = new Processor (
74
82
$ this ->loggerMock ,
75
83
$ this ->appStateMock ,
76
84
$ this ->assetSourceMock ,
77
- $ this ->temporaryFileMock
85
+ $ this ->temporaryFileMock ,
86
+ $ this ->directoryListMock ,
78
87
);
79
88
}
80
89
@@ -89,7 +98,7 @@ public function testProcessContentException()
89
98
90
99
$ this ->appStateMock ->expects (self ::once ())
91
100
->method ('getMode ' )
92
- ->willReturn (State::MODE_DEVELOPER );
101
+ ->willReturn (State::MODE_PRODUCTION );
93
102
94
103
$ this ->assetSourceMock ->expects (self ::once ())
95
104
->method ('getContent ' )
@@ -120,7 +129,7 @@ public function testProcessContentEmpty()
120
129
121
130
$ this ->appStateMock ->expects (self ::once ())
122
131
->method ('getMode ' )
123
- ->willReturn (State::MODE_DEVELOPER );
132
+ ->willReturn (State::MODE_PRODUCTION );
124
133
125
134
$ this ->assetSourceMock ->expects (self ::once ())
126
135
->method ('getContent ' )
@@ -141,12 +150,55 @@ public function testProcessContentEmpty()
141
150
}
142
151
143
152
/**
144
- * Test for processContent method (not empty content)
153
+ * Test for processContent method in production mode (not empty content)
145
154
*/
146
155
public function testProcessContentNotEmpty ()
147
156
{
148
157
$ assetMock = $ this ->getAssetMock ();
149
158
159
+ $ this ->appStateMock ->expects (self ::once ())
160
+ ->method ('getMode ' )
161
+ ->willReturn (State::MODE_PRODUCTION );
162
+
163
+ $ this ->assetSourceMock ->expects (self ::once ())
164
+ ->method ('getContent ' )
165
+ ->with ($ assetMock )
166
+ ->willReturn (self ::TEST_CONTENT );
167
+
168
+ $ this ->temporaryFileMock ->expects (self ::once ())
169
+ ->method ('createFile ' )
170
+ ->with (self ::ASSET_PATH , self ::TEST_CONTENT )
171
+ ->willReturn (__DIR__ . '/ ' . self ::TMP_PATH_LESS );
172
+
173
+ $ assetMock ->expects (self ::once ())
174
+ ->method ('getPath ' )
175
+ ->willReturn (self ::ASSET_PATH );
176
+
177
+ $ this ->loggerMock ->expects (self ::never ())
178
+ ->method ('critical ' );
179
+
180
+ $ clearSymbol = ["\n" , "\r" , "\t" , ' ' ];
181
+ self ::assertEquals (
182
+ trim (str_replace (
183
+ $ clearSymbol ,
184
+ '' ,
185
+ file_get_contents (__DIR__ . '/ ' . self ::TMP_PATH_CSS_PRODUCTION )
186
+ )),
187
+ trim (str_replace (
188
+ $ clearSymbol ,
189
+ '' ,
190
+ $ this ->processor ->processContent ($ assetMock )
191
+ ))
192
+ );
193
+ }
194
+
195
+ /**
196
+ * Test for processContent method in developer mode (not empty content)
197
+ */
198
+ public function testProcessContentNotEmptyInDeveloperMode ()
199
+ {
200
+ $ assetMock = $ this ->getAssetMock ();
201
+
150
202
$ this ->appStateMock ->expects (self ::once ())
151
203
->method ('getMode ' )
152
204
->willReturn (State::MODE_DEVELOPER );
@@ -170,8 +222,16 @@ public function testProcessContentNotEmpty()
170
222
171
223
$ clearSymbol = ["\n" , "\r" , "\t" , ' ' ];
172
224
self ::assertEquals (
173
- trim (str_replace ($ clearSymbol , '' , file_get_contents (__DIR__ . '/ ' . self ::TMP_PATH_CSS ))),
174
- trim (str_replace ($ clearSymbol , '' , $ this ->processor ->processContent ($ assetMock )))
225
+ trim (str_replace (
226
+ $ clearSymbol ,
227
+ '' ,
228
+ file_get_contents (__DIR__ . '/ ' . self ::TMP_PATH_CSS_DEVELOPER )
229
+ )),
230
+ trim (str_replace (
231
+ $ clearSymbol ,
232
+ '' ,
233
+ $ this ->normalizeInlineSourceMap ($ this ->processor ->processContent ($ assetMock ))
234
+ ))
175
235
);
176
236
}
177
237
@@ -186,4 +246,34 @@ private function getAssetMock()
186
246
187
247
return $ assetMock ;
188
248
}
249
+
250
+ /**
251
+ * - find json part of sourcemap
252
+ * - url decode it
253
+ * - replace \/ with / in source filenames
254
+ * - remove absolute path in filename, make it a relative path
255
+ */
256
+ private function normalizeInlineSourceMap (string $ css ): string
257
+ {
258
+ $ regexBegin = 'sourceMappingURL=data:application/json, ' ;
259
+ $ regexEnd = '*/ ' ;
260
+ $ regex = '@ ' . preg_quote ($ regexBegin , '@ ' ) . '([^\*]+) ' . preg_quote ($ regexEnd , '@ ' ) . '@ ' ;
261
+
262
+ if (preg_match ($ regex , $ css , $ matches ) === 1 ) {
263
+ $ inlineSourceMapJson = $ matches [1 ];
264
+ $ inlineSourceMapJson = urldecode ($ inlineSourceMapJson );
265
+ $ inlineSourceMapJson = json_decode ($ inlineSourceMapJson , true , 512 , JSON_UNESCAPED_SLASHES );
266
+
267
+ $ relativeFilenames = [];
268
+ foreach ($ inlineSourceMapJson ['sources ' ] as $ filename ) {
269
+ $ relativeFilenames [] = str_replace (sprintf ('%s/ ' , BP ), '' , $ filename );
270
+ }
271
+ $ inlineSourceMapJson ['sources ' ] = $ relativeFilenames ;
272
+ $ inlineSourceMapJson = json_encode ($ inlineSourceMapJson , JSON_UNESCAPED_SLASHES );
273
+
274
+ $ css = preg_replace ($ regex , sprintf ('%s%s%s ' , $ regexBegin , $ inlineSourceMapJson , $ regexEnd ), $ css );
275
+ }
276
+
277
+ return $ css ;
278
+ }
189
279
}
0 commit comments