Plato on Github
Report Home
index.js
Maintainability
68.43
Lines of code
308
Difficulty
41.85
Estimated Errors
2.03
Function weight
By Complexity
By SLOC
/*! * * Copyright (c) 2013 Sebastian Golasch * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ 'use strict'; // ext. libs var Handlebars = require('handlebars'); var stylus = require('stylus'); var fs = require('fs'); // int. globals var reporter = null; /** * The HTML reporter can produce a set of HTML files with the results of your testrun. * * The reporter can be installed with the following command: * * ```bash * $ npm install dalek-reporter-html --save-dev * ``` * * By default the files will be written to the `report/dalek/` folder, * you can change this by adding a config option to the your Dalekfile * * ```javascript * "html-reporter": { * "dest": "your/folder" * } * ``` * * If you would like to use the reporter (in addition to the std. console reporter), * you can start dalek with a special command line argument * * ```bash * $ dalek your_test.js -r console,html * ``` * * or you can add it to your Dalekfile * * ```javascript * "reporter": ["console", "html"] * ``` * * @class Reporter * @constructor * @part html * @api */ function Reporter (opts) { this.events = opts.events; this.config = opts.config; this.temporaryAssertions = []; this.temp = {}; var defaultReportFolder = 'report/dalek'; this.dest = this.config.get('html-reporter') && this.config.get('html-reporter').dest ? this.config.get('html-reporter').dest : defaultReportFolder; this.loadTemplates(); this.initOutputHandlers(); this.startListening(); } /** * @module Reporter */ module.exports = function (opts) { if (reporter === null) { reporter = new Reporter(opts); } return reporter; }; Reporter.prototype = { /** * Inits the html buffer objects * * @method initOutputHandlers * @chainable */ initOutputHandlers: function () { this.output = {}; this.output.test = {}; return this; }, /** * Loads and prepares all the templates for * CSS, JS & HTML * * @method loadTemplates * @chainable */ loadTemplates: function () { // render stylesheets var precss = fs.readFileSync(__dirname + '/themes/default/styl/default.styl', 'utf8'); stylus.render(precss, { filename: 'default.css' }, function(err, css){ if (err) { throw err; } this.styles = css; }.bind(this)); // collect client js (to be inined later) this.js = fs.readFileSync(__dirname + '/themes/default/js/default.js', 'utf8'); // register handlebars helpers Handlebars.registerHelper('roundNumber', function (number) { return Math.round(number * Math.pow(10, 2)) / Math.pow(10, 2); }); // collect & compile templates this.templates = {}; this.templates.test = Handlebars.compile(fs.readFileSync(__dirname + '/themes/default/hbs/test.hbs', 'utf8')); this.templates.wrapper = Handlebars.compile(fs.readFileSync(__dirname + '/themes/default/hbs/wrapper.hbs', 'utf8')); this.templates.testresult = Handlebars.compile(fs.readFileSync(__dirname + '/themes/default/hbs/tests.hbs', 'utf8')); this.templates.banner = Handlebars.compile(fs.readFileSync(__dirname + '/themes/default/hbs/banner.hbs', 'utf8')); this.templates.detail = Handlebars.compile(fs.readFileSync(__dirname + '/themes/default/hbs/detail.hbs', 'utf8')); return this; }, /** * Connects to all the event listeners * * @method startListening * @chainable */ startListening: function () { // index page this.events.on('report:assertion', this.outputAssertionResult.bind(this)); this.events.on('report:test:finished', this.outputTestFinished.bind(this)); this.events.on('report:runner:finished', this.outputRunnerFinished.bind(this)); this.events.on('report:run:browser', this.outputRunBrowser.bind(this)); // detail page this.events.on('report:test:started', this.startDetailPage.bind(this)); this.events.on('report:action', this.addActionToDetailPage.bind(this)); this.events.on('report:assertion', this.addAssertionToDetailPage.bind(this)); this.events.on('report:test:finished', this.finishDetailPage.bind(this)); return this; }, /** * Prepares the output for a test detail page * * @method startDetailPage * @chainable */ startDetailPage: function () { this.detailContents = {}; this.detailContents.eventLog = []; return this; }, /** * Adds an action output to the detail page * * @method addActionToDetailPage * @param {object} data Event data * @chainable */ addActionToDetailPage: function (data) { data.isAction = true; this.detailContents.eventLog.push(data); return this; }, /** * Adds an assertion result to the detail page * * @method addAssertionToDetailPage * @param {object} data Event data * @chainable */ addAssertionToDetailPage: function (data) { data.isAssertion = true; this.detailContents.eventLog.push(data); return this; }, /** * Writes a detail page to the file system * * @method finishDetailPage * @param {object} data Event data * @chainable */ finishDetailPage: function (data) { this.detailContents.testResult = data; this.detailContents.styles = this.styles; this.detailContents.js = this.js; fs.writeFileSync(this.dest + '/details/' + data.id + '.html', this.templates.detail(this.detailContents), 'utf8'); return this; }, /** * Stores the current browser name * * @method outputRunBrowser * @param {string} browser Browser name * @chainable */ outputRunBrowser: function (browser) { this.temp.browser = browser; return this; }, /** * Writes the index page to the filesystem * * @method outputRunnerFinished * @param {object} data Event data * @chainable */ outputRunnerFinished: function (data) { var body = ''; var contents = ''; var tests = ''; var banner = ''; // add test results var keys = Object.keys(this.output.test); keys.forEach(function (key) { tests += this.output.test[key]; }.bind(this)); // compile the test result template body = this.templates.testresult({result: data, tests: tests}); // compile the banner banner = this.templates.banner({status: data.status}); // compile the contents within the wrapper template contents = this.templates.wrapper({styles: this.styles, js: this.js, banner: banner, body: body}); // save the main test output file this.events.emit('report:written', {type: 'html', dest: this.dest}); this._recursiveMakeDirSync(this.dest + '/details'); fs.writeFileSync(this.dest + '/index.html', contents, 'utf8'); return this; }, /** * Pushes an assertion result to the index output queue * * @method outputAssertionResult * @param {object} data Event data * @chainable */ outputAssertionResult: function (data) { this.temporaryAssertions.push(data); return this; }, /** * Pushes an test result to the index output queue * * @method outputTestFinished * @param {object} data Event data * @chainable */ outputTestFinished: function (data) { data.assertionInfo = this.temporaryAssertions; data.browser = this.temp.browser; this.output.test[data.id] = this.templates.test(data); this.temporaryAssertions = []; return this; }, /** * Helper method to generate deeper nested directory structures * * @method _recursiveMakeDirSync * @param {string} path PAth to create */ _recursiveMakeDirSync: function (path) { var pathSep = require('path').sep; var dirs = path.split(pathSep); var root = ''; while (dirs.length > 0) { var dir = dirs.shift(); if (dir === '') { root = pathSep; } if (!fs.existsSync(root + dir)) { fs.mkdirSync(root + dir); } root += dir + pathSep; } } };