gulp-html-src
Version:
Gulp plugin to accept HTML input, and output the linked JavaScript (script tags) and CSS (link tags)
502 lines (418 loc) • 16.8 kB
JavaScript
var path = require('path'),
PassThrough = require('stream').PassThrough,
FakeFile = require('gulp-util').File,
extend = require('extend'),
q = require('q'),
mocha = require('mocha'),
expect = require('chai').expect,
ghtmlsrc = require('../');
describe('gulp-html-src', function() {
var createFakeReadStream = function(path) {
var stream = new PassThrough();
setTimeout(function() {
stream.write('FAKEFILE:');
stream.write(path);
stream.end();
}, 0);
return stream;
};
/**
* Creates fake read stream function with fake delays that will simulate different loading times.
* @param {Array} delays Array of delays in milliseconds.
* @returns {Function}
*/
var createFakeReadStreamWithDelay = function (delays) {
var i = 0;
return function(path) {
var stream = new PassThrough();
setTimeout(function() {
stream.write('FAKEFILE:');
stream.write(path);
stream.end();
}, delays[i++]);
return stream;
};
};
it('should be a function', function() {
expect(ghtmlsrc).to.be.a('function');
});
it('should emit no files for empty file', function(done) {
var dataReceived = false;
var stream = ghtmlsrc();
stream.on('data', function(data) {
dataReceived = true;
});
stream.on('end', function() {
expect(dataReceived).to.equal(false);
done();
});
stream.write(new FakeFile({
path: '/test/html/test.html',
contents: new Buffer('<html></html>')
}));
stream.read();
stream.end();
});
describe('for Buffer files', function() {
var runForInput = function(html, options, asserts) {
var dataReceived = [];
// Skip options if not provided
if (typeof options === 'function') {
asserts = options;
options = {};
}
options = extend({}, { createReadStream : createFakeReadStream }, options);
var stream = ghtmlsrc(options);
stream.on('data', function(data) {
dataReceived.push(data);
});
stream.on('error', function(err) {
console.log('error received ', err);
})
stream.on('end', function() {
asserts(dataReceived);
});
stream.write(new FakeFile({
cwd: '/',
base: '/test/',
path: '/test/html/test.html',
contents: new Buffer(html)
}));
stream.read();
stream.end();
}
it('should emit a single entry for one script', function(done) {
runForInput('<html><body>' +
'<script src="js/test1.js"></script>' +
'</body>' +
'</html>',
function(dataReceived) {
expect(dataReceived.length).to.equal(1);
expect(dataReceived[0].path).to.equal(path.normalize('/test/html/js/test1.js'));
expect(dataReceived[0].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test1.js'));
done();
}
);
});
it('should emit an entry for each script', function(done) {
runForInput(
'<html><body>' +
'<script src="js/test1.js"></script>' +
'<script src="js/test2.js"></script>' +
'<script src="js/test3.js"></script>' +
'</body>' +
'</html>',
function(dataReceived) {
expect(dataReceived.length).to.equal(3);
expect(dataReceived[0].path).to.equal(path.normalize('/test/html/js/test1.js'));
expect(dataReceived[0].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test1.js'));
expect(dataReceived[1].path).to.equal(path.normalize('/test/html/js/test2.js'));
expect(dataReceived[1].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test2.js'));
expect(dataReceived[2].path).to.equal(path.normalize('/test/html/js/test3.js'));
expect(dataReceived[2].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test3.js'));
done();
});
});
it('should ignore data-ignore=true scripts', function(done) {
runForInput(
'<html><body>' +
'<script src="js/test1.js"></script>' +
'<script src="js/test2.js" data-ignore="true"></script>' +
'<script src="js/test3.js"></script>' +
'</body>' +
'</html>',
function(dataReceived) {
expect(dataReceived.length).to.equal(2);
expect(dataReceived[0].path).to.equal(path.normalize('/test/html/js/test1.js'));
expect(dataReceived[0].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test1.js'));
expect(dataReceived[1].path).to.equal(path.normalize('/test/html/js/test3.js'));
expect(dataReceived[1].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test3.js'));
done();
});
});
it('should ignore data-remove=true scripts', function(done) {
runForInput(
'<html><body>' +
'<script src="js/test1.js"></script>' +
'<script src="js/test2.js" data-remove="true"></script>' +
'<script src="js/test3.js"></script>' +
'</body>' +
'</html>',
function(dataReceived) {
expect(dataReceived.length).to.equal(2);
expect(dataReceived[0].path).to.equal(path.normalize('/test/html/js/test1.js'));
expect(dataReceived[0].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test1.js'));
expect(dataReceived[1].path).to.equal(path.normalize('/test/html/js/test3.js'));
expect(dataReceived[1].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test3.js'));
done();
});
});
it('should include the html file in transformed stream when the option is set', function(done) {
runForInput(
'<html><body>' +
'<script src="js/test1.js"></script>' +
'<script src="js/test2.js" data-remove="true"></script>' +
'<script src="js/test3.js"></script>' +
'</body>' +
'</html>',
{ includeHtmlInOutput : true },
function(dataReceived) {
expect(dataReceived.length).to.equal(3);
expect(dataReceived[0].path).to.equal(path.normalize('/test/html/js/test1.js'));
expect(dataReceived[0].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test1.js'));
expect(dataReceived[1].path).to.equal(path.normalize('/test/html/js/test3.js'));
expect(dataReceived[1].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test3.js'));
expect(dataReceived[2].path).to.equal('/test/html/test.html');
done();
}
);
});
it('should emit a single css for css presets', function(done) {
runForInput(
'<html>' +
'<head>' +
'<link rel="stylesheet" type="text/css" href="css/test1.css">' +
'</head><body>' +
'<script src="js/test1.js"></script>' +
'<script src="js/test2.js" data-remove="true"></script>' +
'<script src="js/test3.js"></script>' +
'</body>' +
'</html>',
{ presets : 'css' },
function(dataReceived) {
expect(dataReceived.length).to.equal(1);
expect(dataReceived[0].path).to.equal(path.normalize('/test/html/css/test1.css'));
expect(dataReceived[0].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/css/test1.css'));
done();
}
);
});
it('should emit a multiple css for css presets', function(done) {
runForInput(
'<html>' +
'<head>' +
'<link rel="stylesheet" type="text/css" href="css/test1.css">' +
'<link rel="stylesheet" type="text/css" href="css/test2.css">' +
'</head><body>' +
'<script src="js/test1.js"></script>' +
'<script src="js/test2.js" data-remove="true"></script>' +
'<script src="js/test3.js"></script>' +
'</body>' +
'</html>',
{ presets : 'css' },
function(dataReceived) {
expect(dataReceived.length).to.equal(2);
expect(dataReceived[0].path).to.equal(path.normalize('/test/html/css/test1.css'));
expect(dataReceived[0].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/css/test1.css'));
expect(dataReceived[1].path).to.equal(path.normalize('/test/html/css/test2.css'));
expect(dataReceived[1].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/css/test2.css'));
done();
}
);
});
it('should skip data-remove links for css presets', function(done) {
runForInput(
'<html>' +
'<head>' +
'<link rel="stylesheet" type="text/css" href="css/test1.css">' +
'<link rel="stylesheet" type="text/css" data-remove="true" href="css/testremove.css">' +
'<link rel="stylesheet" type="text/css" href="css/test2.css">' +
'</head><body>' +
'<script src="js/test1.js"></script>' +
'<script src="js/test2.js" data-remove="true"></script>' +
'<script src="js/test3.js"></script>' +
'</body>' +
'</html>',
{ presets : 'css' },
function(dataReceived) {
expect(dataReceived.length).to.equal(2);
expect(dataReceived[0].path).to.equal(path.normalize('/test/html/css/test1.css'));
expect(dataReceived[0].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/css/test1.css'));
expect(dataReceived[1].path).to.equal(path.normalize('/test/html/css/test2.css'));
expect(dataReceived[1].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/css/test2.css'));
done();
}
);
});
it('should skip data-ignore links for css presets', function(done) {
runForInput(
'<html>' +
'<head>' +
'<link rel="stylesheet" type="text/css" href="css/test1.css">' +
'<link rel="stylesheet" type="text/css" data-ignore="true" href="css/testremove.css">' +
'<link rel="stylesheet" type="text/css" href="css/test2.css">' +
'</head><body>' +
'<script src="js/test1.js"></script>' +
'<script src="js/test2.js" data-remove="true"></script>' +
'<script src="js/test3.js"></script>' +
'</body>' +
'</html>',
{ presets : 'css' },
function(dataReceived) {
expect(dataReceived.length).to.equal(2);
expect(dataReceived[0].path).to.equal(path.normalize('/test/html/css/test1.css'));
expect(dataReceived[0].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/css/test1.css'));
expect(dataReceived[1].path).to.equal(path.normalize('/test/html/css/test2.css'));
expect(dataReceived[1].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/css/test2.css'));
done();
}
);
});
it('should emit an error event on error opening stream', function(done) {
var dataReceived = [];
var errorsReceived = [];
var stream = ghtmlsrc({ createReadStream : function(path) {
throw new Error('path not found')
} } );
stream.on('data', function(data) {
dataReceived.push(data);
});
stream.on('error', function(err) {
errorsReceived.push(err);
})
stream.on('end', function() {
expect(errorsReceived.length).to.equal(1);
expect(errorsReceived[0]).to.be.an.instanceOf(Error);
expect(errorsReceived[0].message).to.equal('path not found');
done();
});
stream.write(new FakeFile({
cwd: '/',
base: '/test/',
path: '/test/html/test.html',
contents: new Buffer('<html><body><script src="js/notfound.js"></script></body></html>')
}));
stream.read();
stream.end();
});
it('should skip absolute http:// scripts', function(done) {
runForInput(
'<html>' +
'<body>' +
'<script src="js/test1.js"></script>' +
'<script src="js/test2.js"></script>' +
'<script src="http://cdn.jquery.com/jquery.min.js"></script>' +
'</body>' +
'</html>',
{ presets : 'js' },
function(dataReceived) {
expect(dataReceived.length).to.equal(2);
expect(dataReceived[0].path).to.equal(path.normalize('/test/html/js/test1.js'));
expect(dataReceived[1].path).to.equal(path.normalize('/test/html/js/test2.js'));
done();
});
});
it('should return files in same order as they appear in HTML file', function(done) {
runForInput(
'<html><body>' +
'<script src="js/test1.js"></script>' +
'<script src="js/test2.js"></script>' +
'<script src="js/test3.js"></script>' +
'</body>' +
'</html>',
{createReadStream: createFakeReadStreamWithDelay([500, 100, 0])},
function(dataReceived) {
expect(dataReceived.length).to.equal(3);
expect(dataReceived[0].path).to.equal(path.normalize('/test/html/js/test1.js'));
expect(dataReceived[0].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test1.js'));
expect(dataReceived[1].path).to.equal(path.normalize('/test/html/js/test2.js'));
expect(dataReceived[1].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test2.js'));
expect(dataReceived[2].path).to.equal(path.normalize('/test/html/js/test3.js'));
expect(dataReceived[2].contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test3.js'));
done();
});
});
});
describe('for streams', function() {
var createHtmlStream = function(contents) {
var stream = new PassThrough();
setTimeout(function() {
stream.write(contents);
stream.end();
}, 0);
return stream;
};
var runForInput = function(html, options, asserts) {
var dataReceived = [];
var errorsReceived = [];
// Skip options if not provided
if (typeof options === 'function') {
asserts = options;
options = {};
}
options = extend({}, { createReadStream : createFakeReadStream }, options);
var stream = ghtmlsrc(options);
stream.on('data', function(data) {
dataReceived.push(data);
});
stream.on('error', function(err) {
errorsReceived.push(err);
});
stream.on('end', function() {
asserts(errorsReceived, dataReceived);
});
stream.write(new FakeFile({
cwd: '/',
base: '/test/',
path: '/test/html/test.html',
contents: createHtmlStream(html)
}));
stream.read();
stream.end();
};
var readStream = function(stream) {
var deferred = q.defer();
var contents = [];
stream.on('readable', function() {
contents.push(stream.read());
});
stream.on('error', function(err) {
deferred.reject(err);
});
stream.on('end', function() {
deferred.resolve(Buffer.concat(contents));
});
return deferred.promise;
}
it('emits no files for empty html', function(done) {
runForInput('<html></html>', function(errorsReceived, dataReceived) {
expect(errorsReceived.length).to.equal(0);
expect(dataReceived.length).to.equal(0);
done();
});
});
it('emits single script stream from html', function(done) {
runForInput('<html><body><script src="js/test1.js"></script></html>', function(errorsReceived, dataReceived) {
expect(errorsReceived.length).to.equal(0);
expect(dataReceived.length).to.equal(1);
expect(dataReceived[0].contents).to.be.an.instanceOf(PassThrough);
readStream(dataReceived[0].contents)
.then(function(contents) {
expect(contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test1.js'));
})
.then(done, done);
});
});
it('emits multiple script streams from html', function(done) {
runForInput('<html><body>' +
'<script src="js/test1.js"></script>' +
'<script src="js/test2.js"></script>' +
'</body></html>', function(errorsReceived, dataReceived) {
expect(errorsReceived.length).to.equal(0);
expect(dataReceived.length).to.equal(2);
expect(dataReceived[0].contents).to.be.an.instanceOf(PassThrough);
readStream(dataReceived[0].contents)
.then(function(contents) {
expect(contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test1.js'));
})
.then(function() {
return readStream(dataReceived[1].contents);
})
.then(function(contents) {
expect(contents.toString()).to.equal('FAKEFILE:' + path.normalize('/test/html/js/test2.js'))
})
.then(done, done);
});
});
});
});