cli.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. var assert = require('assert'),
  2. fs = require('fs'),
  3. path = require('path'),
  4. read = require('fs').readFileSync,
  5. spawn = require('cross-spawn'),
  6. cli = path.join(__dirname, '..', 'bin', 'node-sass'),
  7. fixture = path.join.bind(null, __dirname, 'fixtures');
  8. describe('cli', function() {
  9. describe('node-sass < in.scss', function() {
  10. it('should read data from stdin', function(done) {
  11. var src = fs.createReadStream(fixture('simple/index.scss'));
  12. var expected = read(fixture('simple/expected.css'), 'utf8').trim();
  13. var bin = spawn(cli, ['--stdout']);
  14. bin.stdout.setEncoding('utf8');
  15. bin.stdout.once('data', function(data) {
  16. assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
  17. done();
  18. });
  19. src.pipe(bin.stdin);
  20. });
  21. it('should compile sass using the --indented-syntax option', function(done) {
  22. var src = fs.createReadStream(fixture('indent/index.sass'));
  23. var expected = read(fixture('indent/expected.css'), 'utf8').trim();
  24. var bin = spawn(cli, ['--stdout', '--indented-syntax']);
  25. bin.stdout.setEncoding('utf8');
  26. bin.stdout.once('data', function(data) {
  27. assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
  28. done();
  29. });
  30. src.pipe(bin.stdin);
  31. });
  32. it('should compile with the --output-style option', function(done) {
  33. var src = fs.createReadStream(fixture('compressed/index.scss'));
  34. var expected = read(fixture('compressed/expected.css'), 'utf8').trim();
  35. var bin = spawn(cli, ['--stdout', '--output-style', 'compressed']);
  36. bin.stdout.setEncoding('utf8');
  37. bin.stdout.once('data', function(data) {
  38. assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
  39. done();
  40. });
  41. src.pipe(bin.stdin);
  42. });
  43. it('should compile with the --source-comments option', function(done) {
  44. var src = fs.createReadStream(fixture('source-comments/index.scss'));
  45. var expected = read(fixture('source-comments/expected.css'), 'utf8').trim();
  46. var bin = spawn(cli, ['--stdout', '--source-comments']);
  47. bin.stdout.setEncoding('utf8');
  48. bin.stdout.once('data', function(data) {
  49. assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
  50. done();
  51. });
  52. src.pipe(bin.stdin);
  53. });
  54. it('should compile with the --image-path option', function(done) {
  55. var src = fs.createReadStream(fixture('image-path/index.scss'));
  56. var expected = read(fixture('image-path/expected.css'), 'utf8').trim();
  57. var bin = spawn(cli, ['--stdout', '--image-path', '/path/to/images']);
  58. bin.stdout.setEncoding('utf8');
  59. bin.stdout.once('data', function(data) {
  60. assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
  61. done();
  62. });
  63. src.pipe(bin.stdin);
  64. });
  65. });
  66. describe('node-sass in.scss', function() {
  67. it('should compile a scss file', function(done) {
  68. process.chdir(fixture('simple'));
  69. var src = fixture('simple/index.scss');
  70. var dest = fixture('simple/index.css');
  71. var bin = spawn(cli, [src]);
  72. bin.on('close', function() {
  73. assert(fs.existsSync(dest));
  74. fs.unlinkSync(dest);
  75. process.chdir(__dirname);
  76. done();
  77. });
  78. });
  79. it('should compile a scss file to custom destination', function(done) {
  80. process.chdir(fixture('simple'));
  81. var src = fixture('simple/index.scss');
  82. var dest = fixture('simple/index-custom.css');
  83. var bin = spawn(cli, [src, dest]);
  84. bin.on('close', function() {
  85. assert(fs.existsSync(dest));
  86. fs.unlinkSync(dest);
  87. process.chdir(__dirname);
  88. done();
  89. });
  90. });
  91. it('should compile with the --include-path option', function(done) {
  92. var includePaths = [
  93. '--include-path', fixture('include-path/functions'),
  94. '--include-path', fixture('include-path/lib')
  95. ];
  96. var src = fixture('include-path/index.scss');
  97. var expected = read(fixture('include-path/expected.css'), 'utf8').trim();
  98. var bin = spawn(cli, [src, '--stdout'].concat(includePaths));
  99. bin.stdout.setEncoding('utf8');
  100. bin.stdout.once('data', function(data) {
  101. assert.equal(data.trim(), expected.replace(/\r\n/g, '\n'));
  102. done();
  103. });
  104. });
  105. it('should not exit with the --watch option', function(done) {
  106. var src = fixture('simple/index.scss');
  107. var bin = spawn(cli, [src, '--stdout', '--watch']);
  108. var exited;
  109. bin.on('close', function () {
  110. exited = true;
  111. });
  112. setTimeout(function() {
  113. if (exited) {
  114. throw new Error('Watch ended too early!');
  115. } else {
  116. bin.kill();
  117. done();
  118. }
  119. }, 100);
  120. });
  121. it('should emit `warn` on file change when using --watch option', function(done) {
  122. fs.writeFileSync(fixture('simple/tmp.scss'), '');
  123. var src = fixture('simple/tmp.scss');
  124. var bin = spawn(cli, [src, '--stdout', '--watch']);
  125. bin.stderr.setEncoding('utf8');
  126. bin.stderr.on('data', function(data) {
  127. assert(data.trim() === '=> changed: ' + src);
  128. bin.kill();
  129. fs.unlinkSync(src);
  130. done();
  131. });
  132. setTimeout(function() {
  133. fs.appendFileSync(src, 'body {}');
  134. }, 500);
  135. });
  136. it('should render all watched files', function(done) {
  137. fs.writeFileSync(fixture('simple/foo.scss'), '');
  138. fs.writeFileSync(fixture('simple/bar.scss'), '');
  139. var src = fixture('simple/foo.scss');
  140. var watched = fixture('simple/bar.scss');
  141. var bin = spawn(cli, [
  142. src, '--stdout', '--watch', watched,
  143. '--output-style', 'compressed'
  144. ]);
  145. bin.stdout.setEncoding('utf8');
  146. bin.stdout.on('data', function(data) {
  147. assert(data.trim() === 'body{background:white}');
  148. bin.kill();
  149. fs.unlinkSync(src);
  150. fs.unlinkSync(watched);
  151. done();
  152. });
  153. setTimeout(function() {
  154. fs.appendFileSync(watched, 'body{background:white}');
  155. }, 500);
  156. });
  157. });
  158. describe('node-sass in.scss --output out.css', function() {
  159. it('should compile a scss file to build.css', function(done) {
  160. var src = fixture('simple/index.scss');
  161. var dest = fixture('simple/index.css');
  162. var bin = spawn(cli, [src, '--output', path.dirname(dest)]);
  163. bin.on('close', function() {
  164. assert(fs.existsSync(dest));
  165. fs.unlinkSync(dest);
  166. done();
  167. });
  168. });
  169. it('should compile with the --source-map option', function(done) {
  170. var src = fixture('source-map/index.scss');
  171. var destCss = fixture('source-map/index.css');
  172. var destMap = fixture('source-map/index.map');
  173. var expectedCss = read(fixture('source-map/expected.css'), 'utf8').trim().replace(/\r\n/g, '\n');
  174. var expectedMap = read(fixture('source-map/expected.map'), 'utf8').trim().replace(/\r\n/g, '\n');
  175. var bin = spawn(cli, [src, '--output', path.dirname(destCss), '--source-map', destMap]);
  176. bin.on('close', function () {
  177. assert.equal(read(destCss, 'utf8').trim(), expectedCss);
  178. assert.equal(read(destMap, 'utf8').trim(), expectedMap);
  179. fs.unlinkSync(destMap);
  180. fs.unlinkSync(destCss);
  181. done();
  182. });
  183. });
  184. it('should omit sourceMappingURL if --omit-source-map-url flag is used', function(done) {
  185. var src = fixture('source-map/index.scss');
  186. var dest = fixture('source-map/index.css');
  187. var map = fixture('source-map/index.map');
  188. var bin = spawn(cli, [
  189. src, '--output', path.dirname(dest),
  190. '--source-map', map, '--omit-source-map-url'
  191. ]);
  192. bin.on('close', function () {
  193. assert(read(dest, 'utf8').indexOf('sourceMappingURL') === -1);
  194. assert(fs.existsSync(map));
  195. fs.unlinkSync(map);
  196. fs.unlinkSync(dest);
  197. done();
  198. });
  199. });
  200. });
  201. describe('node-sass in.scss --output path/to/file/out.css', function() {
  202. it('should create the output directory', function(done) {
  203. var src = fixture('output-directory/index.scss');
  204. var dest = fixture('output-directory/path/to/file/index.css');
  205. var bin = spawn(cli, [src, '--output', path.dirname(dest)]);
  206. bin.on('close', function() {
  207. assert(fs.existsSync(path.dirname(dest)));
  208. fs.unlinkSync(dest);
  209. fs.rmdirSync(path.dirname(dest));
  210. dest = path.dirname(dest);
  211. fs.rmdirSync(path.dirname(dest));
  212. dest = path.dirname(dest);
  213. fs.rmdirSync(path.dirname(dest));
  214. done();
  215. });
  216. });
  217. });
  218. describe('importer', function() {
  219. var dest = fixture('include-files/index.css');
  220. var src = fixture('include-files/index.scss');
  221. var expected = read(fixture('include-files/expected-importer.css'), 'utf8').trim().replace(/\r\n/g, '\n');
  222. it('should override imports and fire callback with file and contents', function(done) {
  223. var bin = spawn(cli, [
  224. src, '--output', path.dirname(dest),
  225. '--importer', fixture('extras/my_custom_importer_file_and_data_cb.js')
  226. ]);
  227. bin.on('close', function () {
  228. assert.equal(read(dest, 'utf8').trim(), expected);
  229. fs.unlinkSync(dest);
  230. done();
  231. });
  232. });
  233. it('should override imports and fire callback with file', function(done) {
  234. var bin = spawn(cli, [
  235. src, '--output', path.dirname(dest),
  236. '--importer', fixture('extras/my_custom_importer_file_cb.js')
  237. ]);
  238. bin.on('close', function () {
  239. if (fs.existsSync(dest)) {
  240. assert.equal(read(dest, 'utf8').trim(), '');
  241. fs.unlinkSync(dest);
  242. }
  243. done();
  244. });
  245. });
  246. it('should override imports and fire callback with data', function(done) {
  247. var bin = spawn(cli, [
  248. src, '--output', path.dirname(dest),
  249. '--importer', fixture('extras/my_custom_importer_data_cb.js')
  250. ]);
  251. bin.on('close', function () {
  252. assert.equal(read(dest, 'utf8').trim(), expected);
  253. fs.unlinkSync(dest);
  254. done();
  255. });
  256. });
  257. it('should override imports and return file and contents', function(done) {
  258. var bin = spawn(cli, [
  259. src, '--output', path.dirname(dest),
  260. '--importer', fixture('extras/my_custom_importer_file_and_data.js')
  261. ]);
  262. bin.on('close', function () {
  263. assert.equal(read(dest, 'utf8').trim(), expected);
  264. fs.unlinkSync(dest);
  265. done();
  266. });
  267. });
  268. it('should override imports and return file', function(done) {
  269. var bin = spawn(cli, [
  270. src, '--output', path.dirname(dest),
  271. '--importer', fixture('extras/my_custom_importer_file.js')
  272. ]);
  273. bin.on('close', function () {
  274. if (fs.existsSync(dest)) {
  275. assert.equal(read(dest, 'utf8').trim(), '');
  276. fs.unlinkSync(dest);
  277. }
  278. done();
  279. });
  280. });
  281. it('should override imports and return data', function(done) {
  282. var bin = spawn(cli, [
  283. src, '--output', path.dirname(dest),
  284. '--importer', fixture('extras/my_custom_importer_data.js')
  285. ]);
  286. bin.on('close', function () {
  287. assert.equal(read(dest, 'utf8').trim(), expected);
  288. fs.unlinkSync(dest);
  289. done();
  290. });
  291. });
  292. it('should return error on for invalid importer file path', function(done) {
  293. var bin = spawn(cli, [
  294. src, '--output', path.dirname(dest),
  295. '--importer', fixture('non/existing/path')
  296. ]);
  297. bin.on('close', function (code) {
  298. assert(code !== 0);
  299. done();
  300. });
  301. });
  302. });
  303. });