- // Copyright 2014, Yahoo! Inc.
- // Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.
-
- var Base = require('preceptor-core').Base;
- var utils = require('preceptor-core').utils;
- var _ = require('underscore');
-
- /**
- * This class manages the messages received and is used as data-source for the reporter instances.
- *
- * @class ReportContainer
- * @extends Base
- *
- * @property {object[]} _sequence Sequence of items in the report
- * @property {object} _actions Actions for each item keyed by the id - used for direct access into the tree
- * @property {object} _tree Root object of reporting tree - uses references from _actions to form tree
- */
- var ReportContainer = Base.extend(
-
- {
- /**
- * Called when reporting starts
- *
- * @method start
- */
- start: function () {
- this._sequence = [];
- this._actions = {};
- this._tree = {
- startTime: +(new Date()),
- pending: true,
- type: 'root',
- name: 'Root',
- level: 0,
- data: {},
- messages: [],
- children: [],
- output: {}
- };
- },
-
- /**
- * Called when reporting stops
- *
- * @method stop
- */
- stop: function () {
-
- this._tree.endTime = +(new Date());
- this._tree.duration = this._tree.endTime - this._tree.startTime;
- this._tree.pending = false;
-
- _.each(_.keys(this._actions), function (id) {
-
- var action = this._actions[id];
-
- if (action.pending) {
- throw new Error("Reporter action '" + action.type + "' for '" + action.name + "' is pending when end was reached.");
- }
- }, this);
- },
-
- /**
- * Reporting is completed
- *
- * @method complete
- */
- complete: function () {
- // Nothing here
- },
-
- /**
- * Called when suite starts
- *
- * @method suiteStart
- * @param {string} id
- * @param {string} parentId
- * @param {string} suiteName
- * @param {object} [options]
- * @param {int} [options.startTime]
- */
- suiteStart: function (id, parentId, suiteName, options) {
- var parent;
-
- options = options || {};
-
- this._actions[id] = {
- id: id,
- startTime: options.startTime || +(new Date()),
- pending: true,
- type: 'suite',
- name: suiteName,
- data: {},
- messages: [],
- parentId: parentId,
- children: [],
- output: {}
- };
-
- parent = this.getAction(parentId);
- this._actions[id].level = parent.level + 1;
-
- this._sequence.push(this._actions[id]);
- parent.children.push(this._actions[id]);
- },
-
- /**
- * Called when suite ends
- *
- * @method suiteEnd
- * @param {string} id
- * @param {object} [options]
- * @param {int} [options.endTime]
- */
- suiteEnd: function (id, options) {
- var action = this.getAction(id);
-
- options = options || {};
-
- if (action.type !== 'suite') {
- throw new Error("Type of reporter action was expected to be 'suite' but was '" + action.type + "'.")
- }
- if (!action.pending) {
- throw new Error("Reporter action for suite was already closed.");
- }
-
- action.endTime = options.startTime || +(new Date());
- action.duration = action.endTime - action.startTime;
- action.pending = false;
- },
-
-
- /**
- * Called when any item has custom data
- *
- * @method itemData
- * @param {string} id
- * @param {string} json JSON-data
- */
- itemData: function (id, json) {
- var action = this.getAction(id);
-
- action.data = utils.deepExtend(action.data, [JSON.parse(json)]);
- },
-
- /**
- * Called when any item has a custom message
- *
- * @method itemMessage
- * @param {string} id
- * @param {string} message
- */
- itemMessage: function (id, message) {
- this.getAction(id).messages.push(message);
- },
-
-
- /**
- * Called when test starts
- *
- * @method testStart
- * @param {string} id
- * @param {string} parentId
- * @param {string} testName
- * @param {object} [options]
- * @param {int} [options.startTime]
- */
- testStart: function (id, parentId, testName, options) {
- var parent;
-
- options = options || {};
-
- this._actions[id] = {
- id: id,
- startTime: options.startTime || +(new Date()),
- pending: true,
- type: 'test',
- name: testName,
- data: {},
- messages: [],
- parentId: parentId,
- output: {}
- };
-
- parent = this.getAction(parentId);
- this._actions[id].level = parent.level + 1;
-
- this._sequence.push(this._actions[id]);
- parent.children.push(this._actions[id]);
- },
-
-
- /**
- * Called when test fails
- *
- * @method testFailed
- * @param {string} id
- * @param {string} [message]
- * @param {string} [reason]
- * @param {object} [options]
- * @param {int} [options.endTime]
- */
- testFailed: function (id, message, reason, options) {
- var action = this._completeTestAction(id, options);
-
- action.outcome = 'failed';
- action.message = message || 'FAILED';
- action.reason = reason || action.message;
- },
-
- /**
- * Called when test has an error
- *
- * @method testError
- * @param {string} id
- * @param {string} [message]
- * @param {string} [reason]
- * @param {object} [options]
- */
- testError: function (id, message, reason, options) {
- var action = this._completeTestAction(id, options);
-
- action.outcome = 'error';
- action.message = message || 'ERROR';
- action.reason = reason || action.message;
- },
-
- /**
- * Called when test has passed
- *
- * @method testPassed
- * @param {string} id
- * @param {object} [options]
- */
- testPassed: function (id, options) {
- var action = this._completeTestAction(id, options);
-
- action.outcome = 'passed';
- },
-
- /**
- * Called when test is undefined
- *
- * @method testUndefined
- * @param {string} id
- * @param {object} [options]
- */
- testUndefined: function (id, options) {
- var action = this._completeTestAction(id, options);
-
- action.outcome = 'undefined';
- },
-
- /**
- * Called when test is skipped
- *
- * @method testSkipped
- * @param {string} id
- * @param {string} [reason]
- * @param {object} [options]
- */
- testSkipped: function (id, reason, options) {
- var action = this._completeTestAction(id, options);
-
- action.outcome = 'skipped';
- action.reason = reason || 'SKIPPED';
- },
-
- /**
- * Called when test is incomplete
- *
- * @method testIncomplete
- * @param {string} id
- * @param {object} [options]
- */
- testIncomplete: function (id, options) {
- var action = this._completeTestAction(id, options);
-
- action.outcome = 'incomplete';
- },
-
-
- /**
- * Completes a test
- *
- * @method _completeTestAction
- * @param {string} id
- * @param {object} [options]
- * @param {int} [options.endTime]
- * @return {object} Action
- * @private
- */
- _completeTestAction: function (id, options) {
- var action = this.getAction(id);
-
- options = options || {};
-
- if (action.type !== 'test') {
- throw new Error("Type of reporter action was expected to be 'test' but was '" + action.type + "'.")
- }
- if (!action.pending) {
- throw new Error("Reporter action for test was already closed.");
- }
-
- action.endTime = options.endTime || +(new Date());
- action.duration = action.endTime - action.startTime;
- action.pending = false;
-
- return action;
- },
-
-
- /**
- * Gets action by id
- *
- * @method getAction
- * @param {string} id
- * @return {object}
- */
- getAction: function (id) {
- var action;
-
- if (id === "undefined") {
- id = undefined;
- }
- if (id === "null") {
- id = null;
- }
-
- if ((id === undefined) || (id === null)) {
- action = this.getTree();
- } else {
- action = this._actions[id];
-
- if (!action) {
- throw new Error("Id for reporter action doesn't exist " + id + ".");
- }
- }
-
- return action;
- },
-
- /**
- * Gets the sequence of actions by the sequential list of ids
- *
- * @method getSequence
- * @return {string[]}
- */
- getSequence: function () {
- return this._sequence;
- },
-
- /**
- * Gets the action tree
- *
- * @method getTree
- * @return {object}
- */
- getTree: function () {
- return this._tree;
- },
-
-
- /**
- * Gathers all test outcomes for a node
- *
- * @method gatherTestOutcomes
- * @param {object} treeNode
- * @return {object} Of `{tests: int, failed: int, disabled: int, error: int}`
- */
- gatherTestOutcomes: function (treeNode) {
- var result = {
- tests: 0,
- failed: 0,
- incomplete: 0,
- skipped: 0,
- error: 0,
- passed: 0,
- undef: 0
- };
-
- this._countOutcomes(treeNode, result);
-
- return result;
- },
-
- /**
- * Counts a specific outcome downwards from the current tree-point
- *
- * @method _countOutcomes
- * @param {object} treeNode
- * @param {object} sumObj
- * @private
- */
- _countOutcomes: function (treeNode, sumObj) {
- if (treeNode.type === 'test') {
- sumObj.tests++;
-
- if (treeNode.outcome === 'undefined') {
- sumObj['undef']++;
- } else {
- sumObj[treeNode.outcome]++;
- }
- } else {
- _.each(treeNode.children || [], function (node) {
- this._countOutcomes(node, sumObj);
- }, this);
- }
- },
-
- /**
- * Gets the full name of an object
- *
- * @method getFullName
- * @param {string} id
- * @return {string}
- */
- getFullName: function (id) {
- var action = this.getAction(id),
- parentId = action.parentId,
- name = action.name;
-
- if (parentId !== undefined) {
- return [this.getFullName(parentId), name].join(" ");
- } else {
- return name;
- }
- }
- },
-
- {
- /**
- * @property TYPE
- * @type {string}
- * @static
- */
- TYPE: 'ReportContainer'
- });
-
- module.exports = ReportContainer;
-
-