grunt-spritesmith
Version:
Grunt task for converting a set of images into a spritesheet and corresponding CSS variables.
271 lines (219 loc) • 10.5 kB
JavaScript
// Load in dependencies
var assert = require('assert');
var fs = require('fs');
var rimraf = require('rimraf');
var getPixels = require('get-pixels');
var gruntUtils = require('./utils/grunt');
// Set up default variables
var expectedDir = __dirname + '/expected_files/';
var actualDir = __dirname + '/scratch/';
// Clean up output directory
before(function cleanupActualDir(done) {
rimraf(actualDir, done);
});
// Start our tests
describe('grunt-spritesmith', function () {
describe('converting a set of images', function () {
gruntUtils.runTask('sprite:basic');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
it('generates an image', function (done) {
// Load in the images and compare them
getPixels(actualDir + 'sprite.basic.png', function handleActualPixels(err, actualImage) {
if (err) { return done(err); }
getPixels(expectedDir + 'pixelsmith.basic.png', function handleExpectedPixels(err, expectedImage) {
if (err) { return done(err); }
assert.deepEqual(actualImage, expectedImage, 'Actual image does not match expected image');
done();
});
});
});
it('generates CSS variables', function () {
// Load in the sprite positions
// TODO: Assert the same variables exist -- which means loading this into either Stylus or a meta-language
var expectedCoords = fs.readFileSync(expectedDir + 'sprite_positions.basic.styl', 'utf8');
var actualCoords = fs.readFileSync(actualDir + 'sprite_positions.basic.styl', 'utf8');
// Make sure the outputs match
assert.strictEqual(actualCoords, expectedCoords);
});
});
describe('converting a retina set of images', function () {
gruntUtils.runTask('sprite:retina');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
it('generates an image', function (done) {
// Load in the images and compare them
getPixels(actualDir + 'sprite.retina.png', function handleActualPixels(err, actualImage) {
if (err) { return done(err); }
getPixels(expectedDir + 'pixelsmith.retina.png', function handleExpectedPixels(err, expectedImage) {
if (err) { return done(err); }
assert.deepEqual(actualImage, expectedImage, 'Actual image does not match expected image');
done();
});
});
});
it('generates a retina image', function (done) {
// Load in the images and compare them
this.timeout(10000);
getPixels(actualDir + 'sprite.retina@2x.png', function handleActualPixels(err, actualImage) {
if (err) { return done(err); }
getPixels(expectedDir + 'pixelsmith.retina@2x.png', function handleExpectedPixels(err, expectedImage) {
if (err) { return done(err); }
assert.deepEqual(actualImage, expectedImage, 'Actual image does not match expected image');
done();
});
});
});
it('generates CSS and retina variables', function () {
// Load in the sprite positions
var expectedCoords = fs.readFileSync(expectedDir + 'sprite_positions.retina.styl', 'utf8');
var actualCoords = fs.readFileSync(actualDir + 'sprite_positions.retina.styl', 'utf8');
// Make sure the outputs match
assert.strictEqual(actualCoords, expectedCoords);
});
});
describe('generating a jpg and JSON', function () {
gruntUtils.runTask('sprite:jpg,json');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
it('generates a jpg', function () {
// Load in the images
var actualImage = fs.readFileSync(actualDir + 'sprite.basic.jpg', 'binary');
// Assert they are equal
// TODO: Perform more accurate assertion (currently skipped due to being a JPG)
assert(actualImage, 'Actual image does not match expected image');
});
it('generates JSON', function () {
// Load in the sprite positions
var expectedCoords = fs.readFileSync(expectedDir + 'sprite_positions.basic.json', 'utf8');
var actualCoords = fs.readFileSync(actualDir + 'sprite_positions.basic.json', 'utf8');
// Make sure the outputs match
assert.deepEqual(JSON.parse(actualCoords), JSON.parse(expectedCoords),
'Generated output doesn\'t match expected output.');
});
});
describe('running a task using overrides', function () {
gruntUtils.runTask('sprite:overrides');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
it('generates an image', function () {
// Load in the images
var actualImage = fs.readFileSync(actualDir + 'sprite.overrides.png', 'binary');
// Assert they are equal
// TODO: Perform more accurate assertion (currently skipped due to being a JPG)
assert(actualImage, 'Actual image does not match expected image');
});
it('generates coordinates', function () {
// Load in the sprite positions
var expectedCoords = fs.readFileSync(expectedDir + 'sprite_positions.overrides.styl', 'utf8');
var actualCoords = fs.readFileSync(actualDir + 'sprite_positions.overrides.styl', 'utf8');
// Make sure the outputs match
assert.deepEqual(JSON.parse(actualCoords), JSON.parse(expectedCoords),
'Generated output doesn\'t match expected output.');
});
});
describe('generating an image in a nested location', function () {
gruntUtils.runTask('sprite:nested');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
// TODO: Not entirely sure about the name of this test
it('resolves a collapsed path', function () {
// Load in the coordinates and extract the path to the sprite file
var coords = fs.readFileSync(actualDir + '3/4/sprite_positions.styl', 'utf8');
// Assert the path is the relative one we expect
assert.notEqual(coords.indexOf('../../nested/1/2/spritesheet.png'), -1);
});
});
});
// Edge cases
describe('grunt-spritesmith', function () {
// DEV: This is for testing an edge case -- don't let this strawman you in maintenance.
describe('running a task with no images', function () {
gruntUtils.runTask('sprite:empty');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
it('generates an empty image', function () {
var img = fs.readFileSync(actualDir + 'sprite.empty.png', 'binary');
assert.strictEqual(img, '');
});
it('generates no coordinates', function () {
var coords = fs.readFileSync(actualDir + 'sprite_positions.empty.json', 'utf8');
assert.strictEqual(coords, '{}');
});
});
// DEV: This is testing an edge case. CSS options are not critical for module functionality.
describe('running a task with css options', function () {
gruntUtils.runTask('sprite:cssOpts');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
it('uses the new selector', function () {
var expectedCoords = fs.readFileSync(expectedDir + 'sprite_positions.cssOpts.css', 'utf8');
var actualCoords = fs.readFileSync(actualDir + 'sprite_positions.cssOpts.css', 'utf8');
assert.strictEqual(actualCoords, expectedCoords, 'Generated output doesn\'t match expected output.');
});
});
// DEV: This is testing an edge case. A custom template is not critical for module functionality.
describe('running a task with a custom template function', function () {
gruntUtils.runTask('sprite:cssFunctionTemplate');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
it('uses the template', function () {
var expectedCoords = fs.readFileSync(expectedDir + 'sprite_positions.cssFunctionTemplate.styl', 'utf8');
var actualCoords = fs.readFileSync(actualDir + 'sprite_positions.cssFunctionTemplate.styl', 'utf8');
assert.strictEqual(actualCoords, expectedCoords, 'Generated output doesn\'t match expected output.');
});
});
// DEV: This is testing an edge case. A custom template is not critical for module functionality.
describe('running a task with a custom handlebars template', function () {
gruntUtils.runTask('sprite:cssHandlebarsTemplate');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
it('uses the template', function () {
var expectedCoords = fs.readFileSync(expectedDir + 'sprite_positions.cssHandlebarsTemplate.styl', 'utf8');
var actualCoords = fs.readFileSync(actualDir + 'sprite_positions.cssHandlebarsTemplate.styl', 'utf8');
assert.strictEqual(actualCoords, expectedCoords, 'Generated output doesn\'t match expected output.');
});
});
// DEV: This is testing an edge case. A custom template is not critical for module functionality.
describe('running a task with custom CSS variable names', function () {
gruntUtils.runTask('sprite:cssVarMap');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
it('uses the new variable names', function () {
var expectedCoords = fs.readFileSync(expectedDir + 'sprite_positions.cssVarMap.styl', 'utf8');
var actualCoords = fs.readFileSync(actualDir + 'sprite_positions.cssVarMap.styl', 'utf8');
assert.strictEqual(actualCoords, expectedCoords, 'Generated output doesn\'t match expected output.');
});
});
describe('running a retina task with custom CSS variable names', function () {
gruntUtils.runTask('sprite:retinaMapped');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
it('uses the new variable names', function () {
var expectedCoords = fs.readFileSync(expectedDir + 'sprite_positions.retinaMapped.styl', 'utf8');
var actualCoords = fs.readFileSync(actualDir + 'sprite_positions.retinaMapped.styl', 'utf8');
assert.strictEqual(actualCoords, expectedCoords, 'Generated output doesn\'t match expected output.');
});
});
});
describe('grunt-newer running grunt-spritesmith', function () {
gruntUtils.runTask('newer:sprite:newer');
it('has no errors', function () {
assert.strictEqual(this.err, null, this.stderr);
});
it('generates an image', function () {
var actualStats = fs.statSync(actualDir + 'sprite.newer.png');
assert(actualStats);
});
});