dredd
Version:
HTTP API Testing Framework
226 lines (189 loc) • 6.13 kB
JavaScript
const tty = require('tty');
const logger = require('../logger');
const prettifyResponse = require('../prettifyResponse');
const reporterOutputLogger = require('./reporterOutputLogger');
function NyanCatReporter(emitter, stats, tests) {
let windowWidth;
this.type = 'nyan';
this.stats = stats;
this.tests = tests;
this.isatty = tty.isatty(1) && tty.isatty(2);
if (this.isatty) {
if (process.stdout.getWindowSize) {
windowWidth = process.stdout.getWindowSize(1)[0];
} else {
windowWidth = tty.getWindowSize()[1];
}
} else {
windowWidth = 75;
}
this.rainbowColors = this.generateColors();
this.colorIndex = 0;
this.numberOfLines = 4;
this.trajectories = [[], [], [], []];
this.nyanCatWidth = 11;
this.trajectoryWidthMax = (((windowWidth * 0.75) | 0) - this.nyanCatWidth); // eslint-disable-line no-bitwise
this.scoreboardWidth = 5;
this.tick = 0;
this.errors = [];
this.configureEmitter(emitter);
logger.debug(`Using '${this.type}' reporter.`);
}
NyanCatReporter.prototype.configureEmitter = function configureEmitter(emitter) {
emitter.on('start', (rawBlueprint, callback) => {
this.cursorHide();
this.draw();
callback();
});
emitter.on('end', (callback) => {
this.cursorShow();
let i = 0;
while (i < this.numberOfLines) {
this.write('\n');
i++;
}
if (this.errors.length > 0) {
this.write('\n');
reporterOutputLogger.info('Displaying failed tests...');
for (const test of this.errors) {
reporterOutputLogger.fail(`${test.title} duration: ${test.duration}ms`);
reporterOutputLogger.fail(test.message);
reporterOutputLogger.request(`\n${prettifyResponse(test.request)}\n`);
reporterOutputLogger.expected(`\n${prettifyResponse(test.expected)}\n`);
reporterOutputLogger.actual(`\n${prettifyResponse(test.actual)}\n\n`);
}
}
reporterOutputLogger.complete(`${this.stats.passes} passing, ${this.stats.failures} failing, ${this.stats.errors} errors, ${this.stats.skipped} skipped`);
reporterOutputLogger.complete(`Tests took ${this.stats.duration}ms`);
callback();
});
emitter.on('test pass', () => {
this.draw();
});
emitter.on('test skip', () => {
this.draw();
});
emitter.on('test fail', (test) => {
this.errors.push(test);
this.draw();
});
emitter.on('test error', (error, test) => {
test.message = `\nError: \n${error}\nStacktrace: \n${error.stack}\n`;
this.errors.push(test);
this.draw();
});
};
NyanCatReporter.prototype.draw = function draw() {
this.appendRainbow();
this.drawScoreboard();
this.drawRainbow();
this.drawNyanCat();
this.tick = !this.tick;
};
NyanCatReporter.prototype.drawScoreboard = function drawScoreboard() {
const colors = {
fail: 31,
skipped: 36,
pass: 32,
};
// Capture outer `this`
const draw = (color, n) => {
this.write(' ');
this.write(`\u001b[${color}m${n}\u001b[0m`);
this.write('\n');
};
draw(colors.pass, this.stats.passes);
draw(colors.fail, this.stats.failures);
draw(colors.fail, this.stats.errors);
draw(colors.skipped, this.stats.skipped);
this.write('\n');
this.cursorUp(this.numberOfLines + 1);
};
NyanCatReporter.prototype.appendRainbow = function appendRainbow() {
const segment = (this.tick ? '_' : '-');
const rainbowified = this.rainbowify(segment);
const result = [];
let index = 0;
while (index < this.numberOfLines) {
const trajectory = this.trajectories[index];
if (trajectory.length >= this.trajectoryWidthMax) { trajectory.shift(); }
trajectory.push(rainbowified);
result.push(index++);
}
return result;
};
NyanCatReporter.prototype.drawRainbow = function drawRainbow() {
this.trajectories.forEach((line) => {
this.write(`\u001b[${this.scoreboardWidth}C`);
this.write(line.join(''));
this.write('\n');
});
this.cursorUp(this.numberOfLines);
};
NyanCatReporter.prototype.drawNyanCat = function drawNyanCat() {
const startWidth = this.scoreboardWidth + this.trajectories[0].length;
const color = `\u001b[${startWidth}C`;
let padding = '';
this.write(color);
this.write('_,------,');
this.write('\n');
this.write(color);
padding = (this.tick ? ' ' : ' ');
this.write(`_|${padding}/\\_/\\ `);
this.write('\n');
this.write(color);
padding = (this.tick ? '_' : '__');
const tail = (this.tick ? '~' : '^');
this.write(`${tail}|${padding}${this.face()} `);
this.write('\n');
this.write(color);
padding = (this.tick ? ' ' : ' ');
this.write(`${padding}'' '' `);
this.write('\n');
this.cursorUp(this.numberOfLines);
};
NyanCatReporter.prototype.face = function face() {
if (this.stats.failures) {
return '( x .x)';
} if (this.stats.skipped) {
return '( o .o)';
} if (this.stats.passes) {
return '( ^ .^)';
}
return '( - .-)';
};
NyanCatReporter.prototype.cursorUp = function cursorUp(n) {
this.write(`\u001b[${n}A`);
};
NyanCatReporter.prototype.cursorDown = function cursorDown(n) {
this.write(`\u001b[${n}B`);
};
NyanCatReporter.prototype.cursorShow = function cursorShow() {
if (this.isatty) { this.write('\u001b[?25h'); }
};
NyanCatReporter.prototype.cursorHide = function cursorHide() {
if (this.isatty) { this.write('\u001b[?25l'); }
};
NyanCatReporter.prototype.generateColors = function generateColors() {
const colors = [];
let i = 0;
while (i < (6 * 7)) {
const pi3 = Math.floor(Math.PI / 3);
const n = (i * (1.0 / 6));
const r = Math.floor((3 * Math.sin(n)) + 3);
const g = Math.floor((3 * Math.sin(n + (2 * pi3))) + 3);
const b = Math.floor((3 * Math.sin(n + (4 * pi3))) + 3);
colors.push((36 * r) + (6 * g) + b + 16);
i++;
}
return colors;
};
NyanCatReporter.prototype.rainbowify = function rainbowify(str) {
const color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
this.colorIndex += 1;
return `\u001b[38;5;${color}m${str}\u001b[0m`;
};
NyanCatReporter.prototype.write = function write(str) {
process.stdout.write(str);
};
module.exports = NyanCatReporter;