agliojs
Version:
An API Blueprint renderer with theme support
403 lines (389 loc) • 12.2 kB
JavaScript
(function() {
var aglio, assert, bin, blueprint, drafter, fs, http, path, root, sinon,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
aglio = require('../lib/main');
assert = require('assert');
bin = require('../lib/bin');
fs = require('fs');
http = require('http');
path = require('path');
drafter = require('drafter.js');
sinon = require('sinon');
root = path.dirname(__dirname);
blueprint = fs.readFileSync(path.join(root, 'example.apib'), 'utf-8');
describe('API Blueprint Renderer', function() {
it('Should load the default theme', function() {
var theme;
theme = aglio.getTheme('default');
return assert.ok(theme);
});
it('Should get a list of included files', function() {
var input, paths;
sinon.stub(fs, 'readFileSync', function() {
return 'I am a test file';
});
input = '# Title\n<!-- include(test1.apib) -->\nSome content...\n<!-- include(test2.apib) -->\nMore content...';
paths = aglio.collectPathsSync(input, '.');
fs.readFileSync.restore();
assert.equal(paths.length, 2);
assert(indexOf.call(paths, 'test1.apib') >= 0);
return assert(indexOf.call(paths, 'test2.apib') >= 0);
});
it('Should render blank string', function(done) {
return aglio.render('', {
template: 'default',
locals: {
foo: 1
}
}, function(err, html) {
if (err) {
return done(err);
}
assert(html);
return done();
});
});
it('Should render a complex document', function(done) {
return aglio.render(blueprint, 'default', function(err, html) {
if (err) {
return done(err);
}
assert(html);
assert(html.indexOf('This is content that was included'));
return done();
});
});
it('Should render mixed line endings and tabs properly', function(done) {
var temp;
temp = '# GET /message\r\n+ Response 200 (text/plain)\r\r\t\tHello!\n';
return aglio.render(temp, 'default', done);
});
it('Should render a custom template by filename', function(done) {
var template;
template = path.join(root, 'test', 'test.jade');
return aglio.render('# Blueprint', template, function(err, html) {
if (err) {
return done(err);
}
assert(html);
return done();
});
});
it('Should return warnings with filtered input', function(done) {
var filteredTemp, temp;
temp = '# GET /message\r\n+ Response 200 (text/plain)\r\r\t\tHello!\n';
filteredTemp = temp.replace(/\r\n?/g, '\n').replace(/\t/g, ' ');
return aglio.render(temp, 'default', function(err, html, warnings) {
if (err) {
return done(err);
}
assert.equal(filteredTemp, warnings.input);
return done();
});
});
it('Should render from/to files', function(done) {
var dest, src;
src = path.join(root, 'example.apib');
dest = path.join(root, 'example.html');
return aglio.renderFile(src, dest, {}, done);
});
it('Should render from stdin', function(done) {
sinon.stub(process.stdin, 'read', function() {
return '# Hello\n';
});
setTimeout(function() {
return process.stdin.emit('readable', 1);
});
return aglio.renderFile('-', 'example.html', 'default', function(err) {
if (err) {
return done(err);
}
assert(process.stdin.read.called);
process.stdin.read.restore();
process.stdin.removeAllListeners();
return done();
});
});
it('Should render to stdout', function(done) {
sinon.stub(console, 'log');
return aglio.renderFile(path.join(root, 'example.apib'), '-', 'default', function(err) {
if (err) {
console.log.restore();
return done(err);
}
assert(console.log.called);
console.log.restore();
return done();
});
});
it('Should compile from/to files', function(done) {
var dest, src;
src = path.join(root, 'example.apib');
dest = path.join(root, 'example-compiled.apib');
return aglio.compileFile(src, dest, done);
});
it('Should compile from stdin', function(done) {
sinon.stub(process.stdin, 'read', function() {
return '# Hello\n';
});
setTimeout(function() {
return process.stdin.emit('readable', 1);
});
return aglio.compileFile('-', 'example-compiled.apib', function(err) {
if (err) {
return done(err);
}
assert(process.stdin.read.called);
process.stdin.read.restore();
process.stdin.removeAllListeners();
return done();
});
});
it('Should compile to stdout', function(done) {
sinon.stub(console, 'log');
return aglio.compileFile(path.join(root, 'example.apib'), '-', function(err) {
if (err) {
return done(err);
}
assert(console.log.called);
console.log.restore();
return done();
});
});
it('Should support legacy theme names', function(done) {
return aglio.render('', {
template: 'flatly'
}, function(err, html) {
if (err) {
return done(err);
}
assert(html);
return done();
});
});
it('Should error on missing input file', function(done) {
return aglio.renderFile('missing', 'output.html', 'default', function(err, html) {
assert(err);
return aglio.compileFile('missing', 'output.apib', function(err) {
assert(err);
return done();
});
});
});
it('Should error on bad template', function(done) {
return aglio.render(blueprint, 'bad', function(err, html) {
assert(err);
return done();
});
});
it('Should error on drafter failure', function(done) {
sinon.stub(drafter, 'parse', function(content, options, callback) {
return callback('error');
});
return aglio.render(blueprint, 'default', function(err, html) {
assert(err);
drafter.parse.restore();
return done();
});
});
it('Should error on file read failure', function(done) {
sinon.stub(fs, 'readFile', function(filename, options, callback) {
return callback('error');
});
return aglio.renderFile('foo', 'bar', 'default', function(err, html) {
assert(err);
fs.readFile.restore();
return done();
});
});
it('Should error on file write failure', function(done) {
sinon.stub(fs, 'writeFile', function(filename, data, callback) {
return callback('error');
});
return aglio.renderFile('foo', 'bar', 'default', function(err, html) {
assert(err);
fs.writeFile.restore();
return done();
});
});
return it('Should error on non-file failure', function(done) {
sinon.stub(aglio, 'render', function(content, template, callback) {
return callback('error');
});
return aglio.renderFile(path.join(root, 'example.apib'), 'bar', 'default', function(err, html) {
assert(err);
aglio.render.restore();
return done();
});
});
});
describe('Executable', function() {
it('Should print a version', function(done) {
sinon.stub(console, 'log');
return bin.run({
version: true
}, function(err) {
assert(console.log.args[0][0].match(/aglio \d+/));
assert(console.log.args[1][0].match(/olio \d+/));
console.log.restore();
return done(err);
});
});
it('Should render a file', function(done) {
sinon.stub(console, 'error');
sinon.stub(aglio, 'renderFile', function(i, o, t, callback) {
var warnings;
warnings = [
{
code: 1,
message: 'Test message',
location: [
{
index: 0,
length: 1
}
]
}
];
warnings.input = 'test';
return callback(null, warnings);
});
bin.run({}, function(err) {
return assert(err);
});
return bin.run({
i: path.join(root, 'example.apib'),
o: '-'
}, function() {
console.error.restore();
aglio.renderFile.restore();
return done();
});
});
it('Should compile a file', function(done) {
sinon.stub(aglio, 'compileFile', function(i, o, callback) {
return callback(null);
});
return bin.run({
c: 1,
i: path.join(root, 'example.apib'),
o: '-'
}, function() {
aglio.compileFile.restore();
return done();
});
});
it('Should start a live preview server', function(done) {
this.timeout(5000);
sinon.stub(aglio, 'render', function(i, t, callback) {
return callback(null, 'foo');
});
sinon.stub(http, 'createServer', function(handler) {
return {
listen: function(port, host, cb) {
var req, res;
console.log('calling listen');
req = {
url: '/favicon.ico'
};
res = {
end: function(data) {
return assert(!data);
}
};
handler(req, res);
req = {
url: '/'
};
res = {
writeHead: function(status, headers) {
return false;
},
end: function(data) {
var file;
aglio.render.restore();
cb();
file = fs.readFileSync('example.apib', 'utf8');
return setTimeout(function() {
fs.writeFileSync('example.apib', file, 'utf8');
return setTimeout(function() {
console.log.restore();
return done();
}, 500);
}, 500);
}
};
return handler(req, res);
}
};
});
sinon.stub(console, 'log');
sinon.stub(console, 'error');
return bin.run({
s: true
}, function(err) {
console.error.restore();
assert(err);
return bin.run({
i: path.join(root, 'example.apib'),
s: true,
p: 3000,
h: 'localhost'
}, function(err) {
assert.equal(err, null);
return http.createServer.restore();
});
});
});
it('Should support custom Jade template shortcut', function(done) {
sinon.stub(console, 'log');
return bin.run({
i: path.join(root, 'example.apib'),
t: 'test.jade',
o: '-'
}, function(err) {
console.log.restore();
return done(err);
});
});
it('Should handle theme load errors', function(done) {
sinon.stub(console, 'error');
sinon.stub(aglio, 'getTheme', function() {
throw new Error('Could not load theme');
});
return bin.run({
template: 'invalid'
}, function(err) {
console.error.restore();
aglio.getTheme.restore();
assert(err);
return done();
});
});
return it('Should handle rendering errors', function(done) {
sinon.stub(aglio, 'renderFile', function(i, o, t, callback) {
return callback({
code: 1,
message: 'foo',
input: 'foo bar baz',
location: [
{
index: 1,
length: 1
}
]
});
});
sinon.stub(console, 'error');
return bin.run({
i: path.join(root, 'example.apib'),
o: '-'
}, function() {
assert(console.error.called);
console.error.restore();
aglio.renderFile.restore();
return done();
});
});
});
}).call(this);