cli.js 25 KB

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