77
88namespace Magento \Framework \Css \Test \Unit \PreProcessor \Adapter \Less ;
99
10+ use Magento \Framework \App \Filesystem \DirectoryList ;
1011use Magento \Framework \App \State ;
1112use Magento \Framework \Css \PreProcessor \Adapter \Less \Processor ;
1213use Magento \Framework \Css \PreProcessor \File \Temporary ;
1819
1920class ProcessorTest extends TestCase
2021{
21- const TEST_CONTENT = 'test-content ' ;
22+ private const TEST_CONTENT = 'test-content ' ;
2223
23- const ASSET_PATH = 'test-path ' ;
24+ private const ASSET_PATH = 'test-path ' ;
2425
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 ' ;
2629
27- const TMP_PATH_CSS = '_file/test.css ' ;
28-
29- const ERROR_MESSAGE = 'Test exception ' ;
30+ private const ERROR_MESSAGE = 'Test exception ' ;
3031
3132 /**
3233 * @var Processor
@@ -52,6 +53,10 @@ class ProcessorTest extends TestCase
5253 * @var Temporary|MockObject
5354 */
5455 private $ temporaryFileMock ;
56+ /**
57+ * @var DirectoryList|MockObject
58+ */
59+ private $ directoryListMock ;
5560
5661 /**
5762 * Set up
@@ -69,12 +74,16 @@ protected function setUp(): void
6974 $ this ->temporaryFileMock = $ this ->getMockBuilder (Temporary::class)
7075 ->disableOriginalConstructor ()
7176 ->getMock ();
77+ $ this ->directoryListMock = $ this ->getMockBuilder (DirectoryList::class)
78+ ->disableOriginalConstructor ()
79+ ->getMock ();
7280
7381 $ this ->processor = new Processor (
7482 $ this ->loggerMock ,
7583 $ this ->appStateMock ,
7684 $ this ->assetSourceMock ,
77- $ this ->temporaryFileMock
85+ $ this ->temporaryFileMock ,
86+ $ this ->directoryListMock ,
7887 );
7988 }
8089
@@ -89,7 +98,7 @@ public function testProcessContentException()
8998
9099 $ this ->appStateMock ->expects (self ::once ())
91100 ->method ('getMode ' )
92- ->willReturn (State::MODE_DEVELOPER );
101+ ->willReturn (State::MODE_PRODUCTION );
93102
94103 $ this ->assetSourceMock ->expects (self ::once ())
95104 ->method ('getContent ' )
@@ -120,7 +129,7 @@ public function testProcessContentEmpty()
120129
121130 $ this ->appStateMock ->expects (self ::once ())
122131 ->method ('getMode ' )
123- ->willReturn (State::MODE_DEVELOPER );
132+ ->willReturn (State::MODE_PRODUCTION );
124133
125134 $ this ->assetSourceMock ->expects (self ::once ())
126135 ->method ('getContent ' )
@@ -141,12 +150,55 @@ public function testProcessContentEmpty()
141150 }
142151
143152 /**
144- * Test for processContent method (not empty content)
153+ * Test for processContent method in production mode (not empty content)
145154 */
146155 public function testProcessContentNotEmpty ()
147156 {
148157 $ assetMock = $ this ->getAssetMock ();
149158
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+
150202 $ this ->appStateMock ->expects (self ::once ())
151203 ->method ('getMode ' )
152204 ->willReturn (State::MODE_DEVELOPER );
@@ -170,8 +222,16 @@ public function testProcessContentNotEmpty()
170222
171223 $ clearSymbol = ["\n" , "\r" , "\t" , ' ' ];
172224 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+ ))
175235 );
176236 }
177237
@@ -186,4 +246,34 @@ private function getAssetMock()
186246
187247 return $ assetMock ;
188248 }
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+ }
189279}
0 commit comments