-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
1,044 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
'use strict'; | ||
|
||
const Collector = require('./lib/collector'); | ||
const geminiCollector = require('./lib/collector/gemini'); | ||
const parseConfig = require('./lib/config'); | ||
|
||
module.exports = (gemini, opts) => { | ||
const config = parseConfig(opts); | ||
|
||
if (!config.enabled) { | ||
return; | ||
} | ||
|
||
const collector = Collector.create(geminiCollector, config); | ||
|
||
gemini.on(gemini.events.TEST_RESULT, (data) => { | ||
data.equal ? collector.addSuccess(data) : collector.addFail(data); | ||
}); | ||
|
||
gemini.on(gemini.events.SKIP_STATE, (data) => collector.addSkipped(data)); | ||
|
||
gemini.on(gemini.events.RETRY, (data) => collector.addRetry(data)); | ||
|
||
gemini.on(gemini.events.ERROR, (data) => collector.addError(data)); | ||
|
||
gemini.on(gemini.events.END_RUNNER, () => collector.saveFile()); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
'use strict'; | ||
|
||
const Collector = require('./lib/collector'); | ||
const hermioneCollector = require('./lib/collector/hermione'); | ||
const parseConfig = require('./lib/config'); | ||
|
||
module.exports = (hermione, opts) => { | ||
const config = parseConfig(opts); | ||
|
||
if (!config.enabled) { | ||
return; | ||
} | ||
|
||
const collector = Collector.create(hermioneCollector, config); | ||
|
||
hermione.on(hermione.events.TEST_PASS, (data) => collector.addSuccess(data)); | ||
|
||
hermione.on(hermione.events.TEST_FAIL, (data) => collector.addFail(data)); | ||
hermione.on(hermione.events.SUITE_FAIL, (data) => collector.addFail(data)); | ||
|
||
hermione.on(hermione.events.TEST_PENDING, (data) => collector.addSkipped(data)); | ||
|
||
hermione.on(hermione.events.RETRY, (data) => collector.addRetry(data)); | ||
|
||
hermione.on(hermione.events.ERROR, (data) => collector.addError(data)); | ||
|
||
hermione.on(hermione.events.RUNNER_END, () => collector.saveFile()); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
'use strict'; | ||
|
||
const _ = require('lodash'); | ||
|
||
module.exports = class DataCollector { | ||
static create() { | ||
return new DataCollector(); | ||
} | ||
|
||
constructor() { | ||
this._data = {}; | ||
} | ||
|
||
append(test) { | ||
const id = this._generateId(test); | ||
this._data[id] = test; | ||
} | ||
|
||
getData() { | ||
return this._data; | ||
} | ||
|
||
_generateId(test) { | ||
return _(test) | ||
.at(['fullName', 'browserId']) | ||
.compact() | ||
.join('.'); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
'use strict'; | ||
|
||
const _ = require('lodash'); | ||
const utils = require('./utils'); | ||
|
||
exports.configureTestResult = (result) => { | ||
return { | ||
fullName: result.state.fullName, | ||
browserId: result.browserId, | ||
file: result.suite.file, | ||
referencePath: utils.getRelativePath(result.referencePath), | ||
url: result.suite.url | ||
}; | ||
}; | ||
|
||
exports.isFailedTest = (result) => { | ||
return result.hasOwnProperty('equal'); | ||
}; | ||
|
||
exports.getSkipReason = (result) => { | ||
return _.get(result, 'suite.skipComment', 'No skip reason'); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
'use strict'; | ||
|
||
const _ = require('lodash'); | ||
const url = require('url'); | ||
const utils = require('./utils'); | ||
|
||
const getFilePath = (test) => test && test.file || getFilePath(test.parent); | ||
|
||
exports.configureTestResult = (result) => { | ||
const filePath = getFilePath(result) || ''; | ||
const metaUrl = _.get(result, 'meta.url', ''); | ||
|
||
return { | ||
fullName: result.fullTitle(), | ||
browserId: result.browserId, | ||
file: utils.getRelativePath(filePath), | ||
url: url.parse(metaUrl).path | ||
}; | ||
}; | ||
|
||
exports.isFailedTest = (result) => { | ||
return result.state === 'failed' || result.hook && result.hook.state === 'failed'; | ||
}; | ||
|
||
exports.getSkipReason = (result) => { | ||
const findSkipReason = (test) => test.parent && findSkipReason(test.parent) || test.skipReason; | ||
|
||
return findSkipReason(result) || 'No skip reason'; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
'use strict'; | ||
|
||
const _ = require('lodash'); | ||
const Promise = require('bluebird'); | ||
const fs = Promise.promisifyAll(require('fs-extra')); | ||
|
||
const DataCollector = require('./data-collector'); | ||
|
||
module.exports = class Collector { | ||
static create(toolCollector, config) { | ||
return new Collector(toolCollector, config); | ||
} | ||
|
||
constructor(toolCollector, config) { | ||
this._toolCollector = toolCollector; | ||
this._dataCollector = DataCollector.create(); | ||
this._config = config; | ||
} | ||
|
||
addSuccess(result) { | ||
this._addTestResult(result, {status: 'success'}); | ||
} | ||
|
||
addFail(result) { | ||
this._addTestResult(result, {status: 'fail'}); | ||
} | ||
|
||
addSkipped(result) { | ||
this._addTestResult(result, { | ||
status: 'skipped', | ||
skipReason: this._toolCollector.getSkipReason(result) | ||
}); | ||
} | ||
|
||
addRetry(result) { | ||
this._toolCollector.isFailedTest(result) | ||
? this.addFail(result) | ||
: this.addError(result); | ||
} | ||
|
||
addError(result) { | ||
this._addTestResult(result, { | ||
status: 'error', | ||
errorReason: result.stack || result.message || '' | ||
}); | ||
} | ||
|
||
saveFile() { | ||
return fs.outputJsonAsync(this._config.path, this._dataCollector.getData()) | ||
.catch(console.error); | ||
} | ||
|
||
_addTestResult(result, props) { | ||
const configuredResult = this._toolCollector.configureTestResult(result); | ||
const test = _.extend(configuredResult, props); | ||
|
||
this._dataCollector.append(test); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
'use strict'; | ||
|
||
const path = require('path'); | ||
|
||
exports.getRelativePath = (fullPath) => { | ||
return fullPath | ||
? path.relative(process.cwd(), fullPath) | ||
: null; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
'use strict'; | ||
|
||
const _ = require('lodash'); | ||
const configParser = require('gemini-configparser'); | ||
|
||
const root = configParser.root; | ||
const section = configParser.section; | ||
const option = configParser.option; | ||
|
||
const ENV_PREFIX = 'json_reporter_'; | ||
|
||
const getParser = () => { | ||
return root(section({ | ||
enabled: option({ | ||
defaultValue: true, | ||
parseEnv: JSON.parse, | ||
validate: _.isBoolean | ||
}), | ||
path: option({ | ||
defaultValue: 'json-reporter.json', | ||
validate: _.isString | ||
}) | ||
}), {envPrefix: ENV_PREFIX}); | ||
}; | ||
|
||
module.exports = (options) => { | ||
const env = process.env; | ||
const argv = process.argv; | ||
|
||
return getParser()({options, env, argv}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
'use strict'; | ||
|
||
const _ = require('lodash'); | ||
const EventEmitter = require('events').EventEmitter; | ||
const proxyquire = require('proxyquire'); | ||
|
||
const Collector = require('../lib/collector'); | ||
const geminiCollector = require('../lib/collector/gemini'); | ||
|
||
describe('json-reporter/gemini', () => { | ||
const sandbox = sinon.sandbox.create(); | ||
|
||
let gemini; | ||
let parseConfig; | ||
|
||
const mkGemini_ = () => { | ||
const emitter = new EventEmitter(); | ||
|
||
emitter.events = { | ||
TEST_RESULT: 'testResult', | ||
SKIP_STATE: 'skipState', | ||
RETRY: 'retry', | ||
ERROR: 'err', | ||
END_RUNNER: 'endRunner' | ||
}; | ||
|
||
return emitter; | ||
}; | ||
|
||
const initReporter_ = (opts) => { | ||
opts = _.defaults(opts || {}, { | ||
enabled: true, | ||
path: '/default/path' | ||
}); | ||
|
||
parseConfig = sandbox.stub().returns(opts); | ||
|
||
const geminiReporter = proxyquire('../gemini', { | ||
'./lib/config': parseConfig | ||
}); | ||
|
||
return geminiReporter(gemini, opts); | ||
}; | ||
|
||
beforeEach(() => { | ||
gemini = mkGemini_(); | ||
}); | ||
|
||
afterEach(() => sandbox.restore()); | ||
|
||
it('should do nothing if plugin is disabled', () => { | ||
sandbox.stub(Collector, 'create'); | ||
|
||
initReporter_({enabled: false}); | ||
|
||
assert.notCalled(Collector.create); | ||
}); | ||
|
||
it('should parse config', () => { | ||
initReporter_({enabled: true, path: '/some/path'}); | ||
|
||
assert.calledOnce(parseConfig); | ||
assert.calledWithMatch(parseConfig, {enabled: true, path: '/some/path'}); | ||
}); | ||
|
||
it('should create collector', () => { | ||
sandbox.stub(Collector, 'create'); | ||
|
||
initReporter_({enabled: true, path: '/some/path'}); | ||
|
||
assert.calledWith( | ||
Collector.create, | ||
geminiCollector, | ||
{enabled: true, path: '/some/path'} | ||
); | ||
}); | ||
|
||
describe('call the appropriate event handlers', () => { | ||
beforeEach(() => initReporter_()); | ||
|
||
it('should call appropriate method for passed test', () => { | ||
const data = {equal: true}; | ||
sandbox.stub(Collector.prototype, 'addSuccess'); | ||
|
||
gemini.emit(gemini.events.TEST_RESULT, data); | ||
|
||
assert.calledOnce(Collector.prototype.addSuccess); | ||
assert.calledWith(Collector.prototype.addSuccess, data); | ||
}); | ||
|
||
it('should call appropriate method for failed test', () => { | ||
const data = {equal: false}; | ||
sandbox.stub(Collector.prototype, 'addFail'); | ||
|
||
gemini.emit(gemini.events.TEST_RESULT, data); | ||
|
||
assert.calledOnce(Collector.prototype.addFail); | ||
assert.calledWith(Collector.prototype.addFail, data); | ||
}); | ||
|
||
it('should call appropriate method for skipped test', () => { | ||
const data = {foo: 'bar'}; | ||
sandbox.stub(Collector.prototype, 'addSkipped'); | ||
|
||
gemini.emit(gemini.events.SKIP_STATE, data); | ||
|
||
assert.calledOnce(Collector.prototype.addSkipped); | ||
assert.calledWith(Collector.prototype.addSkipped, data); | ||
}); | ||
|
||
it('should call appropriate method for retried test', () => { | ||
const data = {foo: 'bar'}; | ||
sandbox.stub(Collector.prototype, 'addRetry'); | ||
|
||
gemini.emit(gemini.events.RETRY, data); | ||
|
||
assert.calledOnce(Collector.prototype.addRetry); | ||
assert.calledWith(Collector.prototype.addRetry, data); | ||
}); | ||
|
||
it('should call appropriate method for error occurred on test execution', () => { | ||
const data = {foo: 'bar'}; | ||
sandbox.stub(Collector.prototype, 'addError'); | ||
|
||
gemini.emit(gemini.events.ERROR, data); | ||
|
||
assert.calledOnce(Collector.prototype.addError); | ||
assert.calledWith(Collector.prototype.addError, data); | ||
}); | ||
|
||
it('should save collected test data into file when the tests are completed', () => { | ||
sandbox.stub(Collector.prototype, 'saveFile'); | ||
|
||
gemini.emit(gemini.events.END_RUNNER); | ||
|
||
assert.calledOnce(Collector.prototype.saveFile); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.