1 | 'use strict';
|
2 |
|
3 | require('dotenv').config();
|
4 |
|
5 | const _ = require('underscore');
|
6 | const path = require('path');
|
7 | const fs = require('fs-extra');
|
8 | const request = require('request');
|
9 | const zlib = require('zlib');
|
10 | const NodeunitAsync = require('nodeunit-async');
|
11 |
|
12 | const AssetProcessor = require('../lib/assetProcessor');
|
13 |
|
14 |
|
15 | const th = new NodeunitAsync();
|
16 |
|
17 | if (_.any(['S3_BUCKET', 'S3_ACCESS_KEY', 'S3_SECRET', 'GITHUB_OAUTH_TOKEN'], k => { return _.isUndefined(process.env[k]); })) {
|
18 | throw new Error("Missing required configuration. Do you have a .env file?");
|
19 | }
|
20 |
|
21 | const credentials = {
|
22 | s3: {
|
23 | bucket: process.env.S3_BUCKET,
|
24 | key: process.env.S3_ACCESS_KEY,
|
25 | secret: process.env.S3_SECRET
|
26 | },
|
27 | git: {
|
28 | token: process.env.GITHUB_OAUTH_TOKEN
|
29 | }
|
30 | };
|
31 |
|
32 |
|
33 | const assetProcessor = _assetProcessorForTestConfig('test-config.json');
|
34 |
|
35 | exports.testGetJavaScriptFiles = function(test) {
|
36 |
|
37 | test.expect(1);
|
38 |
|
39 | th.runTest(test, {
|
40 | getJavaScriptFiles: [function(next) {
|
41 | assetProcessor.getJavaScriptFiles(next);
|
42 | }],
|
43 | assertResult: ['getJavaScriptFiles', function(next, results) {
|
44 | const files = results && results.getJavaScriptFiles;
|
45 | const expected = [
|
46 | 'js/js_directory_1/one.js',
|
47 | 'js/js_directory_2/two.js',
|
48 | 'js/js_directory_1/three.js',
|
49 | 'mixed/four.js',
|
50 | 'mixed/mixed_directory_1/five.js',
|
51 | 'mixed/mixed_directory_2/six.js',
|
52 | 'js/js_excluded/shouldBeIncluded.js',
|
53 | 'js/js_directory_1/anywhere1.js',
|
54 | 'js/js_directory_2/anywhere2.js',
|
55 | 'mixed/anywhere5.js',
|
56 | 'mixed/mixed_directory_1/anywhere3.js',
|
57 | 'mixed/mixed_directory_2/anywhere4.js'
|
58 | ];
|
59 |
|
60 | test.deepEqual(expected, files);
|
61 | next();
|
62 | }]
|
63 | });
|
64 | };
|
65 |
|
66 | exports.testGetCssFiles = function(test) {
|
67 |
|
68 | test.expect(1);
|
69 |
|
70 | th.runTest(test, {
|
71 | getCssFiles: [function(next) {
|
72 | assetProcessor.getCssFiles(next);
|
73 | }],
|
74 | assertResult: ['getCssFiles', function(next, results) {
|
75 | const files = results && results.getCssFiles;
|
76 | const expected = [
|
77 | 'css/css_directory_1/one.css',
|
78 | 'css/css_directory_2/two.css',
|
79 | 'css/css_directory_1/three.css',
|
80 | 'mixed/mixed_directory_1/four.css',
|
81 | 'css/css_directory_2/five.css',
|
82 | 'css/css_priority/priority2_butfirst.css',
|
83 | 'css/css_priority/prioirty1_butsecond.css',
|
84 | 'css/css_priority/priority3_butthird.css',
|
85 | 'css/css_directory_1/anywhere1.css',
|
86 | 'css/css_directory_1/anywhere2.css',
|
87 | 'css/css_directory_2/anywhere3.css',
|
88 | 'mixed/mixed_directory_2/anywhere4.css'
|
89 | ];
|
90 | test.deepEqual(expected, files);
|
91 | next();
|
92 | }]
|
93 | });
|
94 | };
|
95 |
|
96 | exports.testGetImageFiles = function(test) {
|
97 |
|
98 | test.expect(1);
|
99 |
|
100 | th.runTest(test, {
|
101 | getImageFiles: [function(next) {
|
102 | assetProcessor.getImageFiles(next);
|
103 | }],
|
104 | assertResult: ['getImageFiles', function(next, results) {
|
105 | const files = results && results.getImageFiles;
|
106 | const expected = [
|
107 | 'img/img_directory_1/grey_wash_wall.png',
|
108 | 'img/img_directory_1/mooning.png',
|
109 | 'img/img_directory_2/purty_wood.png',
|
110 | 'img/slash_it.png'
|
111 | ];
|
112 | test.deepEqual(expected, files);
|
113 | next();
|
114 | }]
|
115 | });
|
116 | };
|
117 |
|
118 | exports.testGetExtraFiles = function(test) {
|
119 |
|
120 | test.expect(1);
|
121 |
|
122 | th.runTest(test, {
|
123 | getExtraFiles: [function(next) {
|
124 | assetProcessor.getExtraFiles(next);
|
125 | }],
|
126 | assertResult: ['getExtraFiles', function(next, results) {
|
127 | const files = results && results.getExtraFiles;
|
128 | const expected = [
|
129 | 'extra/fonts/FontAwesome.otf',
|
130 | 'extra/fonts/fontawesome-webfont.eot',
|
131 | 'extra/fonts/fontawesome-webfont.svg',
|
132 | 'extra/fonts/fontawesome-webfont.ttf',
|
133 | 'extra/fonts/fontawesome-webfont.woff',
|
134 | 'extra/swf/copy_csv_xls.swf'
|
135 | ];
|
136 | test.deepEqual(expected, files);
|
137 | next();
|
138 | }]
|
139 | });
|
140 | };
|
141 |
|
142 | exports.testGetFilesNormalizedFullPaths = function(test) {
|
143 |
|
144 | test.expect(1);
|
145 |
|
146 | th.runTest(test, {
|
147 | getCssFiles: [function(next) {
|
148 | assetProcessor.getCssFiles(true, next);
|
149 | }],
|
150 | assertResult: ['getCssFiles', function(next, results) {
|
151 | const files = results && results.getCssFiles;
|
152 | test.ok(files[0] && files[0].indexOf(path.join(__dirname, 'test-files', 'css')) === 0);
|
153 | next();
|
154 | }]
|
155 | });
|
156 | };
|
157 |
|
158 | exports.testCompileLessFiles = function(test) {
|
159 |
|
160 | const filesToCreate = [
|
161 | path.join(__dirname, 'test-files', 'css', 'css_directory_1', 'three.css'),
|
162 | path.join(__dirname, 'test-files', 'mixed', 'mixed_directory_2', 'anywhere4.css')
|
163 | ];
|
164 |
|
165 |
|
166 | test.expect(2);
|
167 |
|
168 | filesToCreate.forEach(function(file) {
|
169 | fs.copySync(file, file+'.deleted');
|
170 | fs.unlinkSync(file);
|
171 | });
|
172 |
|
173 | th.runTest(test, {
|
174 | compileLessFiles: [function(next) {
|
175 | assetProcessor.compileLessFiles(next);
|
176 | }],
|
177 | assertResult: ['compileLessFiles', function(next, results) {
|
178 | const files = results && results.compileLessFiles || [];
|
179 | test.ok(files.some(function(file) {
|
180 | return path.basename(file) === 'three.css';
|
181 | }));
|
182 | test.ok(files.some(function(file) {
|
183 | return path.basename(file) === 'anywhere4.css';
|
184 | }));
|
185 |
|
186 |
|
187 | filesToCreate.forEach(function(file) {
|
188 | const deletedPath = file+'.deleted';
|
189 | if (fs.existsSync(deletedPath)) {
|
190 | fs.copySync(deletedPath ,file);
|
191 | fs.unlinkSync(deletedPath);
|
192 | }
|
193 | });
|
194 |
|
195 | next();
|
196 | }]
|
197 | });
|
198 |
|
199 | };
|
200 |
|
201 | exports.testUploadJavaScriptToCdn = function(test) {
|
202 |
|
203 | test.expect(8);
|
204 |
|
205 | th.runTest(test, {
|
206 | uploadJavaScriptToCdn: [function(next) {
|
207 | assetProcessor.uploadJavaScriptToCdn(next);
|
208 | }],
|
209 | download: ['uploadJavaScriptToCdn', function(next, results) {
|
210 | _downloadAndUncompress(results.uploadJavaScriptToCdn, next);
|
211 | }],
|
212 | assertResult: ['download', function(next, results) {
|
213 |
|
214 | const js = results.download && results.download || '';
|
215 |
|
216 | test.ok(results.uploadJavaScriptToCdn);
|
217 | test.ok(js);
|
218 | test.equal(-1, js.indexOf('longVariableName'));
|
219 | test.ok(js.indexOf('\n') === -1 || js.indexOf('\n') > 100);
|
220 | test.ok(js.indexOf('1') < js.indexOf('2'));
|
221 | test.ok(js.indexOf('2') < js.indexOf('3'));
|
222 | test.ok(js.indexOf('3') < js.indexOf('4'));
|
223 | test.ok(js.indexOf('5') < js.indexOf('6'));
|
224 |
|
225 | next();
|
226 | }]
|
227 | });
|
228 |
|
229 | };
|
230 |
|
231 | exports.testUploadJavaScriptToCdn_withErrors = function(test) {
|
232 |
|
233 | const otherAssetProcessor = _assetProcessorForTestConfig('test-config-withErrors.json');
|
234 |
|
235 | test.expect(2);
|
236 |
|
237 | th.runTest(test, {
|
238 | uploadJavaScriptToCdn: [function(next) {
|
239 | otherAssetProcessor.uploadJavaScriptToCdn(function(err) {
|
240 | next(null, err);
|
241 | });
|
242 | }],
|
243 | assertResult: ['uploadJavaScriptToCdn', function(next, results) {
|
244 |
|
245 | const err = results.uploadJavaScriptToCdn;
|
246 |
|
247 | test.ok(err);
|
248 | test.ok(err.message.match(/unexpected token/i));
|
249 |
|
250 | next();
|
251 | }]
|
252 | });
|
253 |
|
254 | };
|
255 |
|
256 |
|
257 | exports.testUploadCssToCdn = function(test) {
|
258 |
|
259 | test.expect(13);
|
260 |
|
261 | th.runTest(test, {
|
262 | uploadCssToCdn: [function(next) {
|
263 | assetProcessor.uploadCssToCdn(next);
|
264 | }],
|
265 | download: ['uploadCssToCdn', function(next, results) {
|
266 | _downloadAndUncompress(results.uploadCssToCdn, next);
|
267 | }],
|
268 | assertResult: ['download', function(next, results) {
|
269 |
|
270 | const css = results.download && results.download || '';
|
271 | const bucket = credentials.s3 && credentials.s3.bucket || 'my-aws-s3-bucket';
|
272 |
|
273 | test.ok(results.uploadCssToCdn);
|
274 |
|
275 | test.ok(css.indexOf('.one') < css.indexOf('.two'));
|
276 | test.ok(css.indexOf('.three') < css.indexOf('.four'));
|
277 | test.ok(css.indexOf('.four') < css.indexOf('.five'));
|
278 | test.ok(css.indexOf('.five') < css.indexOf('.p2'));
|
279 | test.ok(css.indexOf('.p2') < css.indexOf('.p1'));
|
280 | test.ok(css.indexOf('.p1') < css.indexOf('.p3'));
|
281 |
|
282 |
|
283 | test.notEqual(-1, css.indexOf('url(/img/img_directory_1/grey_wash_wall.png)'));
|
284 | test.notEqual(-1, css.indexOf('url(/img/img_directory_1/mooning.png)'));
|
285 | test.notEqual(-1, css.indexOf('url(/extra/fonts/fontawesome-webfont.woff)'));
|
286 | test.notEqual(-1, css.indexOf('url(//fonts.googleapis.com/css?family=Roboto:400,300,500,500italic,700,900,400italic,700italic)'));
|
287 | test.notEqual(-1, css.indexOf('url(https://themes.googleusercontent.com/static/fonts/opensans/v8/MTP_ySUJH_bn48VBG8sNSnhCUOGz7vYGh680lGh-uXM.woff)'));
|
288 | test.ok(css.indexOf('url(data:image/png;base64') > 0);
|
289 |
|
290 | next();
|
291 | }]
|
292 | });
|
293 | };
|
294 |
|
295 | exports.testUploadImagesToCdn = function(test) {
|
296 |
|
297 | test.expect(2);
|
298 |
|
299 | th.runTest(test, {
|
300 | uploadImagesToCdn: [function(next) {
|
301 | assetProcessor.uploadImagesToCdn(next);
|
302 | }],
|
303 | download: ['uploadImagesToCdn', function(next, results) {
|
304 | const sampleImageUrl = results.uploadImagesToCdn+'/img_directory_2/purty_wood.png';
|
305 | request(sampleImageUrl, function(err, response, body) {
|
306 | next(err, !err && response.statusCode === 200 && (''+body).length);
|
307 | });
|
308 | }],
|
309 | assertResult: ['download', function(next, results) {
|
310 |
|
311 | test.ok(results.uploadImagesToCdn);
|
312 | test.ok(results.download > 10000);
|
313 |
|
314 | next();
|
315 | }]
|
316 | });
|
317 |
|
318 | };
|
319 |
|
320 | exports.testUploadExtrasToCdn = function(test) {
|
321 |
|
322 | test.expect(3);
|
323 |
|
324 | th.runTest(test, {
|
325 | uploadExtrasToCdn: [function(next) {
|
326 | assetProcessor.uploadExtrasToCdn(next);
|
327 | }],
|
328 | download: ['uploadExtrasToCdn', function(next, results) {
|
329 | const sampleImageUrl = results.uploadExtrasToCdn+'/fonts/FontAwesome.otf';
|
330 | request(sampleImageUrl, function(err, response, body) {
|
331 | next(err, !err && response.statusCode === 200 && (''+body).length);
|
332 | });
|
333 | }],
|
334 | assertResult: ['download', function(next, results) {
|
335 |
|
336 | test.ok(results.uploadExtrasToCdn);
|
337 | test.ok(results.uploadExtrasToCdn && results.uploadExtrasToCdn.toLowerCase().indexOf('s3') >= 0);
|
338 | test.ok(results.download > 10000);
|
339 |
|
340 | next();
|
341 | }]
|
342 | });
|
343 |
|
344 | };
|
345 |
|
346 | function _downloadAndUncompress(url, callback) {
|
347 | const stream = request(url).pipe(zlib.createGunzip());
|
348 | let uncompressed = '';
|
349 |
|
350 | stream.on('data', function(data) {
|
351 | uncompressed += data;
|
352 | });
|
353 |
|
354 | stream.on('error', function(err) {
|
355 | callback(err);
|
356 | });
|
357 |
|
358 | stream.on('end', function() {
|
359 | callback(null, uncompressed);
|
360 | });
|
361 | }
|
362 |
|
363 | exports.testEnsureAssets = function(test) {
|
364 |
|
365 | test.expect(8);
|
366 |
|
367 | th.runTest(test, {
|
368 | ensureAssets: [function(next) {
|
369 | assetProcessor.ensureAssets(next);
|
370 | }],
|
371 | assertResult: ['ensureAssets', function(next, results) {
|
372 | const ensureResult = results.ensureAssets || {};
|
373 |
|
374 | test.notEqual('undefined', typeof ensureResult.jsUrl);
|
375 | test.notEqual('undefined', typeof ensureResult.jsChanged);
|
376 | test.notEqual('undefined', typeof ensureResult.cssUrl);
|
377 | test.notEqual('undefined', typeof ensureResult.cssChanged);
|
378 | test.notEqual('undefined', typeof ensureResult.imagesUrl);
|
379 | test.notEqual('undefined', typeof ensureResult.imagesChanged);
|
380 | test.notEqual('undefined', typeof ensureResult.extrasUrl);
|
381 | test.notEqual('undefined', typeof ensureResult.extrasChanged);
|
382 |
|
383 | next();
|
384 | }]
|
385 | });
|
386 |
|
387 | };
|
388 |
|
389 | exports.testTargetFiles = function(test) {
|
390 |
|
391 |
|
392 | const otherAssetProcessor = _assetProcessorForTestConfig('test-config-2.json');
|
393 |
|
394 | test.expect(4);
|
395 |
|
396 | th.runTest(test, {
|
397 | getJavaScriptFiles: [function(next) {
|
398 | otherAssetProcessor.getJavaScriptFiles(next);
|
399 | }],
|
400 | getCssFiles: [function(next) {
|
401 | otherAssetProcessor.getCssFiles(next);
|
402 | }],
|
403 | getImageFiles: [function(next) {
|
404 | otherAssetProcessor.getImageFiles(next);
|
405 | }],
|
406 | getExtraFiles: [function(next) {
|
407 | otherAssetProcessor.getExtraFiles(next);
|
408 | }],
|
409 | assertResults: ['getJavaScriptFiles', 'getCssFiles', 'getImageFiles', 'getExtraFiles', function(next, results) {
|
410 |
|
411 | test.deepEqual(['test/test-files/js/js_directory_1/one.js', 'test/test-files/js/js_directory_2/two.js', 'test/test-files/js/js_directory_1/three.js'], results.getJavaScriptFiles);
|
412 | test.deepEqual(['test/test-files/css/css_directory_1/one.css', 'test/test-files/css/css_directory_2/two.css', 'test/test-files/css/css_directory_1/three.css', 'test/test-files/mixed/mixed_directory_1/four.css'], results.getCssFiles);
|
413 | test.deepEqual(['test/test-files/img/slash_it.png'], results.getImageFiles);
|
414 | test.deepEqual(['test/test-files/extra/swf/copy_csv_xls.swf', 'test/test-files/extra/fonts/FontAwesome.otf'], results.getExtraFiles);
|
415 |
|
416 | next();
|
417 | }]
|
418 | })
|
419 |
|
420 | };
|
421 |
|
422 | exports.testUploadExtrasToCdnCloudfront = function(test) {
|
423 |
|
424 |
|
425 | const otherAssetProcessor = _assetProcessorForTestConfig('test-config-3.json');
|
426 |
|
427 | test.expect(2);
|
428 |
|
429 | th.runTest(test, {
|
430 | uploadExtrasToCdn: [function(next) {
|
431 | otherAssetProcessor.uploadExtrasToCdn(next);
|
432 | }],
|
433 | assertResult: ['uploadExtrasToCdn', function(next, results) {
|
434 | test.ok(results.uploadExtrasToCdn && results.uploadExtrasToCdn.indexOf('cloudfront') >= 0);
|
435 | test.ok(results.uploadExtrasToCdn && results.uploadExtrasToCdn.indexOf('dummyCfMapping') >= 0);
|
436 | next();
|
437 | }]
|
438 | });
|
439 |
|
440 | };
|
441 |
|
442 | exports.testUseCloudFrontWithoutS3 = function(test) {
|
443 |
|
444 |
|
445 | const configPath = path.resolve(__dirname, 'test-files', 'test-config-5.json');
|
446 | const config = fs.readJsonFileSync(configPath);
|
447 | config.root = path.normalize(path.resolve(path.dirname(configPath), config.root || '.'));
|
448 | const otherAssetProcessor = new AssetProcessor(config);
|
449 |
|
450 | test.expect(1);
|
451 |
|
452 | th.runTest(test, {
|
453 | processAssets: [function(next) {
|
454 | otherAssetProcessor.processAssets(next);
|
455 | }],
|
456 | assertResult: ['processAssets', function(next, results) {
|
457 |
|
458 | const cssFilePath = path.resolve(__dirname, 'test-files', 'css', results.processAssets.cssUrl.split('/').pop());
|
459 | const cssFile = fs.readFileSync(cssFilePath).toString();
|
460 |
|
461 |
|
462 | test.ok(cssFile.indexOf('/img') >= 0);
|
463 | next();
|
464 | }]
|
465 | });
|
466 |
|
467 | };
|
468 |
|
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 |
|
489 |
|
490 |
|
491 |
|
492 |
|
493 |
|
494 |
|
495 |
|
496 |
|
497 |
|
498 |
|
499 |
|
500 |
|
501 |
|
502 |
|
503 |
|
504 |
|
505 |
|
506 |
|
507 |
|
508 |
|
509 |
|
510 |
|
511 |
|
512 |
|
513 |
|
514 |
|
515 |
|
516 |
|
517 |
|
518 |
|
519 |
|
520 | function _assetProcessorForTestConfig(configFile) {
|
521 |
|
522 | const configPath = path.resolve(__dirname, 'test-files', configFile);
|
523 | const config = fs.readJsonFileSync(configPath);
|
524 |
|
525 |
|
526 | config.s3 = _.extend(config.s3 || {}, credentials.s3);
|
527 | config.git = _.extend(config.git || {}, credentials.git);
|
528 |
|
529 | config.root = path.normalize(path.resolve(path.dirname(configPath), config.root || '.'));
|
530 |
|
531 | return new AssetProcessor(config);
|
532 | }
|