switched from jshint to xo

This commit is contained in:
Ben Zörb 2015-11-13 22:59:10 +01:00
parent 9a63dc291d
commit ae3f2ba581
8 changed files with 497 additions and 574 deletions

View File

@ -2,7 +2,7 @@ root = true
[*]
indent_style = space
indent_size = 2
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true

View File

@ -1,4 +0,0 @@
{
"laxcomma": true,
"node": true
}

View File

@ -1,52 +0,0 @@
// Generated on 2014-08-03 using generator-nodejs 2.0.1
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
complexity: {
generic: {
src: ['app/**/*.js'],
options: {
errorsOnly: false,
cyclometric: 6, // default is 3
halstead: 16, // default is 8
maintainability: 100 // default is 100
}
}
},
jshint: {
all: [
'Gruntfile.js',
'app/**/*.js',
'test/**/*.js'
],
options: {
jshintrc: true
}
},
mochacli: {
all: ['test/**/*.js'],
options: {
reporter: 'spec',
ui: 'bdd',
timeout: 10000
}
},
watch: {
js: {
files: ['**/*.js', '!node_modules/**/*.js'],
tasks: ['default'],
options: {
nospawn: true
}
}
}
});
grunt.loadNpmTasks('grunt-complexity');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-mocha-cli');
grunt.registerTask('test', ['complexity', 'jshint', 'mochacli', 'watch']);
grunt.registerTask('ci', ['complexity', 'jshint', 'mochacli']);
grunt.registerTask('default', ['test']);
};

193
cli.js
View File

@ -11,130 +11,127 @@ var inlineCritical = require('./');
var ok;
var help = [
'Usage: inline-critical <input> [<option>]',
'',
'Options:',
' -c, --css Path to CSS file',
' -h, --html Path to HTML file',
' -i, --ignore Skip matching stylesheets',
' -m, --minify Minify the styles before inlining',
' -e, --extract Remove the inlined styles from any stylesheets referenced in the HTML',
' -b, --base Is used when extracting styles to find the files references by `href` attributes',
' -s, --selector Optionally defines the element used by loadCSS as a reference for inlining'
'Usage: inline-critical <input> [<option>]',
'',
'Options:',
' -c, --css Path to CSS file',
' -h, --html Path to HTML file',
' -i, --ignore Skip matching stylesheets',
' -m, --minify Minify the styles before inlining',
' -e, --extract Remove the inlined styles from any stylesheets referenced in the HTML',
' -b, --base Is used when extracting styles to find the files references by `href` attributes',
' -s, --selector Optionally defines the element used by loadCSS as a reference for inlining'
];
var cli = meow({
help: help
help: help
}, {
alias: {
c: 'css',
h: 'html',
i: 'ignore',
m: 'minify',
b: 'base',
e: 'extract',
s: 'selector'
}
alias: {
c: 'css',
h: 'html',
i: 'ignore',
m: 'minify',
b: 'base',
e: 'extract',
s: 'selector'
}
});
// cleanup cli flags
cli.flags = _.reduce(cli.flags, function (res, val, key) {
if (key.length <= 1) {
if (key.length <= 1) {
return res;
}
switch (key) {
case 'css':
case 'html':
try {
res[key] = read(val);
} catch (err) {
}
break;
case 'base':
res.basePath = val;
break;
case 'ignore':
if (_.isString(val) || _.isRegExp(val)) {
val = [val];
}
res.ignore = _.map(val || [], function (ignore) {
// check regex
var match = ignore.match(/^\/(.*)\/([igmy]+)?$/);
if (match) {
return new RegExp(_.escapeRegExp(match[1]), match[2]);
}
return ignore;
});
break;
default:
res[key] = val;
break;
}
return res;
}
switch (key) {
case 'css':
case 'html':
try {
res[key] = read(val)
} catch (err) {
}
break;
case 'base':
res.basePath = val;
break;
case 'ignore':
if (_.isString(val) || _.isRegExp(val)) {
val = [val];
}
res.ignore = _.map(val || [], function (ignore) {
// check regex
var match = ignore.match(/^\/(.*)\/([igmy]+)?$/);
if (match) {
return new RegExp(_.escapeRegExp(match[1]), match[2]);
}
return ignore;
});
break;
default:
res[key] = val;
break;
}
return res;
}, {});
function error(err) {
process.stderr.write(indentString(err.message || err, ' Error: '));
process.stderr.write(os.EOL);
process.stderr.write(indentString(help.join(os.EOL), ' '));
process.exit(1);
process.stderr.write(indentString(err.message || err, ' Error: '));
process.stderr.write(os.EOL);
process.stderr.write(indentString(help.join(os.EOL), ' '));
process.exit(1);
}
function read(file) {
try {
return fs.readFileSync(file, 'utf8');
} catch (err) {
error(err);
}
try {
return fs.readFileSync(file, 'utf8');
} catch (err) {
error(err);
}
}
function run(data) {
var opts = _.defaults(cli.flags, {basePath: process.cwd()});
ok = true;
var opts = _.defaults(cli.flags, {basePath: process.cwd()});
ok = true;
if (data) {
// detect html
try {
css.parse(data);
opts.css = data;
} catch (err) {
opts.html = data;
if (data) {
// detect html
try {
css.parse(data);
opts.css = data;
} catch (err) {
opts.html = data;
}
}
}
_.forEach(cli.input, function (file) {
var tmp = read(file);
try {
css.parse(tmp);
opts.css = tmp;
} catch (err) {
opts.html = tmp;
_.forEach(cli.input, function (file) {
var tmp = read(file);
try {
css.parse(tmp);
opts.css = tmp;
} catch (err) {
opts.html = tmp;
}
});
if (!opts.html || !opts.css) {
cli.showHelp();
}
});
if (!opts.html || !opts.css) {
cli.showHelp();
}
try {
var out = inlineCritical(opts.html, opts.css, opts);
console.log(out.toString());
} catch (err) {
error(err);
}
try {
var out = inlineCritical(opts.html, opts.css, opts);
console.log(out.toString());
} catch (err) {
error(err);
}
}
// get stdin
stdin().then(run);
setTimeout(function () {
if (ok) {
return;
}
run();
if (ok) {
return;
}
run();
}, 100);

153
index.js
View File

@ -13,7 +13,7 @@
var _ = require('lodash');
var fs = require('fs');
var path = require('path');
var UglifyJS = require("uglify-js");
var UglifyJS = require('uglify-js');
var cave = require('cave');
var reaver = require('reaver');
var cheerio = require('cheerio');
@ -26,14 +26,13 @@ var resolve = require('resolve');
var loadCSS = read(resolve.sync('fg-loadcss'));
loadCSS = UglifyJS.minify(loadCSS, {fromString: true}).code;
/**
* Fixup slashes in file paths for windows
* @param {string} str
* @return {string}
*/
function normalizePath(str) {
return process.platform === 'win32' ? slash(str) : str;
return process.platform === 'win32' ? slash(str) : str;
}
/**
@ -42,94 +41,88 @@ function normalizePath(str) {
* @returns {string}
*/
function read(file) {
return fs.readFileSync(file, 'utf8');
return fs.readFileSync(file, 'utf8');
}
module.exports = function (html, styles, options) {
var $ = cheerio.load(String(html), {
decodeEntities: false
});
var links = $('link[rel="stylesheet"]').filter(function () {
return !$(this).parents('noscript').length;
});
var o = options || {};
var target = o.selector || links.get(0) || $('script').get(0);
var $target = $(target);
if (_.isString(o.ignore)) {
o.ignore = [o.ignore];
}
if (o.ignore) {
links = links.filter(function () {
var href = $(this).attr('href');
return _.findIndex(o.ignore, function (arg) {
return _.isRegExp(arg) && arg.test(href) || arg === href;
}) === -1;
var $ = cheerio.load(String(html), {
decodeEntities: false
});
}
// minify if minify option is set
if (o.minify) {
styles = new CleanCSS().minify(styles).styles;
}
var links = $('link[rel="stylesheet"]').filter(function () {
return !$(this).parents('noscript').length;
});
var o = options || {};
var target = o.selector || links.get(0) || $('script').get(0);
var $target = $(target);
// insert inline styles right before first <link rel="stylesheet" />
$target.before('<style type="text/css">\n' + styles + '\n</style>\n');
if (links.length) {
var noscript = $('<noscript>\n</noscript>');
// insert noscript block right after stylesheets
$target.after(noscript);
var hrefs = links.map(function (idx, el) {
return $(this).attr('href');
}).toArray();
// extract styles from stylesheets if extract option is set
if (o.extract) {
if (!o.basePath) {
throw new Error('Option `basePath` is missing and required when using `extract`!');
}
hrefs = hrefs.map(function (href) {
var file = path.resolve(path.join(o.basePath, href));
if (!fs.existsSync(file)) {
return href;
}
var diff = normalizeNewline(cave(file, {css: styles}));
fs.writeFileSync(reaver.rev(file, diff), diff);
return normalizePath(reaver.rev(href, diff));
});
if (_.isString(o.ignore)) {
o.ignore = [o.ignore];
}
// wrap links to stylesheets in noscript block so that they will evaluated when js is turned off
links.each(function (idx) {
var el = $(this);
el.attr('href', hrefs[idx]);
noscript.append(el);
noscript.append('\n');
});
if (o.ignore) {
links = links.filter(function () {
var href = $(this).attr('href');
return _.findIndex(o.ignore, function (arg) {
return _.isRegExp(arg) && arg.test(href) || arg === href;
}) === -1;
});
}
// build js block to load blocking stylesheets and insert it right before
noscript.before('<script id="loadcss">\n' +
'(function(u,s){' +
loadCSS +
'for(var i in u){loadCSS(u[i],s);}' +
'}([\'' + hrefs.join('\',\'') + '\'],document.getElementById("loadcss")));\n' +
'</script>\n');
}
// minify if minify option is set
if (o.minify) {
styles = new CleanCSS().minify(styles).styles;
}
// insert inline styles right before first <link rel="stylesheet" />
$target.before('<style type="text/css">\n' + styles + '\n</style>\n');
var dom = parse($.html());
var markup = render(dom);
if (links.length) {
var noscript = $('<noscript>\n</noscript>');
return new Buffer(markup);
// insert noscript block right after stylesheets
$target.after(noscript);
var hrefs = links.map(function (idx, el) {
return $(el).attr('href');
}).toArray();
// extract styles from stylesheets if extract option is set
if (o.extract) {
if (!o.basePath) {
throw new Error('Option `basePath` is missing and required when using `extract`!');
}
hrefs = hrefs.map(function (href) {
var file = path.resolve(path.join(o.basePath, href));
if (!fs.existsSync(file)) {
return href;
}
var diff = normalizeNewline(cave(file, {css: styles}));
fs.writeFileSync(reaver.rev(file, diff), diff);
return normalizePath(reaver.rev(href, diff));
});
}
// wrap links to stylesheets in noscript block so that they will evaluated when js is turned off
links.each(function (idx) {
var el = $(this);
el.attr('href', hrefs[idx]);
noscript.append(el);
noscript.append('\n');
});
// build js block to load blocking stylesheets and insert it right before
noscript.before('<script id="loadcss">\n' +
'(function(u,s){' +
loadCSS +
'for(var i in u){loadCSS(u[i],s);}' +
'}([\'' + hrefs.join('\',\'') + '\'],document.getElementById("loadcss")));\n' +
'</script>\n');
}
var dom = parse($.html());
var markup = render(dom);
return new Buffer(markup);
};

View File

@ -4,12 +4,11 @@
"description": "Inline critical-path css and load the existing stylesheets asynchronously",
"main": "index.js",
"scripts": {
"test": "node_modules/.bin/grunt ci"
"test": "xo && mocha test/index.js"
},
"files": [
"index.js",
"cli.js",
"lib/loadCSS.js"
"cli.js"
],
"bin": "cli.js",
"repository": {
@ -46,13 +45,19 @@
},
"devDependencies": {
"chai": "3.4.1",
"grunt": "0.4.5",
"grunt-cli": "0.1.13",
"grunt-complexity": "0.3.0",
"grunt-contrib-jshint": "0.11.3",
"grunt-contrib-watch": "0.6.1",
"grunt-mocha-cli": "2.0.0",
"mocha": "2.3.3",
"mockery": "1.4.0",
"read-package-json": "2.0.2"
"read-package-json": "2.0.2",
"xo": "0.11.0"
},
"xo": {
"space": 4,
"envs": [
"node",
"mocha"
],
"ignores": [
"test/*.js"
]
}
}

View File

@ -1,6 +0,0 @@
{
"mocha": true,
"expr": true,
"laxcomma": true,
"node": true
}

View File

@ -1,5 +1,4 @@
'use strict';
var expect = require('chai').expect;
var reaver = require('reaver');
var fs = require('fs');
@ -12,385 +11,376 @@ var inlineCritical = require('..');
var skipWin = process.platform === 'win32' ? it.skip : it;
function strip(string) {
return string.replace(/[\r\n]+/mg,' ').replace(/\s+/gm,'');
return string.replace(/[\r\n]+/mg, ' ').replace(/\s+/gm, '');
}
function read (file) {
return fs.readFileSync(file, 'utf8');
function read(file) {
return fs.readFileSync(file, 'utf8');
}
describe('Module: inline-critical', function() {
it('should inline css', function(done) {
var html = read('test/fixtures/index.html');
var css = read('test/fixtures/critical.css');
describe('Module: inline-critical', function () {
it('should inline css', function (done) {
var html = read('test/fixtures/index.html');
var css = read('test/fixtures/critical.css');
var expected = read('test/expected/index-inlined-async-final.html');
var out = inlineCritical(html, css);
var expected = read('test/expected/index-inlined-async-final.html');
var out = inlineCritical(html, css);
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
done();
});
it('should inline absolute css', function(done) {
var html = read('test/fixtures/index-absolute.html');
var css = read('test/fixtures/critical.css');
it('should inline absolute css', function (done) {
var html = read('test/fixtures/index-absolute.html');
var css = read('test/fixtures/critical.css');
var expected = read('test/expected/index-inlined-absolute.html');
var out = inlineCritical(html, css);
var expected = read('test/expected/index-inlined-absolute.html');
var out = inlineCritical(html, css);
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
done();
});
it('should inline and minify css', function (done) {
var html = read('test/fixtures/index.html');
var css = read('test/fixtures/critical.css');
it('should inline and minify css', function(done) {
var html = read('test/fixtures/index.html');
var css = read('test/fixtures/critical.css');
var expected = read('test/expected/index-inlined-async-minified-final.html');
var out = inlineCritical(html, css, {minify: true});
var expected = read('test/expected/index-inlined-async-minified-final.html');
var out = inlineCritical(html, css, { minify: true });
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
done();
});
it('should inline and extract css', function (done) {
var html = read('test/fixtures/cartoon.html');
var css = read('test/fixtures/critical.css');
var expected = read('test/expected/cartoon-expected.css');
var expectedHtml = read('test/expected/cartoon-expected.html');
var out = inlineCritical(html, css, {extract: true, basePath: 'test/fixtures'});
it('should inline and extract css', function(done) {
var html = read('test/fixtures/cartoon.html');
var css = read('test/fixtures/critical.css');
var expected = read('test/expected/cartoon-expected.css');
var expectedHtml = read('test/expected/cartoon-expected.html');
expect(read(reaver.rev('test/fixtures/css/cartoon.css', expected))).to.be.equal(expected);
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expectedHtml));
var out = inlineCritical(html, css, { extract: true, basePath: 'test/fixtures' });
done();
});
expect(read(reaver.rev('test/fixtures/css/cartoon.css', expected))).to.be.equal(expected);
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expectedHtml));
it('should inline and extract css correctly with absolute paths', function (done) {
var html = read('test/fixtures/cartoon-absolute.html');
var css = read('test/fixtures/critical.css');
var expected = read('test/expected/cartoon-expected.css');
var expectedHtml = read('test/expected/cartoon-absolute-expected.html');
done();
});
var out = inlineCritical(html, css, {extract: true, basePath: 'test/fixtures'});
it('should inline and extract css correctly with absolute paths', function(done) {
var html = read('test/fixtures/cartoon-absolute.html');
var css = read('test/fixtures/critical.css');
var expected = read('test/expected/cartoon-expected.css');
var expectedHtml = read('test/expected/cartoon-absolute-expected.html');
expect(read(reaver.rev('test/fixtures/css/cartoon.css', expected))).to.be.equal(expected);
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expectedHtml));
var out = inlineCritical(html, css, { extract: true, basePath: 'test/fixtures' });
done();
});
expect(read(reaver.rev('test/fixtures/css/cartoon.css', expected))).to.be.equal(expected);
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expectedHtml));
it('should not strip of svg closing tags', function (done) {
var html = read('test/fixtures/entities.html');
var out = inlineCritical(html, '');
done();
});
expect(strip(out.toString('utf-8'))).to.be.equal(strip(html));
done();
});
it('should not strip of svg closing tags', function(done) {
var html = read('test/fixtures/entities.html');
var out = inlineCritical(html, '');
it('should not keep external urls', function (done) {
function strip2(string) {
return string.replace(/\s+/gm, '');
}
expect(strip(out.toString('utf-8'))).to.be.equal(strip(html));
done();
});
var html = read('test/fixtures/external.html');
var expected = read('test/expected/external-expected.html');
var css = read('test/fixtures/critical.css');
var out = inlineCritical(html, css);
it('should not keep external urls', function(done) {
expect(strip2(out.toString('utf-8'))).to.be.equal(strip2(expected));
done();
});
function strip2(string) {
return string.replace(/\s+/gm,'');
}
it('should not keep external urls on extract', function (done) {
function strip2(string) {
return string.replace(/\s+/gm, '');
}
var html = read('test/fixtures/external.html');
var expected = read('test/expected/external-expected.html');
var css = read('test/fixtures/critical.css');
var out = inlineCritical(html, css);
var html = read('test/fixtures/external.html');
var expected = read('test/expected/external-extract-expected.html');
var css = read('test/fixtures/critical.css');
var out = inlineCritical(html, css, {extract: true, basePath: 'test/fixtures'});
expect(strip2(out.toString('utf-8'))).to.be.equal(strip2(expected));
done();
});
expect(strip2(out.toString('utf-8'))).to.be.equal(strip2(expected));
done();
});
it('should not keep external urls on extract', function(done) {
it('should keep self closing svg elements', function (done) {
var html = read('test/fixtures/entities2.html');
var out = inlineCritical(html, '');
expect(strip(out.toString('utf-8'))).to.be.equal(strip(html));
done();
});
function strip2(string) {
return string.replace(/\s+/gm,'');
}
it('should respect ignore option with string', function (done) {
function strip2(string) {
return string.replace(/\s+/gm, '');
}
var html = read('test/fixtures/external.html');
var expected = read('test/expected/external-extract-expected.html');
var css = read('test/fixtures/critical.css');
var out = inlineCritical(html, css, { extract: true, basePath: 'test/fixtures' });
var html = read('test/fixtures/external.html');
var expected = read('test/expected/external-ignore-expected.html');
var css = read('test/fixtures/critical.css');
var out = inlineCritical(html, css, {ignore: ['bower_components/bootstrap/dist/css/bootstrap.css']});
expect(strip2(out.toString('utf-8'))).to.be.equal(strip2(expected));
done();
});
expect(strip2(out.toString('utf-8'))).to.be.equal(strip2(expected));
done();
});
it('should respect ignore option with RegExp', function (done) {
function strip2(string) {
return string.replace(/\s+/gm, '');
}
it('should keep self closing svg elements', function(done) {
var html = read('test/fixtures/entities2.html');
var out = inlineCritical(html, '');
expect(strip(out.toString('utf-8'))).to.be.equal(strip(html));
done();
});
var html = read('test/fixtures/external.html');
var expected = read('test/expected/external-ignore-expected.html');
var css = read('test/fixtures/critical.css');
var out = inlineCritical(html, css, {ignore: [/bootstrap/]});
it('should respect ignore option with string', function(done) {
function strip2(string) {
return string.replace(/\s+/gm,'');
}
expect(strip2(out.toString('utf-8'))).to.be.equal(strip2(expected));
done();
});
var html = read('test/fixtures/external.html');
var expected = read('test/expected/external-ignore-expected.html');
var css = read('test/fixtures/critical.css');
var out = inlineCritical(html, css, {ignore: ['bower_components/bootstrap/dist/css/bootstrap.css']});
it('should respect selector option', function (done) {
var html = read('test/fixtures/index.html');
var css = read('test/fixtures/critical.css');
expect(strip2(out.toString('utf-8'))).to.be.equal(strip2(expected));
done();
});
it('should respect ignore option with RegExp', function(done) {
function strip2(string) {
return string.replace(/\s+/gm,'');
}
var expected = read('test/expected/index-before.html');
var out = inlineCritical(html, css, {minify: true, selector: 'title'});
var html = read('test/fixtures/external.html');
var expected = read('test/expected/external-ignore-expected.html');
var css = read('test/fixtures/critical.css');
var out = inlineCritical(html, css, {ignore: [/bootstrap/]});
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
expect(strip2(out.toString('utf-8'))).to.be.equal(strip2(expected));
done();
});
done();
});
it('should respect selector option', function(done) {
var html = read('test/fixtures/index.html');
var css = read('test/fixtures/critical.css');
it('should ignore stylesheets wrapped in noscript', function (done) {
var html = read('test/fixtures/index-noscript.html');
var css = read('test/fixtures/critical.css');
var expected = read('test/expected/index-before.html');
var out = inlineCritical(html, css, { minify: true, selector: 'title' });
var expected = read('test/expected/index-noscript-inlined-minified-final.html');
var out = inlineCritical(html, css, {minify: true});
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
done();
});
it('should ignore stylesheets wrapped in noscript', function(done) {
var html = read('test/fixtures/index-noscript.html');
var css = read('test/fixtures/critical.css');
it('should skip loadcss if it\'s already present and used for all existing link tags', function (done) {
var html = read('test/fixtures/loadcss.html');
var css = read('test/fixtures/critical.css');
var expected = read('test/expected/index-noscript-inlined-minified-final.html');
var out = inlineCritical(html, css, { minify: true });
var expected = read('test/expected/index-loadcss.html');
var out = inlineCritical(html, css, {minify: true});
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
it('should skip loadcss if it\'s already present and used for all existing link tags', function(done) {
var html = read('test/fixtures/loadcss.html');
var css = read('test/fixtures/critical.css');
var expected = read('test/expected/index-loadcss.html');
var out = inlineCritical(html, css, { minify: true });
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
expect(strip(out.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
});
describe('CLI', function () {
beforeEach(function(done){
readJson(path.join(__dirname, '../','package.json'),function(err,data){
this.pkg = data;
this.bin = path.join(__dirname, '../', data.bin['inline-critical']);
done();
}.bind(this));
});
describe('acceptance', function () {
// empty stdout on appveyor? runs correct on manual test with Windows 7
skipWin('should return the version', function (done) {
execFile('node', [this.bin, '--version'], function(error, stdout){
expect(stdout.replace(/\r\n|\n/g, '')).to.equal(this.pkg.version);
done();
}.bind(this));
beforeEach(function (done) {
readJson(path.join(__dirname, '../', 'package.json'), function (err, data) {
expect(err).to.not.exist;
this.pkg = data;
this.bin = path.join(__dirname, '../', data.bin['inline-critical']);
done();
}.bind(this));
});
it('should work well with the critical CSS & html file passed as input', function (done) {
var expected = read('test/expected/index-inlined-async-final.html');
var cp = execFile('node', [
this.bin,
'test/fixtures/index.html',
'test/fixtures/critical.css'
]);
describe('acceptance', function () {
// empty stdout on appveyor? runs correct on manual test with Windows 7
skipWin('should return the version', function (done) {
execFile('node', [this.bin, '--version'], function (error, stdout) {
expect(stdout.replace(/\r\n|\n/g, '')).to.equal(this.pkg.version);
done();
}.bind(this));
});
cp.stdout.on('data', function (data) {
expect(strip(data.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
it('should work well with the critical CSS & html file passed as input', function (done) {
var expected = read('test/expected/index-inlined-async-final.html');
var cp = execFile('node', [
this.bin,
'test/fixtures/index.html',
'test/fixtures/critical.css'
]);
cp.stdout.on('data', function (data) {
expect(strip(data.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
});
it('should work well with the critical CSS passed as input & html file passed as option', function (done) {
var expected = read('test/expected/index-inlined-async-final.html');
var cp = execFile('node', [
this.bin,
'--html',
'test/fixtures/index.html',
'test/fixtures/critical.css'
]);
cp.stdout.on('data', function (data) {
expect(strip(data.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
});
it('should work well with the critical CSS passed as option & html file passed as input', function (done) {
var expected = read('test/expected/index-inlined-async-final.html');
var cp = execFile('node', [
this.bin,
'--css',
'test/fixtures/critical.css',
'test/fixtures/index.html'
]);
cp.stdout.on('data', function (data) {
expect(strip(data.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
});
// pipes don't work on windows
skipWin('should work well with the critical CSS file piped to inline-critical and html file as input', function (done) {
var cp = exec('cat test/fixtures/critical.css | node ' + this.bin + ' test/fixtures/index.html');
var expected = read('test/expected/index-inlined-async-final.html');
cp.stdout.on('data', function (data) {
expect(strip(data.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
});
skipWin('should work well with the html file piped to inline-critical and critical CSS file as input', function (done) {
var cp = exec('cat test/fixtures/index.html | node ' + this.bin + ' test/fixtures/critical.css');
var expected = read('test/expected/index-inlined-async-final.html');
cp.stdout.on('data', function (data) {
expect(strip(data.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
});
it('should exit with code 1 and show help', function (done) {
execFile('node', [this.bin, 'fixtures/not-exists.html'], function (err, stdout, stderr) {
expect(err).to.exist;
expect(err.code).equal(1);
expect(stderr).to.have.string('Usage:');
done();
});
});
});
it('should work well with the critical CSS passed as input & html file passed as option', function (done) {
var expected = read('test/expected/index-inlined-async-final.html');
var cp = execFile('node', [
this.bin,
'--html',
'test/fixtures/index.html',
'test/fixtures/critical.css'
]);
describe('mocked', function () {
beforeEach(function () {
this.origArgv = process.argv;
this.origExit = process.exit;
this.stdout = process.stdout.write;
this.stderr = process.stderr.write;
cp.stdout.on('data', function (data) {
expect(strip(data.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
mockery.enable({
warnOnUnregistered: false,
useCleanCache: true
});
mockery.registerMock('./', function (html, styles, options) {
this.mockOpts = options;
this.mockOpts.html = html;
this.mockOpts.css = styles;
return '';
}.bind(this));
});
afterEach(function () {
mockery.deregisterAll();
mockery.disable();
process.argv = this.origArgv;
process.exit = this.origExit;
});
it('should pass the correct opts when using short opts', function (done) {
process.argv = [
'node',
this.bin,
'-c', 'test/fixtures/critical.css',
'-h', 'test/fixtures/index.html',
'-i', 'ignore-me',
'-i', '/regexp/',
'-b', 'basePath',
'-s', 'selector',
'-m',
'-e'
];
process.stdout.write = function () {
};
process.stderr.write = function () {
};
require('../cli');
// timeout to wait for get-stdin timeout
setTimeout(function () {
process.stdout.write = this.stdout;
process.stderr.write = this.stderr;
expect(this.mockOpts.css).to.equal(read('test/fixtures/critical.css'));
expect(this.mockOpts.html).to.equal(read('test/fixtures/index.html'));
expect(this.mockOpts.selector).to.equal('selector');
expect(this.mockOpts.ignore).to.be.instanceof(Array);
expect(this.mockOpts.ignore[0]).to.be.a('string');
expect(this.mockOpts.ignore[1]).to.instanceof(RegExp);
expect(this.mockOpts.minify).to.be.ok;
expect(this.mockOpts.extract).to.be.ok;
done();
}.bind(this), 200);
});
it('should pass the correct opts when using long opts', function (done) {
process.argv = [
'node',
this.bin,
'--css', 'test/fixtures/critical.css',
'--html', 'test/fixtures/index.html',
'--ignore', 'ignore-me',
'--ignore', '/regexp/',
'--base', 'basePath',
'--selector', 'selector',
'--minify',
'--extract'
];
process.stdout.write = function () {
};
process.stderr.write = function () {
};
require('../cli');
// timeout to wait for get-stdin timeout
setTimeout(function () {
process.stdout.write = this.stdout;
process.stderr.write = this.stderr;
expect(this.mockOpts.css).to.equal(read('test/fixtures/critical.css'));
expect(this.mockOpts.html).to.equal(read('test/fixtures/index.html'));
expect(this.mockOpts.selector).to.equal('selector');
expect(this.mockOpts.ignore).to.be.instanceof(Array);
expect(this.mockOpts.ignore[0]).to.be.a('string');
expect(this.mockOpts.ignore[1]).to.instanceof(RegExp);
expect(this.mockOpts.minify).to.be.ok;
expect(this.mockOpts.extract).to.be.ok;
done();
}.bind(this), 200);
});
});
it('should work well with the critical CSS passed as option & html file passed as input', function (done) {
var expected = read('test/expected/index-inlined-async-final.html');
var cp = execFile('node', [
this.bin,
'--css',
'test/fixtures/critical.css',
'test/fixtures/index.html'
]);
cp.stdout.on('data', function (data) {
expect(strip(data.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
});
// pipes don't work on windows
skipWin('should work well with the critical CSS file piped to inline-critical and html file as input', function (done) {
var cp = exec('cat test/fixtures/critical.css | node ' + this.bin + ' test/fixtures/index.html');
var expected = read('test/expected/index-inlined-async-final.html');
cp.stdout.on('data', function (data) {
expect(strip(data.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
});
skipWin('should work well with the html file piped to inline-critical and critical CSS file as input', function (done) {
var cp = exec('cat test/fixtures/index.html | node ' + this.bin + ' test/fixtures/critical.css');
var expected = read('test/expected/index-inlined-async-final.html');
cp.stdout.on('data', function (data) {
expect(strip(data.toString('utf-8'))).to.be.equal(strip(expected));
done();
});
});
it('should exit with code 1 and show help', function (done) {
execFile('node', [this.bin, 'fixtures/not-exists.html'], function(err, stdout, stderr){
//noinspection BadExpressionStatementJS
expect(err).to.exist;
expect(err.code).equal(1);
expect(stderr).to.have.string('Usage:');
done();
});
});
});
describe('mocked', function () {
beforeEach(function () {
this.origArgv = process.argv;
this.origExit = process.exit;
this.stdout = process.stdout.write;
this.stderr = process.stderr.write;
mockery.enable({
warnOnUnregistered: false,
useCleanCache: true
});
mockery.registerMock('./', function (html, styles, options) {
this.mockOpts = options;
this.mockOpts.html = html;
this.mockOpts.css = styles;
return '';
}.bind(this));
});
afterEach(function () {
mockery.deregisterAll();
mockery.disable();
process.argv = this.origArgv;
process.exit = this.origExit;
});
it('should pass the correct opts when using short opts', function (done) {
process.argv = [
'node',
this.bin,
'-c','test/fixtures/critical.css',
'-h','test/fixtures/index.html',
'-i','ignore-me',
'-i','/regexp/',
'-b', 'basePath',
'-s', 'selector',
'-m',
'-e'
];
process.stdout.write = function() {};
process.stderr.write = function() {};
require('../cli');
// timeout to wait for get-stdin timeout
setTimeout(function(){
process.stdout.write = this.stdout;
process.stderr.write = this.stderr;
expect(this.mockOpts.css).to.equal(read('test/fixtures/critical.css'));
expect(this.mockOpts.html).to.equal(read('test/fixtures/index.html'));
expect(this.mockOpts.selector).to.equal('selector');
expect(this.mockOpts.ignore).to.be.instanceof(Array);
expect(this.mockOpts.ignore[0]).to.be.a('string');
expect(this.mockOpts.ignore[1]).to.instanceof(RegExp);
expect(this.mockOpts.minify).to.be.ok;
expect(this.mockOpts.extract).to.be.ok;
done();
}.bind(this),200);
});
it('should pass the correct opts when using long opts', function (done) {
process.argv = [
'node',
this.bin,
'--css','test/fixtures/critical.css',
'--html','test/fixtures/index.html',
'--ignore','ignore-me',
'--ignore','/regexp/',
'--base', 'basePath',
'--selector', 'selector',
'--minify',
'--extract'
];
process.stdout.write = function() {};
process.stderr.write = function() {};
require('../cli');
// timeout to wait for get-stdin timeout
setTimeout(function(){
process.stdout.write = this.stdout;
process.stderr.write = this.stderr;
expect(this.mockOpts.css).to.equal(read('test/fixtures/critical.css'));
expect(this.mockOpts.html).to.equal(read('test/fixtures/index.html'));
expect(this.mockOpts.selector).to.equal('selector');
expect(this.mockOpts.ignore).to.be.instanceof(Array);
expect(this.mockOpts.ignore[0]).to.be.a('string');
expect(this.mockOpts.ignore[1]).to.instanceof(RegExp);
expect(this.mockOpts.minify).to.be.ok;
expect(this.mockOpts.extract).to.be.ok;
done();
}.bind(this),200);
});
});
});