Initial commit
[yaffs-website] / node_modules / node-sass / test / cli.js
1 var assert = require('assert'),
2   fs = require('fs'),
3   path = require('path'),
4   read = require('fs').readFileSync,
5   glob = require('glob'),
6   rimraf = require('rimraf'),
7   stream = require('stream'),
8   spawn = require('cross-spawn'),
9   cli = path.join(__dirname, '..', 'bin', 'node-sass'),
10   fixture = path.join.bind(null, __dirname, 'fixtures');
11
12 describe('cli', function() {
13   // For some reason we experience random timeout failures in CI
14   // due to spawn hanging/failing silently. See #1692.
15   this.retries(4);
16
17   describe('node-sass < in.scss', function() {
18     it('should read data from stdin', function(done) {
19       var src = fs.createReadStream(fixture('simple/index.scss'));
20       var expected = read(fixture('simple/expected.css'), 'utf8').trim();
21       var bin = spawn(cli);
22
23       bin.stdout.setEncoding('utf8');
24       bin.stdout.once('data', function(data) {
25         assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
26         done();
27       });
28
29       src.pipe(bin.stdin);
30     });
31
32     it('should compile sass using the --indented-syntax option', function(done) {
33       var src = fs.createReadStream(fixture('indent/index.sass'));
34       var expected = read(fixture('indent/expected.css'), 'utf8').trim();
35       var bin = spawn(cli, ['--indented-syntax']);
36
37       bin.stdout.setEncoding('utf8');
38       bin.stdout.once('data', function(data) {
39         assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
40         done();
41       });
42
43       src.pipe(bin.stdin);
44     });
45
46     it('should compile with the --quiet option', function(done) {
47       var src = fs.createReadStream(fixture('simple/index.scss'));
48       var expected = read(fixture('simple/expected.css'), 'utf8').trim();
49       var bin = spawn(cli, ['--quiet']);
50
51       bin.stdout.setEncoding('utf8');
52       bin.stdout.once('data', function(data) {
53         assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
54         done();
55       });
56
57       src.pipe(bin.stdin);
58     });
59
60     it('should compile with the --output-style option', function(done) {
61       var src = fs.createReadStream(fixture('compressed/index.scss'));
62       var expected = read(fixture('compressed/expected.css'), 'utf8').trim();
63       var bin = spawn(cli, ['--output-style', 'compressed']);
64
65       bin.stdout.setEncoding('utf8');
66       bin.stdout.once('data', function(data) {
67         assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
68         done();
69       });
70
71       src.pipe(bin.stdin);
72     });
73
74     it('should compile with the --source-comments option', function(done) {
75       var src = fs.createReadStream(fixture('source-comments/index.scss'));
76       var expected = read(fixture('source-comments/expected.css'), 'utf8').trim();
77       var bin = spawn(cli, ['--source-comments']);
78
79       bin.stdout.setEncoding('utf8');
80       bin.stdout.once('data', function(data) {
81         assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
82         done();
83       });
84
85       src.pipe(bin.stdin);
86     });
87
88     it('should render with indentWidth and indentType options', function(done) {
89       var src = new stream.Readable();
90       var bin = spawn(cli, ['--indent-width', 7, '--indent-type', 'tab']);
91
92       src._read = function() { };
93       src.push('div { color: transparent; }');
94       src.push(null);
95
96       bin.stdout.setEncoding('utf8');
97       bin.stdout.once('data', function(data) {
98         assert.equal(data.trim(), 'div {\n\t\t\t\t\t\t\tcolor: transparent; }');
99         done();
100       });
101
102       src.pipe(bin.stdin);
103     });
104
105     it('should render with linefeed option', function(done) {
106       var src = new stream.Readable();
107       var bin = spawn(cli, ['--linefeed', 'lfcr']);
108
109       src._read = function() { };
110       src.push('div { color: transparent; }');
111       src.push(null);
112
113       bin.stdout.setEncoding('utf8');
114       bin.stdout.once('data', function(data) {
115         assert.equal(data.trim(), 'div {\n\r  color: transparent; }');
116         done();
117       });
118
119       src.pipe(bin.stdin);
120     });
121   });
122
123   describe('node-sass in.scss', function() {
124     it('should compile a scss file', function(done) {
125       process.chdir(fixture('simple'));
126
127       var src = fixture('simple/index.scss');
128       var dest = fixture('simple/index.css');
129       var bin = spawn(cli, [src, dest]);
130
131       bin.once('close', function() {
132         assert(fs.existsSync(dest));
133         fs.unlinkSync(dest);
134         process.chdir(__dirname);
135         done();
136       });
137     });
138
139     it('should compile a scss file to custom destination', function(done) {
140       process.chdir(fixture('simple'));
141
142       var src = fixture('simple/index.scss');
143       var dest = fixture('simple/index-custom.css');
144       var bin = spawn(cli, [src, dest]);
145
146       bin.once('close', function() {
147         assert(fs.existsSync(dest));
148         fs.unlinkSync(dest);
149         process.chdir(__dirname);
150         done();
151       });
152     });
153
154     it('should compile with the --include-path option', function(done) {
155       var includePaths = [
156         '--include-path', fixture('include-path/functions'),
157         '--include-path', fixture('include-path/lib')
158       ];
159
160       var src = fixture('include-path/index.scss');
161       var expected = read(fixture('include-path/expected.css'), 'utf8').trim();
162       var bin = spawn(cli, [src].concat(includePaths));
163
164       bin.stdout.setEncoding('utf8');
165       bin.stdout.once('data', function(data) {
166         assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
167         done();
168       });
169     });
170
171     it('should compile silently using the --quiet option', function(done) {
172       process.chdir(fixture('simple'));
173
174       var src = fixture('simple/index.scss');
175       var dest = fixture('simple/index.css');
176       var bin = spawn(cli, [src, dest, '--quiet']);
177       var didEmit = false;
178
179       bin.stderr.once('data', function() {
180         didEmit = true;
181       });
182
183       bin.once('close', function() {
184         assert.equal(didEmit, false);
185         fs.unlinkSync(dest);
186         process.chdir(__dirname);
187         done();
188       });
189     });
190
191     it('should still report errors with the --quiet option', function(done) {
192       process.chdir(fixture('invalid'));
193
194       var src = fixture('invalid/index.scss');
195       var dest = fixture('invalid/index.css');
196       var bin = spawn(cli, [src, dest, '--quiet']);
197       var didEmit = false;
198
199       bin.stderr.once('data', function() {
200         didEmit = true;
201       });
202
203       bin.once('close', function() {
204         assert.equal(didEmit, true);
205         process.chdir(__dirname);
206         done();
207       });
208     });
209
210     it('should not exit with the --watch option', function(done) {
211       var src = fixture('simple/index.scss');
212       var bin = spawn(cli, [src, '--watch']);
213       var exited;
214
215       bin.once('close', function() {
216         exited = true;
217       });
218
219       setTimeout(function() {
220         if (exited) {
221           throw new Error('Watch ended too early!');
222         } else {
223           bin.kill();
224           done();
225         }
226       }, 100);
227     });
228
229     it.skip('should emit `warn` on file change when using --watch option', function(done) {
230       var src = fixture('simple/tmp.scss');
231
232       fs.writeFileSync(src, '');
233
234       var bin = spawn(cli, ['--watch', src]);
235
236       bin.stderr.setEncoding('utf8');
237       bin.stderr.once('data', function(data) {
238         assert.strictEqual(data.trim(), '=> changed: ' + src);
239         fs.unlinkSync(src);
240         bin.kill();
241         done();
242       });
243
244       setTimeout(function() {
245         fs.appendFileSync(src, 'body {}');
246       }, 500);
247     });
248
249     it.skip('should emit nothing on file change when using --watch and --quiet options', function(done) {
250       var src = fixture('simple/tmp.scss');
251       var didEmit = false;
252       fs.writeFileSync(src, '');
253
254       var bin = spawn(cli, ['--watch', '--quiet', src]);
255
256       bin.stderr.setEncoding('utf8');
257       bin.stderr.once('data', function() {
258         didEmit = true;
259       });
260
261       setTimeout(function() {
262         fs.appendFileSync(src, 'body {}');
263         setTimeout(function() {
264           assert.equal(didEmit, false);
265           bin.kill();
266           done();
267           fs.unlinkSync(src);
268         }, 200);
269       }, 500);
270     });
271
272     it.skip('should render all watched files', function(done) {
273       var src = fixture('simple/bar.scss');
274
275       fs.writeFileSync(src, '');
276
277       var bin = spawn(cli, [
278         '--output-style', 'compressed',
279         '--watch', src
280       ]);
281
282       bin.stdout.setEncoding('utf8');
283       bin.stdout.once('data', function(data) {
284         assert.strictEqual(data.trim(), 'body{background:white}');
285         fs.unlinkSync(src);
286         bin.kill();
287         done();
288       });
289
290       setTimeout(function() {
291         fs.appendFileSync(src, 'body{background:white}');
292       }, 500);
293     });
294
295     it.skip('should watch the full scss dep tree for a single file (scss)', function(done) {
296       var src = fixture('watching/index.scss');
297       var foo = fixture('watching/white.scss');
298
299       fs.writeFileSync(foo, '');
300
301       var bin = spawn(cli, [
302         '--output-style', 'compressed',
303         '--watch', src
304       ]);
305
306       bin.stdout.setEncoding('utf8');
307       bin.stdout.once('data', function(data) {
308         assert.strictEqual(data.trim(), 'body{background:blue}');
309         bin.kill();
310         done();
311       });
312
313       setTimeout(function() {
314         fs.appendFileSync(foo, 'body{background:blue}\n');
315       }, 500);
316     });
317
318     it.skip('should watch the full sass dep tree for a single file (sass)', function(done) {
319       var src = fixture('watching/index.sass');
320       var foo = fixture('watching/bar.sass');
321
322       fs.writeFileSync(foo, '');
323
324       var bin = spawn(cli, [
325         '--output-style', 'compressed',
326         '--watch', src
327       ]);
328
329       bin.stdout.setEncoding('utf8');
330       bin.stdout.once('data', function(data) {
331         assert.strictEqual(data.trim(), 'body{background:red}');
332         bin.kill();
333         done();
334       });
335
336       setTimeout(function() {
337         fs.appendFileSync(foo, 'body\n\tbackground: red\n');
338       }, 500);
339     });
340   });
341
342   describe('node-sass --output directory', function() {
343     it.skip('should watch whole directory', function(done) {
344       var destDir = fixture('watching-css-out-01/');
345       var srcDir = fixture('watching-dir-01/');
346       var srcFile = path.join(srcDir, 'index.scss');
347
348       fs.writeFileSync(srcFile, '');
349
350       var bin = spawn(cli, [
351         '--output-style', 'compressed',
352         '--output', destDir,
353         '--watch', srcDir
354       ]);
355
356       setTimeout(function() {
357         fs.appendFileSync(srcFile, 'a {color:green;}\n');
358         setTimeout(function() {
359           bin.kill();
360           var files = fs.readdirSync(destDir);
361           assert.deepEqual(files, ['index.css']);
362           rimraf(destDir, done);
363         }, 200);
364       }, 500);
365     });
366
367     it.skip('should compile all changed files in watched directory', function(done) {
368       var destDir = fixture('watching-css-out-02/');
369       var srcDir = fixture('watching-dir-02/');
370       var srcFile = path.join(srcDir, 'foo.scss');
371
372       fs.writeFileSync(srcFile, '');
373
374       var bin = spawn(cli, [
375         '--output-style', 'compressed',
376         '--output', destDir,
377         '--watch', srcDir
378       ]);
379
380       setTimeout(function () {
381         fs.appendFileSync(srcFile, 'body{background:white}\n');
382         setTimeout(function () {
383           bin.kill();
384           var files = fs.readdirSync(destDir);
385           assert.deepEqual(files, ['foo.css', 'index.css']);
386           rimraf(destDir, done);
387         }, 200);
388       }, 500);
389     });
390   });
391
392   describe('node-sass in.scss --output out.css', function() {
393     it('should compile a scss file to build.css', function(done) {
394       var src = fixture('simple/index.scss');
395       var dest = fixture('simple/index.css');
396       var bin = spawn(cli, [src, '--output', path.dirname(dest)]);
397
398       bin.once('close', function() {
399         assert(fs.existsSync(dest));
400         fs.unlinkSync(dest);
401         done();
402       });
403     });
404
405     it('should compile with the --source-map option', function(done) {
406       var src = fixture('source-map/index.scss');
407       var destCss = fixture('source-map/index.css');
408       var destMap = fixture('source-map/index.map');
409       var expectedCss = read(fixture('source-map/expected.css'), 'utf8').trim().replace(/\r\n/g, '\n');
410       var expectedMap = read(fixture('source-map/expected.map'), 'utf8').trim().replace(/\r\n/g, '\n');
411       var bin = spawn(cli, [src, '--output', path.dirname(destCss), '--source-map', destMap]);
412
413       bin.once('close', function() {
414         assert.equal(read(destCss, 'utf8').trim(), expectedCss);
415         assert.equal(read(destMap, 'utf8').trim(), expectedMap);
416         fs.unlinkSync(destCss);
417         fs.unlinkSync(destMap);
418         done();
419       });
420     });
421
422     it('should omit sourceMappingURL if --omit-source-map-url flag is used', function(done) {
423       var src = fixture('source-map/index.scss');
424       var dest = fixture('source-map/index.css');
425       var map = fixture('source-map/index.map');
426       var bin = spawn(cli, [
427         src, '--output', path.dirname(dest),
428         '--source-map', map, '--omit-source-map-url'
429       ]);
430
431       bin.once('close', function() {
432         assert.strictEqual(read(dest, 'utf8').indexOf('sourceMappingURL'), -1);
433         assert(fs.existsSync(map));
434         fs.unlinkSync(map);
435         fs.unlinkSync(dest);
436         done();
437       });
438     });
439
440     it('should compile with the --source-root option', function(done) {
441       var src = fixture('source-map/index.scss');
442       var destCss = fixture('source-map/index.css');
443       var destMap = fixture('source-map/index.map');
444       var expectedCss = read(fixture('source-map/expected.css'), 'utf8').trim().replace(/\r\n/g, '\n');
445       var expectedUrl = 'http://test/';
446       var bin = spawn(cli, [
447         src, '--output', path.dirname(destCss),
448         '--source-map-root', expectedUrl,
449         '--source-map', destMap
450       ]);
451
452       bin.once('close', function() {
453         assert.equal(read(destCss, 'utf8').trim(), expectedCss);
454         assert.equal(JSON.parse(read(destMap, 'utf8')).sourceRoot, expectedUrl);
455         fs.unlinkSync(destCss);
456         fs.unlinkSync(destMap);
457         done();
458       });
459     });
460
461     it('should compile with the --source-map-embed option and no outfile', function(done) {
462       var src = fixture('source-map-embed/index.scss');
463       var expectedCss = read(fixture('source-map-embed/expected.css'), 'utf8').trim().replace(/\r\n/g, '\n');
464       var result = '';
465       var bin = spawn(cli, [
466         src,
467         '--source-map-embed',
468         '--source-map', 'true'
469       ]);
470
471       bin.stdout.on('data', function(data) {
472         result += data;
473       });
474
475       bin.once('close', function() {
476         assert.equal(result.trim().replace(/\r\n/g, '\n'), expectedCss);
477         done();
478       });
479     });
480   });
481
482   describe('node-sass sass/ --output css/', function() {
483     it('should create the output directory', function(done) {
484       var src = fixture('input-directory/sass');
485       var dest = fixture('input-directory/css');
486       var bin = spawn(cli, [src, '--output', dest]);
487
488       bin.once('close', function() {
489         assert(fs.existsSync(dest));
490         rimraf.sync(dest);
491         done();
492       });
493     });
494
495     it('should compile all files in the folder', function(done) {
496       var src = fixture('input-directory/sass');
497       var dest = fixture('input-directory/css');
498       var bin = spawn(cli, [src, '--output', dest]);
499
500       bin.once('close', function() {
501         var files = fs.readdirSync(dest).sort();
502         assert.deepEqual(files, ['one.css', 'two.css', 'nested'].sort());
503         var nestedFiles = fs.readdirSync(path.join(dest, 'nested'));
504         assert.deepEqual(nestedFiles, ['three.css']);
505         rimraf.sync(dest);
506         done();
507       });
508     });
509
510     it('should compile with --source-map set to directory', function(done) {
511       var src = fixture('input-directory/sass');
512       var dest = fixture('input-directory/css');
513       var destMap = fixture('input-directory/map');
514       var bin = spawn(cli, [src, '--output', dest, '--source-map', destMap]);
515
516       bin.once('close', function() {
517         var map = JSON.parse(read(fixture('input-directory/map/nested/three.css.map'), 'utf8'));
518
519         assert.equal(map.file, '../../css/nested/three.css');
520         rimraf.sync(dest);
521         rimraf.sync(destMap);
522         done();
523       });
524     });
525
526     it('should skip files with an underscore', function(done) {
527       var src = fixture('input-directory/sass');
528       var dest = fixture('input-directory/css');
529       var bin = spawn(cli, [src, '--output', dest]);
530
531       bin.once('close', function() {
532         var files = fs.readdirSync(dest);
533         assert.equal(files.indexOf('_skipped.css'), -1);
534         rimraf.sync(dest);
535         done();
536       });
537     });
538
539     it('should ignore nested files if --recursive false', function(done) {
540       var src = fixture('input-directory/sass');
541       var dest = fixture('input-directory/css');
542       var bin = spawn(cli, [
543         src, '--output', dest,
544         '--recursive', false
545       ]);
546
547       bin.once('close', function() {
548         var files = fs.readdirSync(dest);
549         assert.deepEqual(files, ['one.css', 'two.css']);
550         rimraf.sync(dest);
551         done();
552       });
553     });
554
555     it('should error if no output directory is provided', function(done) {
556       var src = fixture('input-directory/sass');
557       var bin = spawn(cli, [src]);
558
559       bin.once('close', function(code) {
560         assert.notStrictEqual(code, 0);
561         assert.strictEqual(glob.sync(fixture('input-directory/**/*.css')).length, 0);
562         done();
563       });
564     });
565
566     it('should error if output directory is not a directory', function(done) {
567       var src = fixture('input-directory/sass');
568       var dest = fixture('input-directory/sass/one.scss');
569       var bin = spawn(cli, [src, '--output', dest]);
570
571       bin.once('close', function(code) {
572         assert.notStrictEqual(code, 0);
573         assert.equal(glob.sync(fixture('input-directory/**/*.css')).length, 0);
574         done();
575       });
576     });
577
578     it('should not error if output directory is a symlink', function(done) {
579       var outputDir = fixture('input-directory/css');
580       var src = fixture('input-directory/sass');
581       var symlink = fixture('symlinked-css');
582       fs.mkdirSync(outputDir);
583       fs.symlinkSync(outputDir, symlink);
584       var bin = spawn(cli, [src, '--output', symlink]);
585
586       bin.once('close', function() {
587         var files = fs.readdirSync(outputDir).sort();
588         assert.deepEqual(files, ['one.css', 'two.css', 'nested'].sort());
589         var nestedFiles = fs.readdirSync(path.join(outputDir, 'nested'));
590         assert.deepEqual(nestedFiles, ['three.css']);
591         rimraf.sync(outputDir);
592         fs.unlinkSync(symlink);
593         done();
594       });
595     });
596   });
597
598   describe('node-sass in.scss --output path/to/file/out.css', function() {
599     it('should create the output directory', function(done) {
600       var src = fixture('output-directory/index.scss');
601       var dest = fixture('output-directory/path/to/file/index.css');
602       var bin = spawn(cli, [src, '--output', path.dirname(dest)]);
603
604       bin.once('close', function() {
605         assert(fs.existsSync(path.dirname(dest)));
606         fs.unlinkSync(dest);
607         fs.rmdirSync(path.dirname(dest));
608         dest = path.dirname(dest);
609         fs.rmdirSync(path.dirname(dest));
610         dest = path.dirname(dest);
611         fs.rmdirSync(path.dirname(dest));
612         done();
613       });
614     });
615
616   });
617
618   describe('node-sass --follow --output output-dir input-dir', function() {
619     it('should compile with the --follow option', function(done) {
620       var src = fixture('follow/input-dir');
621       var dest = fixture('follow/output-dir');
622
623       fs.mkdirSync(src);
624       fs.symlinkSync(path.join(path.dirname(src), 'foo'), path.join(src, 'foo'), 'dir');
625
626       var bin = spawn(cli, [src, '--follow', '--output', dest]);
627
628       bin.once('close', function() {
629         var expected = path.join(dest, 'foo/bar/index.css');
630         fs.unlinkSync(path.join(src, 'foo'));
631         fs.rmdirSync(src);
632         assert(fs.existsSync(expected));
633         fs.unlinkSync(expected);
634         expected = path.dirname(expected);
635         fs.rmdirSync(expected);
636         expected = path.dirname(expected);
637         fs.rmdirSync(expected);
638         fs.rmdirSync(dest);
639         done();
640       });
641     });
642   });
643
644   describe('importer', function() {
645     var dest = fixture('include-files/index.css');
646     var src = fixture('include-files/index.scss');
647     var expected = read(fixture('include-files/expected-importer.css'), 'utf8').trim().replace(/\r\n/g, '\n');
648
649     it('should override imports and fire callback with file and contents', function(done) {
650       var bin = spawn(cli, [
651         src, '--output', path.dirname(dest),
652         '--importer', fixture('extras/my_custom_importer_file_and_data_cb.js')
653       ]);
654
655       bin.once('close', function() {
656         assert.equal(read(dest, 'utf8').trim(), expected);
657         fs.unlinkSync(dest);
658         done();
659       });
660     });
661
662     it('should override imports and fire callback with file', function(done) {
663       var bin = spawn(cli, [
664         src, '--output', path.dirname(dest),
665         '--importer', fixture('extras/my_custom_importer_file_cb.js')
666       ]);
667
668       bin.once('close', function() {
669         if (fs.existsSync(dest)) {
670           assert.equal(read(dest, 'utf8').trim(), '');
671           fs.unlinkSync(dest);
672         }
673
674         done();
675       });
676     });
677
678     it('should override imports and fire callback with data', function(done) {
679       var bin = spawn(cli, [
680         src, '--output', path.dirname(dest),
681         '--importer', fixture('extras/my_custom_importer_data_cb.js')
682       ]);
683
684       bin.once('close', function() {
685         assert.equal(read(dest, 'utf8').trim(), expected);
686         fs.unlinkSync(dest);
687         done();
688       });
689     });
690
691     it('should override imports and return file and contents', function(done) {
692       var bin = spawn(cli, [
693         src, '--output', path.dirname(dest),
694         '--importer', fixture('extras/my_custom_importer_file_and_data.js')
695       ]);
696
697       bin.once('close', function() {
698         assert.equal(read(dest, 'utf8').trim(), expected);
699         fs.unlinkSync(dest);
700         done();
701       });
702     });
703
704     it('should override imports and return file', function(done) {
705       var bin = spawn(cli, [
706         src, '--output', path.dirname(dest),
707         '--importer', fixture('extras/my_custom_importer_file.js')
708       ]);
709
710       bin.once('close', function() {
711         if (fs.existsSync(dest)) {
712           assert.equal(read(dest, 'utf8').trim(), '');
713           fs.unlinkSync(dest);
714         }
715
716         done();
717       });
718     });
719
720     it('should override imports and return data', function(done) {
721       var bin = spawn(cli, [
722         src, '--output', path.dirname(dest),
723         '--importer', fixture('extras/my_custom_importer_data.js')
724       ]);
725
726       bin.once('close', function() {
727         assert.equal(read(dest, 'utf8').trim(), expected);
728         fs.unlinkSync(dest);
729         done();
730       });
731     });
732
733     it('should accept arrays of importers and return respect the order', function(done) {
734       var bin = spawn(cli, [
735         src, '--output', path.dirname(dest),
736         '--importer', fixture('extras/my_custom_arrays_of_importers.js')
737       ]);
738
739       bin.once('close', function() {
740         assert.equal(read(dest, 'utf8').trim(), expected);
741         fs.unlinkSync(dest);
742         done();
743       });
744     });
745
746     it('should return error for invalid importer file path', function(done) {
747       var bin = spawn(cli, [
748         src, '--output', path.dirname(dest),
749         '--importer', fixture('non/existing/path')
750       ]);
751
752       bin.once('close', function(code) {
753         assert.notStrictEqual(code, 0);
754         done();
755       });
756     });
757
758     it('should reflect user-defined Error', function(done) {
759       var bin = spawn(cli, [
760         src, '--output', path.dirname(dest),
761         '--importer', fixture('extras/my_custom_importer_error.js')
762       ]);
763
764       bin.stderr.once('data', function(code) {
765         assert.equal(JSON.parse(code).message, 'doesn\'t exist!');
766         done();
767       });
768     });
769   });
770
771   describe('functions', function() {
772     it('should let custom functions call setter methods on wrapped sass values (number)', function(done) {
773       var dest = fixture('custom-functions/setter.css');
774       var src = fixture('custom-functions/setter.scss');
775       var expected = read(fixture('custom-functions/setter-expected.css'), 'utf8').trim().replace(/\r\n/g, '\n');
776       var bin = spawn(cli, [
777         src, '--output', path.dirname(dest),
778         '--functions', fixture('extras/my_custom_functions_setter.js')
779       ]);
780
781       bin.once('close', function() {
782         assert.equal(read(dest, 'utf8').trim(), expected);
783         fs.unlinkSync(dest);
784         done();
785       });
786     });
787
788     it('should properly convert strings when calling custom functions', function(done) {
789       var dest = fixture('custom-functions/string-conversion.css');
790       var src = fixture('custom-functions/string-conversion.scss');
791       var expected = read(fixture('custom-functions/string-conversion-expected.css'), 'utf8').trim().replace(/\r\n/g, '\n');
792       var bin = spawn(cli, [
793         src, '--output', path.dirname(dest),
794         '--functions', fixture('extras/my_custom_functions_string_conversion.js')
795       ]);
796
797       bin.once('close', function() {
798         assert.equal(read(dest, 'utf8').trim(), expected);
799         fs.unlinkSync(dest);
800         done();
801       });
802     });
803   });
804 });