From 03d06bf048b92a4e0f7ec4940938ffec23fedba3 Mon Sep 17 00:00:00 2001 From: egavr Date: Thu, 20 Oct 2016 15:26:27 +0300 Subject: [PATCH] refactor: use the same 'test-counter' in reporters and in 'stats' --- lib/gemini.js | 3 +- lib/reporters/flat-factory/flat.js | 2 +- lib/reporters/html/view-model.js | 2 +- lib/reporters/utils/test-counter.js | 89 ----------- lib/stats.js | 46 +++--- lib/test-counter.js | 88 +++++++++++ test/unit/stats.js | 144 ++++++++++-------- .../{reporters/utils => }/test-counter.js | 61 +++----- 8 files changed, 209 insertions(+), 226 deletions(-) delete mode 100644 lib/reporters/utils/test-counter.js create mode 100644 lib/test-counter.js rename test/unit/{reporters/utils => }/test-counter.js (57%) diff --git a/lib/gemini.js b/lib/gemini.js index 4933791d8..526d6893c 100644 --- a/lib/gemini.js +++ b/lib/gemini.js @@ -88,7 +88,8 @@ module.exports = class Gemini extends PassthroughEmitter { const stats = new RunnerStats(runner); - return runner.run(suiteCollection).thenReturn(stats.get()); + return runner.run(suiteCollection) + .then(() => stats.get()); }); } diff --git a/lib/reporters/flat-factory/flat.js b/lib/reporters/flat-factory/flat.js index 0e2688658..0f19e3573 100644 --- a/lib/reporters/flat-factory/flat.js +++ b/lib/reporters/flat-factory/flat.js @@ -4,7 +4,7 @@ const _ = require('lodash'); const chalk = require('chalk'); const logger = require('../../utils').logger; -const TestCounter = require('../utils/test-counter'); +const TestCounter = require('../../test-counter'); const Events = require('../../constants/events'); diff --git a/lib/reporters/html/view-model.js b/lib/reporters/html/view-model.js index 6956160fe..38a5a9a11 100644 --- a/lib/reporters/html/view-model.js +++ b/lib/reporters/html/view-model.js @@ -2,7 +2,7 @@ const _ = require('lodash'); const lib = require('./lib'); -const TestCounter = require('../utils/test-counter'); +const TestCounter = require('../../test-counter'); const NO_STATE = 'NO_STATE'; diff --git a/lib/reporters/utils/test-counter.js b/lib/reporters/utils/test-counter.js deleted file mode 100644 index 4cad2116b..000000000 --- a/lib/reporters/utils/test-counter.js +++ /dev/null @@ -1,89 +0,0 @@ -'use strict'; - -var _ = require('lodash'), - inherit = require('inherit'); - -var STATS = { - UPDATED: 'updated', - PASSED: 'passed', - FAILED: 'failed', - SKIPPED: 'skipped' -}; - -module.exports = inherit({ - __constructor: function() { - this._stats = {}; - }, - - onUpdated: function(updated) { - this._addStat(STATS.UPDATED, updated); - }, - - onPassed: function(passed) { - this._addStat(STATS.PASSED, passed); - }, - - onFailed: function(failed) { - this._addStat(STATS.FAILED, failed); - }, - - onSkipped: function(skipped) { - this._addStat(STATS.SKIPPED, skipped); - }, - - onRetry: function(retried) { - var suiteStats = this._getSuiteStats(retried); - - suiteStats.retries++; - suiteStats.states = {}; - }, - - getResult: function() { - var result = { - total: 0, - updated: 0, - passed: 0, - failed: 0, - skipped: 0, - retries: 0 - }; - - _.forEach(this._stats, function(suiteStats) { - result.retries += suiteStats.retries; - _.forEach(suiteStats.states, function(stateStatus) { - result.total++; - result[stateStatus]++; - }); - }); - - return result; - }, - - _addStat: function(stat, completed) { - var completedEntity = completed.state || completed.suite; - if (!completedEntity) { - return; - } - - var suiteStats = this._getSuiteStats(completed); - - suiteStats.states[completedEntity.name] = stat; - }, - - _getSuiteStats: function(completed) { - var key = this._buildSuiteKey(completed); - - if (!this._stats[key]) { - this._stats[key] = { - retries: 0, - states: {} - }; - } - - return this._stats[key]; - }, - - _buildSuiteKey: function(completed) { - return completed.suite.fullName + completed.browserId; - } -}); diff --git a/lib/stats.js b/lib/stats.js index e18e7b0a6..412a2b193 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -1,40 +1,28 @@ 'use strict'; -const _ = require('lodash'); +const RunnerEvents = require('./constants/events'); +const TestCounter = require('./test-counter'); -const Events = require('./constants/events'); +module.exports = class Stats { + constructor(runner) { + this._counter = new TestCounter(); -/** - * @constructor - * @param {Runner} [runner] - */ -module.exports = function(runner) { - const data = {}; - - const add = (key) => { - data[key] = data[key] || 0; - data[key]++; - }; - - if (runner) { runner - .on(Events.BEGIN_STATE, _.partial(add, 'total')) - .on(Events.SKIP_STATE, () => { - add('total'); - add('skipped'); + .on(RunnerEvents.SKIP_STATE, (test) => this._counter.onSkipped(test)) + .on(RunnerEvents.WARNING, (test) => this._counter.onWarned(test)) + .on(RunnerEvents.ERROR, (test) => this._counter.onErrored(test)) + .on(RunnerEvents.UPDATE_RESULT, (test) => { + return test.updated ? this._counter.onUpdated(test) : this._counter.onPassed(test); }) - .on(Events.WARNING, _.partial(add, 'warned')) - .on(Events.ERROR, _.partial(add, 'errored')) - - .on(Events.UPDATE_RESULT, (res) => { - add(res && res.updated ? 'updated' : 'passed'); + .on(RunnerEvents.TEST_RESULT, (test) => { + return test.equal ? this._counter.onPassed(test) : this._counter.onFailed(test); }) - .on(Events.TEST_RESULT, (res) => { - add(res && res.equal ? 'passed' : 'failed'); - }); + .on(RunnerEvents.RETRY, (test) => this._counter.onRetry(test)); } - this.add = add; + get(type) { + const stats = this._counter.getResult(); - this.get = (name) => name === undefined ? data : data[name]; + return type === undefined ? stats : stats[type]; + } }; diff --git a/lib/test-counter.js b/lib/test-counter.js new file mode 100644 index 000000000..4d8785cc5 --- /dev/null +++ b/lib/test-counter.js @@ -0,0 +1,88 @@ +'use strict'; + +const _ = require('lodash'); + +const STATS = { + total: 'total', + updated: 'updated', + passed: 'passed', + failed: 'failed', + errored: 'errored', + skipped: 'skipped', + warned: 'warned', + retries: 'retries' +}; + +module.exports = class TestCounter { + constructor() { + this._stats = {}; + } + + onUpdated(updated) { + this._addStat(STATS.updated, updated); + } + + onPassed(passed) { + this._addStat(STATS.passed, passed); + } + + onFailed(failed) { + this._addStat(STATS.failed, failed); + } + + onErrored(errored) { + this._addStat(STATS.errored, errored); + } + + onSkipped(skipped) { + this._addStat(STATS.skipped, skipped); + } + + onWarned(warned) { + this._addStat(STATS.warned, warned); + } + + onRetry(retried) { + const suiteStats = this._getSuiteStats(retried); + + suiteStats.retries++; + } + + _addStat(stat, test) { + const suiteStats = this._getSuiteStats(test); + + suiteStats.states[test.state.name] = stat; + } + + _getSuiteStats(test) { + const key = this._buildSuiteKey(test); + + if (!this._stats[key]) { + this._stats[key] = { + retries: 0, + states: {} + }; + } + + return this._stats[key]; + } + + _buildSuiteKey(test) { + return test.suite.fullName + test.browserId; + } + + getResult() { + const statNames = _.keys(STATS); + const result = _.zipObject(statNames, _.fill(Array(statNames.length), 0)); + + _.forEach(this._stats, (suiteStats) => { + result.retries += suiteStats.retries; + _.forEach(suiteStats.states, (stateStatus) => { + result.total++; + result[stateStatus]++; + }); + }); + + return result; + } +}; diff --git a/test/unit/stats.js b/test/unit/stats.js index a75b28e4d..726016861 100644 --- a/test/unit/stats.js +++ b/test/unit/stats.js @@ -1,100 +1,120 @@ 'use strict'; const EventEmitter = require('events').EventEmitter; -const inherit = require('inherit'); +const _ = require('lodash'); +const RunnerEvents = require('../../lib/constants/events'); +const Stats = require('../../lib/stats'); -const Stats = require('lib/stats'); -const Events = require('lib/constants/events'); - -describe('stats', () => { +describe('Stats', () => { let stats; + let runner; + + const stubTest = (opts) => { + opts = _.defaults(opts || {}, {name: 'default-name'}); + + return { + state: {fullName: 'full-' + opts.name, name: opts.name}, + suite: {fullName: 'full-default-suite-name', name: 'default-suite-name'}, + updated: opts.updated, + equal: opts.equal + }; + }; beforeEach(() => { - stats = new Stats(); + runner = new EventEmitter(); + stats = new Stats(runner); }); - it('should return \'undefined\' before adding keys', () => { - assert.isUndefined(stats.get('counter')); + it('should count skipped tests', () => { + runner.emit(RunnerEvents.SKIP_STATE, stubTest()); + + assert.equal(stats.get('skipped'), 1); }); - it('should allow to add new key', () => { - stats.add('counter'); - assert.equal(stats.get('counter'), 1); + it('should count warned tests', () => { + runner.emit(RunnerEvents.WARNING, stubTest()); + + assert.equal(stats.get('warned'), 1); }); - it('should increment existing keys', () => { - stats.add('counter'); - stats.add('counter'); - assert.equal(stats.get('counter'), 2); + it('should count errored tests', () => { + runner.emit(RunnerEvents.ERROR, stubTest()); + + assert.equal(stats.get('errored'), 1); }); - it('should return all full stat', () => { - stats.add('counter'); - stats.add('counter'); - stats.add('counter'); - stats.add('counter2'); - stats.add('counter3'); - stats.add('counter3'); - assert.deepEqual(stats.get(), { - counter: 3, - counter2: 1, - counter3: 2 - }); + it('should count updated tests', () => { + runner.emit(RunnerEvents.UPDATE_RESULT, stubTest({updated: true})); + + assert.equal(stats.get('updated'), 1); }); -}); -describe('stats listener', () => { - let stats; - let Runner = inherit(EventEmitter, {}); - let runner; + it('should count passed tests on "UPDATE_RESULT" event', () => { + runner.emit(RunnerEvents.UPDATE_RESULT, stubTest({updated: false})); - beforeEach(() => { - runner = new Runner(); - stats = new Stats(runner); + assert.equal(stats.get('passed'), 1); }); - it('should return undefined before triggering any events', () => { - assert.isUndefined(stats.get('total')); + it('should count failed tests on "TEST_RESULT" event', () => { + runner.emit(RunnerEvents.TEST_RESULT, stubTest({equal: false})); + + assert.equal(stats.get('failed'), 1); }); - it('should count on beginState event', () => { - runner.emit(Events.BEGIN_STATE); - assert.equal(stats.get('total'), 1); + it('should count passed tests on "TEST_RESULT" event', () => { + runner.emit(RunnerEvents.TEST_RESULT, stubTest({equal: true})); + + assert.equal(stats.get('passed'), 1); }); - it('should count on skipState event', () => { - runner.emit(Events.SKIP_STATE); + it('should count retried tests on "RETRY" event', () => { + runner.emit(RunnerEvents.RETRY, stubTest({name: 'some-test'})); + runner.emit(RunnerEvents.TEST_RESULT, stubTest({equal: true, name: 'some-test'})); + assert.equal(stats.get('total'), 1); - assert.equal(stats.get('skipped'), 1); + assert.equal(stats.get('retries'), 1); + assert.equal(stats.get('passed'), 1); }); - it('should count on warning event', () => { - runner.emit(Events.WARNING); + it('should count warned tests on "WARNING" event', () => { + runner.emit(RunnerEvents.WARNING, stubTest()); + assert.equal(stats.get('warned'), 1); }); - it('should count on error event', () => { - runner.emit(Events.ERROR); - assert.equal(stats.get('errored'), 1); - }); + it('should count total test count', () => { + runner.emit(RunnerEvents.TEST_RESULT, stubTest({equal: false, name: 'first'})); + runner.emit(RunnerEvents.TEST_RESULT, stubTest({equal: true, name: 'second'})); - it('should count on updated images', () => { - runner.emit(Events.UPDATE_RESULT, {updated: true}); - assert.equal(stats.get('updated'), 1); + assert.equal(stats.get('total'), 2); }); - it('should count on passed images', () => { - runner.emit(Events.UPDATE_RESULT, {updated: false}); - assert.equal(stats.get('passed'), 1); - }); + it('should get full stat', () => { + runner.emit(RunnerEvents.UPDATE_RESULT, stubTest({updated: true, name: 'updated'})); + runner.emit(RunnerEvents.RETRY, stubTest({name: 'passed'})); + runner.emit(RunnerEvents.TEST_RESULT, stubTest({equal: true, name: 'passed'})); + runner.emit(RunnerEvents.TEST_RESULT, stubTest({equal: false, name: 'failed'})); + runner.emit(RunnerEvents.ERROR, stubTest({name: 'errored'})); + runner.emit(RunnerEvents.SKIP_STATE, stubTest({name: 'skipped'})); + runner.emit(RunnerEvents.WARNING, stubTest({name: 'warned'})); - it('should count test passed', () => { - runner.emit(Events.TEST_RESULT, {equal: true}); - assert.equal(stats.get('passed'), 1); + assert.deepEqual(stats.get(), { + total: 6, + updated: 1, + passed: 1, + failed: 1, + errored: 1, + skipped: 1, + warned: 1, + retries: 1 + }); }); - it('should count test failed', () => { - runner.emit(Events.TEST_RESULT, {equal: false}); - assert.equal(stats.get('failed'), 1); + it('should handle cases when several events were emitted for the same test', () => { + runner.emit(RunnerEvents.SKIP_STATE, stubTest({name: 'some-state'})); + runner.emit(RunnerEvents.ERROR, stubTest({name: 'some-state'})); + + assert.equal(stats.get('skipped'), 0); + assert.equal(stats.get('errored'), 1); }); }); diff --git a/test/unit/reporters/utils/test-counter.js b/test/unit/test-counter.js similarity index 57% rename from test/unit/reporters/utils/test-counter.js rename to test/unit/test-counter.js index c64f77acc..5eb8ac67c 100644 --- a/test/unit/reporters/utils/test-counter.js +++ b/test/unit/test-counter.js @@ -1,8 +1,8 @@ 'use strict'; -const TestCounter = require('lib/reporters/utils/test-counter'); +const TestCounter = require('lib/test-counter'); -const mkCompleted_ = (opts) => { +const stubTest = (opts) => { opts = opts || {}; return { @@ -37,21 +37,12 @@ describe('TestCounter', () => { describe('onRetry', () => { it('should increase `retries` count', () => { - const completed = mkCompleted_({state: 'defaultState'}); + const completed = stubTest({state: 'defaultState'}); counter.onRetry(completed); assert.equal(counter.getResult().retries, 1); }); - - it('should clear stats for retried suite', () => { - const completed = mkCompleted_({state: 'defaultState'}); - - counter.onPassed(completed); - counter.onRetry(completed); - - assert.equal(counter.getResult().passed, 0); - }); }); describe('getResult', () => { @@ -63,23 +54,27 @@ describe('TestCounter', () => { }); }); - it('should calculate total from `updated`, `passed`, `failed` and `skipped`', () => { - const updated = mkCompleted_({state: 'updated'}); - const passed = mkCompleted_({state: 'passed'}); - const failed = mkCompleted_({state: 'failed'}); - const skipped = mkCompleted_({state: 'skipped'}); + it('should calculate total from `updated`, `passed`, `failed`, `errored`, `skipped` and `warned`', () => { + const updated = stubTest({state: 'updated'}); + const passed = stubTest({state: 'passed'}); + const failed = stubTest({state: 'failed'}); + const errored = stubTest({state: 'errored'}); + const skipped = stubTest({state: 'skipped'}); + const warned = stubTest({state: 'warned'}); counter.onUpdated(updated); counter.onPassed(passed); counter.onFailed(failed); + counter.onErrored(errored); counter.onSkipped(skipped); + counter.onWarned(warned); - assert.equal(counter.getResult().total, 4); + assert.equal(counter.getResult().total, 6); }); it('should not add retries to total', () => { - const passed = mkCompleted_({state: 'some_state'}); - const retried = mkCompleted_({ + const passed = stubTest({state: 'some_state'}); + const retried = stubTest({ state: 'some_other_state', browserId: 'some_browser' }); @@ -93,17 +88,8 @@ describe('TestCounter', () => { }); function testCounter_(name) { - it('should count test result if it has state', () => { - const completed = mkCompleted_({state: 'defaultState'}); - const counter = new TestCounter(); - - counter['on' + name](completed); - - assert.equal(counter.getResult()[name.toLowerCase()], 1); - }); - - it('should count test result if it does not have state', () => { - const completed = mkCompleted_({state: undefined}); + it('should count test result', () => { + const completed = stubTest({state: 'defaultState'}); const counter = new TestCounter(); counter['on' + name](completed); @@ -111,18 +97,9 @@ function testCounter_(name) { assert.equal(counter.getResult()[name.toLowerCase()], 1); }); - it('should not count test result if it does not have state or suite', () => { - const completed = {browserId: 'some_browser'}; - const counter = new TestCounter(); - - counter['on' + name](completed); - - assert.equal(counter.getResult()[name.toLowerCase()], 0); - }); - it('should not count test result twice for same suite and browser', () => { const counter = new TestCounter(); - const completed = mkCompleted_({ + const completed = stubTest({ browserId: 'test_browser', state: 'test_state' }); @@ -133,5 +110,3 @@ function testCounter_(name) { assert.equal(counter.getResult()[name.toLowerCase()], 1); }); } - -