1 /* global it, afterEach, beforeEach, describe, Promise */
3 var assert = require('assert')
4 var gutil = require('gulp-util')
5 var sourceMaps = require('gulp-sourcemaps')
6 var postcss = require('./index')
7 var proxyquire = require('proxyquire')
8 var sinon = require('sinon')
9 var path = require('path')
11 it('should pass file when it isNull()', function (cb) {
12 var stream = postcss([ doubler ])
14 isNull: function () { return true }
17 stream.once('data', function (data) {
18 assert.equal(data, emptyFile)
22 stream.write(emptyFile)
27 it('should transform css with multiple processors', function (cb) {
30 [ asyncDoubler, objectDoubler() ]
33 stream.on('data', function (file) {
34 var result = file.contents.toString('utf8')
35 var target = 'a { color: black; color: black; color: black; color: black }'
36 assert.equal( result, target )
40 stream.write(new gutil.File({
41 contents: new Buffer('a { color: black }')
49 it('should correctly wrap postcss errors', function (cb) {
51 var stream = postcss([ doubler ])
53 stream.on('error', function (err) {
54 assert.ok(err instanceof gutil.PluginError)
55 assert.equal(err.plugin, 'gulp-postcss')
56 assert.equal(err.showStack, false)
57 assert.equal(err.fileName, 'testpath')
61 stream.write(new gutil.File({
62 contents: new Buffer('a {'),
70 it('should respond with error on stream files', function (cb) {
72 var stream = postcss([ doubler ])
74 stream.on('error', function (err) {
75 assert.ok(err instanceof gutil.PluginError)
76 assert.equal(err.plugin, 'gulp-postcss')
77 assert.equal(err.showStack, true)
78 assert.equal(err.fileName, 'testpath')
83 isStream: function () { return true },
84 isNull: function() { return false },
88 stream.write(streamFile)
94 it('should generate source maps', function (cb) {
96 var init = sourceMaps.init()
97 var write = sourceMaps.write()
99 [ doubler, asyncDoubler ]
106 write.on('data', function (file) {
107 assert.equal(file.sourceMap.mappings, 'AAAA,IAAI,aAAY,CAAZ,aAAY,CAAZ,aAAY,CAAZ,YAAY,EAAE')
108 assert(/sourceMappingURL=data:application\/json;(?:charset=\w+;)?base64/.test(file.contents.toString()))
112 init.write(new gutil.File({
114 path: __dirname + '/fixture.css',
115 contents: new Buffer('a { color: black }')
123 it('should correctly generate relative source map', function (cb) {
125 var init = sourceMaps.init()
132 css.on('data', function (file) {
133 assert.equal(file.sourceMap.file, 'fixture.css')
134 assert.deepEqual(file.sourceMap.sources, ['fixture.css'])
138 init.write(new gutil.File({
139 base: __dirname + '/src',
140 path: __dirname + '/src/fixture.css',
141 contents: new Buffer('a { color: black }')
149 describe('PostCSS Guidelines', function () {
151 var sandbox = sinon.sandbox.create()
152 var CssSyntaxError = function (message, sourceCode) {
153 this.name = 'CssSyntaxError'
154 this.message = message
155 this.sourceCode = sourceCode
156 this.showSourceCode = function () {
157 return this.sourceCode
162 , process: function () {}
164 var postcssLoadConfigStub
165 var postcss = proxyquire('./index', {
166 postcss: function (plugins) {
167 postcssStub.use(plugins)
170 , 'postcss-load-config': function (ctx, configPath) {
171 return postcssLoadConfigStub(ctx, configPath)
173 , 'vinyl-sourcemaps-apply': function () {
178 beforeEach(function () {
179 postcssLoadConfigStub = sandbox.stub()
180 sandbox.stub(postcssStub, 'use')
181 sandbox.stub(postcssStub, 'process')
184 afterEach(function () {
188 it('should set `from` and `to` processing options to `file.path`', function (cb) {
190 var stream = postcss([ doubler ])
191 var cssPath = __dirname + '/src/fixture.css'
192 postcssStub.process.returns(Promise.resolve({
194 , warnings: function () {
199 stream.on('data', function () {
200 assert.equal(postcssStub.process.getCall(0).args[1].to, cssPath)
201 assert.equal(postcssStub.process.getCall(0).args[1].from, cssPath)
205 stream.write(new gutil.File({
206 contents: new Buffer('a {}')
214 it('should allow override of `to` processing option', function (cb) {
216 var stream = postcss([ doubler ], {to: 'overriden'})
217 postcssStub.process.returns(Promise.resolve({
219 , warnings: function () {
224 stream.on('data', function () {
225 assert.equal(postcssStub.process.getCall(0).args[1].to, 'overriden')
229 stream.write(new gutil.File({
230 contents: new Buffer('a {}')
237 it('should take plugins and options from callback', function (cb) {
239 var cssPath = __dirname + '/fixture.css'
240 var file = new gutil.File({
241 contents: new Buffer('a {}')
244 var plugins = [ doubler ]
245 var callback = sandbox.stub().returns({
247 , options: { to: 'overriden' }
249 var stream = postcss(callback)
251 postcssStub.process.returns(Promise.resolve({
253 , warnings: function () {
258 stream.on('data', function () {
259 assert.equal(callback.getCall(0).args[0], file)
260 assert.equal(postcssStub.use.getCall(0).args[0], plugins)
261 assert.equal(postcssStub.process.getCall(0).args[1].to, 'overriden')
269 it('should take plugins and options from postcss-load-config', function (cb) {
271 var cssPath = __dirname + '/fixture.css'
272 var file = new gutil.File({
273 contents: new Buffer('a {}')
276 var stream = postcss({ to: 'initial' })
277 var plugins = [ doubler ]
279 postcssLoadConfigStub.returns(Promise.resolve({
281 , options: { to: 'overriden' }
284 postcssStub.process.returns(Promise.resolve({
286 , warnings: function () {
291 stream.on('data', function () {
292 assert.deepEqual(postcssLoadConfigStub.getCall(0).args[0], {
294 , options: { to: 'initial' }
296 assert.equal(postcssStub.use.getCall(0).args[0], plugins)
297 assert.equal(postcssStub.process.getCall(0).args[1].to, 'overriden')
305 it('should point the config location to file directory', function (cb) {
306 var cssPath = __dirname + '/fixture.css'
307 var stream = postcss()
308 postcssLoadConfigStub.returns(Promise.resolve({ plugins: [] }))
309 postcssStub.process.returns(Promise.resolve({
311 , warnings: function () {
315 stream.on('data', function () {
316 assert.deepEqual(postcssLoadConfigStub.getCall(0).args[1], __dirname)
319 stream.end(new gutil.File({
320 contents: new Buffer('a {}')
325 it('should set the config location from option', function (cb) {
326 var cssPath = __dirname + '/fixture.css'
327 var stream = postcss({ config: '/absolute/path' })
328 postcssLoadConfigStub.returns(Promise.resolve({ plugins: [] }))
329 postcssStub.process.returns(Promise.resolve({
331 , warnings: function () {
335 stream.on('data', function () {
336 assert.deepEqual(postcssLoadConfigStub.getCall(0).args[1], '/absolute/path')
339 stream.end(new gutil.File({
340 contents: new Buffer('a {}')
345 it('should set the config location from option relative to the base dir', function (cb) {
346 var cssPath = __dirname + '/src/fixture.css'
347 var stream = postcss({ config: './relative/path' })
348 postcssLoadConfigStub.returns(Promise.resolve({ plugins: [] }))
349 postcssStub.process.returns(Promise.resolve({
351 , warnings: function () {
355 stream.on('data', function () {
356 assert.deepEqual(postcssLoadConfigStub.getCall(0).args[1], __dirname + '/relative/path')
359 stream.end(new gutil.File({
360 contents: new Buffer('a {}')
366 it('should not override `from` and `map` if using gulp-sourcemaps', function (cb) {
367 var stream = postcss([ doubler ], { from: 'overriden', map: 'overriden' })
368 var cssPath = __dirname + '/fixture.css'
369 postcssStub.process.returns(Promise.resolve({
371 , warnings: function () {
375 toJSON: function () {
384 sandbox.stub(gutil, 'log')
386 stream.on('data', function () {
387 assert.deepEqual(postcssStub.process.getCall(0).args[1].from, cssPath)
388 assert.deepEqual(postcssStub.process.getCall(0).args[1].map, { annotation: false })
389 var firstMessage = gutil.log.getCall(0).args[1]
390 var secondMessage = gutil.log.getCall(1).args[1]
391 assert(firstMessage, '/fixture.css\nCannot override from option, because it is required by gulp-sourcemaps')
392 assert(secondMessage, '/fixture.css\nCannot override map option, because it is required by gulp-sourcemaps')
396 var file = new gutil.File({
397 contents: new Buffer('a {}')
404 it('should not output js stack trace for `CssSyntaxError`', function (cb) {
406 var stream = postcss([ doubler ])
407 var cssSyntaxError = new CssSyntaxError('message', 'sourceCode')
408 postcssStub.process.returns(Promise.reject(cssSyntaxError))
410 stream.on('error', function (error) {
411 assert.equal(error.showStack, false)
412 assert.equal(error.message, 'message' + '\n\nsourceCode\n')
416 stream.write(new gutil.File({
417 contents: new Buffer('a {}')
425 it('should display `result.warnings()` content', function (cb) {
427 var stream = postcss([ doubler ])
428 var cssPath = __dirname + '/src/fixture.css'
429 function Warning (msg) {
430 this.toString = function () {
435 sandbox.stub(gutil, 'log')
436 postcssStub.process.returns(Promise.resolve({
438 , warnings: function () {
439 return [new Warning('msg1'), new Warning('msg2')]
443 stream.on('data', function () {
444 assert(gutil.log.calledWith('gulp-postcss:', 'src' + path.sep + 'fixture.css\nmsg1\nmsg2'))
448 stream.write(new gutil.File({
449 contents: new Buffer('a {}')
457 it('should pass options down to PostCSS', function (cb) {
459 var customSyntax = function () {}
464 var stream = postcss([ doubler ], options)
465 var cssPath = __dirname + '/src/fixture.css'
466 postcssStub.process.returns(Promise.resolve({
468 , warnings: function () {
473 stream.on('data', function () {
474 var resultOptions = postcssStub.process.getCall(0).args[1]
475 // remove automatically set options
476 delete resultOptions.from
477 delete resultOptions.to
478 delete resultOptions.map
479 assert.deepEqual(resultOptions, options)
483 stream.write(new gutil.File({
484 contents: new Buffer('a {}')
495 function doubler (css) {
496 css.walkDecls(function (decl) {
497 decl.parent.prepend(decl.clone())
501 function asyncDoubler (css) {
502 return new Promise(function (resolve) {
503 setTimeout(function () {
510 function objectDoubler () {
511 var processor = require('postcss')()
512 processor.use(doubler)