diff --git a/gulpfile.js b/gulpfile.js index 776df90..79e0ed9 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -36,6 +36,11 @@ gulp.task('linting', function() { .pipe(stylish.combineWithHintResults()) // combine with jshint results .pipe(jshint.reporter('jshint-stylish')); // use any jshint reporter to log hint }); +gulp.task('runtest', function() { + var mocha = require('gulp-mocha'); + return gulp.src('test/basic.js', { read: false }) + .pipe(mocha()); +}); gulp.task('watch', function() { @@ -46,4 +51,4 @@ gulp.task('watch', function() { gulp.task('project', ['project:basic']); gulp.task('default', ['watch']); -gulp.task('test', ['linting']); +gulp.task('test', ['linting', 'runtest']); diff --git a/index.js b/index.js index 8218d8d..1bf9b72 100644 --- a/index.js +++ b/index.js @@ -29,7 +29,7 @@ var GROUP_MASK = '*'; var BACKGROUND = 'background'; var BACKGROUND_IMAGE = 'background-image'; -module.exports = postcss.plugin('postcss-easysprite', function(opts) { +module.exports = postcss.plugin('postcss-easysprites', function(opts) { opts = opts || {}; // opts @@ -99,7 +99,8 @@ function collectImages(css, opts) { return; } - image.groups = [imageUrl.hash.replace('#', '')]; + image.hash = imageUrl.hash.replace('#', ''); + image.groups = [image.hash]; // Perform search for retina if (isRetinaImage(image.url)) { @@ -109,6 +110,18 @@ function collectImages(css, opts) { // Get the path to the image. image.path = resolveUrl(image, opts); + // file exists + if (!fs.existsSync(image.path)) { + log('Easysprites:', gutil.colors.red(image.path), 'file unreachable or not exists'); + + // remove hash from link + lodash.each(rule.nodes, function(node) { + node.value = node.value.replace('#' + image.hash, ''); + }); + + return rule; + } + images.push(image); } }); @@ -295,7 +308,7 @@ function saveSprites(images, opts, sprites) { // if this file is up to date if (sprite.isFromCache) { var deferred = Q.defer(); - log('Easysprite:', gutil.colors.green(sprite.path), 'unchanged.'); + log('Easysprites:', gutil.colors.green(sprite.path), 'unchanged.'); deferred.resolve(sprite); return deferred.promise; } @@ -303,7 +316,7 @@ function saveSprites(images, opts, sprites) { // save new file version return Q.nfcall(fs.writeFile, sprite.path, new Buffer(sprite.image, 'binary')) .then(function() { - log('Easysprite:', gutil.colors.yellow(sprite.path), 'generated.'); + log('Easysprites:', gutil.colors.yellow(sprite.path), 'generated.'); return sprite; }); }) diff --git a/test/basic.js b/test/basic.js old mode 100644 new mode 100755 index 7243cc2..6dfdeda --- a/test/basic.js +++ b/test/basic.js @@ -1,17 +1,130 @@ + var postcss = require('postcss'); var expect = require('chai').expect; var plugin = require('../'); -var assert = function (input, output, opts, done) { - postcss([ plugin(opts) ]).process(input).then(function (result) { - expect(result.css).to.eql(output); - expect(result.warnings()).to.be.empty; - done(); - }).catch(function (error) { - done(error); - }); +function cacheLog() { + console.logback = console.log; + console.log = function(){ + var args = Array.prototype.slice.call(arguments); + console.logback.apply(console, ['cached'].concat(args)); + console.lastMessage = Array.prototype.slice.call(arguments).join(' '); + }; +} + +function uncacheLog() { + console.log = console.logback; + return console.lastMessage; +} + +var assert = function(input, output, opts, done) { + postcss([plugin(opts)]).process(input).then(function(result) { + expect(result.css).to.eql(output); + expect(result.warnings()).to.be.empty; + done(); + }).catch(function(error) { + done(error); + }); +}; + +var assertCached = function(input, output, opts, done) { + cacheLog(); + + postcss([plugin(opts)]).process(input).then(function(result) { + expect(result.css).to.eql(output); + expect(result.warnings()).to.be.empty; + + if (uncacheLog().indexOf('unchanged') === -1) { + return done(new Error('Cache is not working')); + } + + done(); + }).catch(function(error) { + done(error); + }); }; -describe('postcss-easysprite', function (done) { - assert('a {}', 'a {}', {}, done); +var assertNotCached = function(input, output, opts, done) { + cacheLog(); + + postcss([plugin(opts)]).process(input).then(function(result) { + expect(result.css).to.eql(output); + expect(result.warnings()).to.be.empty; + if (uncacheLog().indexOf('generated') === -1) { + return done(new Error('Sprite already cached, code red!')); + } + + done(); + }).catch(function(error) { + done(error); + }); +}; + +describe('postcss-easysprites', function() { + + it('Relative images test', function(done) { + assert( + 'a { background: url("images/arrow-next.png#elements"); }', + 'a { background-image: url(sprites/elements.png); background-position: 0 0; }', + { + stylesheetPath:'./test/basic', + spritePath: './test/basic/sprites', + }, done); + }); + + it('Absolute images test', function(done) { + assert( + 'a { background: url("/images/arrow-next.png#elements"); }', + 'a { background-image: url(sprites/elements.png); background-position: 0 0; }', + { + imagePath:'./test/basic', + stylesheetPath:'./test/basic', // need here cause of inline call + spritePath: './test/basic/sprites', + }, done); + }); + + it('Retina images test', function(done) { + assert( + 'a { background: url("/images/arrow-next@2x.png#elements"); }', + 'a { background-image: url(sprites/elements@2x.png); background-position: 0 0; background-size: 28px 27px; }', + { + imagePath:'./test/basic', + stylesheetPath:'./test/basic', // need here cause of inline call + spritePath: './test/basic/sprites', + }, done); + }); + + it('Not exists image test', function(done) { + assert( + 'a { background: url("/images/image-not-exists.png#elements"); }', + 'a { background: url("/images/image-not-exists.png"); }', + { + imagePath:'./test/basic', + stylesheetPath:'./test/basic', // need here cause of inline call + spritePath: './test/basic/sprites', + }, done); + }); + + it('Assert sprite not cached', function(done) { + assertNotCached( + 'a { background: url("images/arrow-next_hover.png#elements"); }', + 'a { background-image: url(sprites/elements.png); background-position: 0 0; }', + { + imagePath:'./test/basic', + stylesheetPath:'./test/basic', // need here cause of inline call + spritePath: './test/basic/sprites', + }, done); + }); + + it('Assert sprite cached', function(done) { + assertCached( + 'a { background: url("images/arrow-next_hover.png#elements"); }', + 'a { background-image: url(sprites/elements.png); background-position: 0 0; }', + { + imagePath:'./test/basic', + stylesheetPath:'./test/basic', // need here cause of inline call + spritePath: './test/basic/sprites', + }, done); + }); + }); diff --git a/test/basic/sprites/elements.png b/test/basic/sprites/elements.png index 21e6420..f3df995 100644 Binary files a/test/basic/sprites/elements.png and b/test/basic/sprites/elements.png differ diff --git a/test/basic/sprites/elements@2x.png b/test/basic/sprites/elements@2x.png index 46c5e55..dba4529 100644 Binary files a/test/basic/sprites/elements@2x.png and b/test/basic/sprites/elements@2x.png differ