Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update reporter to be compatible with wdio v5 #14

Merged
merged 13 commits into from
Dec 14, 2019
9 changes: 8 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{
"presets": [
"es2015"
[
"env",
{
"targets": {
"node": "8"
}
}
]
]
}
4 changes: 1 addition & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,4 @@ notifications:

language: node_js
node_js:
- "6"
- "4"
- "0.12"
- "8"
65 changes: 30 additions & 35 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
'use strict';

const { EventEmitter } = require('events');
const WdioReporter = require('@wdio/reporter').default;
const { buildFormatter, events } = require('./lib/message');
const { flow } = require('lodash');
const { inherits } = require('util');

module.exports = WdioTeamcityReporter;
module.exports.reporterName = 'teamcity';

/**
* @param {object} baseReporter
Expand All @@ -17,36 +13,35 @@ module.exports.reporterName = 'teamcity';
* @param {string} reporterOptions.message
* @return {wdioTeamcityReporter}
*/
function WdioTeamcityReporter(baseReporter, wdioConf, reporterOptions = {}) {
this.baseReporter = baseReporter;

const opts = {
captureStandardOutput: typeof reporterOptions.captureStandardOutput === 'boolean'
? reporterOptions.captureStandardOutput
: false,
flowId: typeof reporterOptions.flowId === 'boolean'
? reporterOptions.flowId
: true,
name: typeof reporterOptions.message === 'string'
? reporterOptions.message
: '[title]',
};

this.enableRealTimeOutput(opts);
}

inherits(WdioTeamcityReporter, EventEmitter);

WdioTeamcityReporter.prototype.enableRealTimeOutput = function (opts) {
events.forEach(event => this.on(event, flow(buildFormatter(event, opts), output)));
};
class WdioTeamcityReporter extends WdioReporter {
constructor(reporterOptions) {
Object.assign(reporterOptions, {
captureStandardOutput: typeof reporterOptions.captureStandardOutput === 'boolean'
? reporterOptions.captureStandardOutput
: false,
flowId: typeof reporterOptions.flowId === 'boolean'
? reporterOptions.flowId
: true,
name: typeof reporterOptions.message === 'string'
? reporterOptions.message
: '[title]',
stdout: true,
});
super(reporterOptions);
this.enableRealTimeOutput(reporterOptions);
}

/**
* @param {string} msg
* @return {string}
*/
function output(msg) {
if (msg) {
console.log(msg);
enableRealTimeOutput(opts) {
events.forEach(event => {
this[event] = (...args) =>
flow(buildFormatter(event, opts), msg => {
if (msg) {
this.write(`${msg}\n`);
}
})(...args);
});
}
}

module.exports.default = WdioTeamcityReporter;
module.exports.reporterName = 'teamcity';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like wdio tries to use this as a ES6 module.
Adding module.exports.default = WdioTeamcityReporter; made it not crash for me, when trying to consume this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added that. It should be working now. I was using importing the reporter instead of specifying the name so I didn't catch that. Thanks!

24 changes: 12 additions & 12 deletions lib/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,21 @@
const { camelCase, get, invoke } = require('lodash');

const paths = {
browser: ({ suite }) => ['suite', 'runner', suite.cid, 'browserName'],
details: () => 'suite.err.stack',
flowId: ({ suite }) => ['reporter', 'baseReporter', 'stats', 'runners', suite.cid, 'sessionID'],
browser: () => 'reporter.browser.capabilities.browserName',
details: () => 'suite.error.stack',
flowId: () => 'reporter.browser.sessionId',
hash: () => 'suite.specHash',
message: () => 'suite.err.message',
message: () => 'suite.error.message',
title: () => 'suite.title',
};

const events = {
'suite:start': '##teamcity[testSuiteStarted flowId=\'[flowId]\' name=\'[name]\']',
'test:start': '##teamcity[testStarted flowId=\'[flowId]\' name=\'[name]\' captureStandardOutput=\'[captureStandardOutput]\']',
'test:end': '##teamcity[testFinished flowId=\'[flowId]\' name=\'[name]\']',
'test:fail': '##teamcity[testFailed flowId=\'[flowId]\' name=\'[name]\' message=\'[message]\' details=\'[details]\']',
'test:pending': '##teamcity[testIgnored flowId=\'[flowId]\' name=\'[name]\' message=\'pending\']',
'suite:end': '##teamcity[testSuiteFinished flowId=\'[flowId]\' name=\'[name]\']',
var events = {
'onSuiteStart': '##teamcity[testSuiteStarted flowId=\'[flowId]\' name=\'[name]\']',
'onTestStart': '##teamcity[testStarted flowId=\'[flowId]\' name=\'[name]\' captureStandardOutput=\'[captureStandardOutput]\']',
'onTestEnd': '##teamcity[testFinished flowId=\'[flowId]\' name=\'[name]\']',
'onTestFail': '##teamcity[testFailed flowId=\'[flowId]\' name=\'[name]\' message=\'[message]\' details=\'[details]\']',
'onTestSkip': '##teamcity[testIgnored flowId=\'[flowId]\' name=\'[name]\' message=\'pending\']',
'onSuiteEnd': '##teamcity[testSuiteFinished flowId=\'[flowId]\' name=\'[name]\']'
};

exports.buildFormatter = buildFormatter;
Expand All @@ -52,7 +52,7 @@ function buildFormatter(eventName, opts) {
return formatter;

function formatter(suite) {
if (suite.pending && eventName !== 'test:pending') {
if (suite.pending && eventName !== 'onTestSkip') {
return '';
}

Expand Down
16 changes: 12 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "WebdriverIO Teamcity reporter",
"main": "index.js",
"engines": {
"node": ">=0.12"
"node": ">=8.11.0"
},
"scripts": {
"cleanup": "git reset --hard",
Expand Down Expand Up @@ -33,13 +33,21 @@
"lodash": "^4.15.0"
},
"devDependencies": {
"@wdio/cli": "^5.0.0",
"@wdio/local-runner": "^5.7.0",
"@wdio/mocha-framework": "^5.7.0",
"@wdio/reporter": "^5.7.0",
"@wdio/selenium-standalone-service": "^5.7.0",
"@wdio/sync": "^5.7.0",
"babel-cli": "^6.11.4",
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "^6.13.2",
"babel-register": "^6.11.6",
"eslint": "^2.13.1",
"in-publish": "^2.0.0",
"tape": "^4.6.0",
"wdio-mocha-framework": "^0.2.13",
"webdriverio": "^4.2.5"
"tape": "^4.6.0"
},
"peerDependencies": {
"@wdio/cli": "^5.0.0"
}
}
12 changes: 5 additions & 7 deletions test/integration/wdio.conf.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
'use strict';

const teamcity = require('../../');
const teamcity = require('../../').default;

exports.config = {
specs: ['./test/integration/*.js'],

maxInstances: 2,

capabilities: [{
maxInstances: 2,
browserName: 'firefox',
Expand All @@ -26,15 +24,15 @@ exports.config = {

framework: 'mocha',

reporters: [teamcity],

reporterOptions: {
reporters: [[teamcity, {
flowId: false,
message: '[browser]/[title]', // [browser] [title] [hash]
},
}]],

mochaOpts: {
timeout: 60000,
ui: 'tdd',
},

services: ['selenium-standalone'],
};
16 changes: 8 additions & 8 deletions test/unit/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,29 @@ const opts = {
test('formatter for events', t => {
const reporter = mockReporterContext();

t.test('suite:start', a => {
const msg = buildFormatter('suite:start', opts).call(reporter, mockSuite('suite:start'));
t.test('onSuiteStart', a => {
const msg = buildFormatter('onSuiteStart', opts).call(reporter, mockSuite('onSuiteStart'));

a.plan(1);
assertMsg(a, '##teamcity[testSuiteStarted ', msg);
});

t.test('test:start', a => {
const msg = buildFormatter('test:start', opts).call(reporter, mockSuite('test:start'));
t.test('onTestStart', a => {
const msg = buildFormatter('onTestStart', opts).call(reporter, mockSuite('onTestStart'));

a.plan(1);
assertMsg(a, '##teamcity[testStarted ', msg);
});

t.test('test:end', a => {
const msg = buildFormatter('test:end', opts).call(reporter, mockSuite('test:end'));
t.test('onTestEnd', a => {
const msg = buildFormatter('onTestEnd', opts).call(reporter, mockSuite('onTestEnd'));

a.plan(1);
assertMsg(a, '##teamcity[testFinished ', msg);
});

t.test('suite:end', a => {
const msg = buildFormatter('suite:end', opts).call(reporter, mockSuite('suite:end'));
t.test('onSuiteEnd', a => {
const msg = buildFormatter('onSuiteEnd', opts).call(reporter, mockSuite('onSuiteEnd'));

a.plan(1);
assertMsg(a, '##teamcity[testSuiteFinished ', msg);
Expand Down
40 changes: 23 additions & 17 deletions test/unit/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
'use strict';

const Reporter = require('../../');
const mockReporterContext = require('./fixture/reporter-context');
const Reporter = require('../../').default;
const test = require('tape');

const events = [
'start',
'suite:start',
'hook:start',
'hook:end',
'test:start',
'test:end',
'test:pass',
'test:fail',
'test:pending',
'suite:end',
'end',
'onRunnerStart',
'onBeforeCommand',
'onAfterCommand',
'onScreenshot',
'onSuiteStart',
'onHookStart',
'onHookEnd',
'onTestStart',
'onTestPass',
'onTestFail',
'onTestSkip',
'onTestEnd',
'onSuiteEnd',
'onRunnerEnd',
];

const mockedContext = mockReporterContext();
const reporter = new Reporter(mockedContext.baseReporter);
const reporter = new Reporter({});
reporter.outputStream = {
write(msg) {
console.log(msg);
},
};

events.forEach(event => test(event, t => {
const data = {
Expand All @@ -36,9 +42,9 @@ events.forEach(event => test(event, t => {
};

if (event.indexOf('fail') > -1) {
data.err = new Error('artificial error');
data.error = new Error('artificial error');
}

reporter.emit(event, data);
reporter[event](data);
t.end();
}));