Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ Implement corresponding methods to them.
* `_afterStep` - after each step
* `_beforeSuite` - before each suite
* `_afterSuite` - after each suite
* `_passed` - after a test passed
* `_failed` - after a test failed

Each implemented method should return a value as they will be added to global promise chain as well.

Expand Down
1 change: 1 addition & 0 deletions lib/codecept.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class Codecept {
mocha.run(() => {
const done = () => {
event.emit(event.all.result, this);
event.emit(event.all.after, this);
};
this.teardown(done);
});
Expand Down
2 changes: 2 additions & 0 deletions lib/command/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const mkdirp = require('mkdirp');
const Config = require('../config');
const Codecept = require('../codecept');
const output = require('../output');
const event = require('../event');

module.exports = function (test, options) {
// registering options globally to use in config
Expand All @@ -34,6 +35,7 @@ module.exports = function (test, options) {
codecept = new Codecept(config, options);
codecept.init(testRoot, (err) => {
if (err) throw new Error(`Error while running bootstrap file :${err}`);
event.emit(event.all.before, this);
codecept.loadTests();
codecept.run(test);
});
Expand Down
9 changes: 9 additions & 0 deletions lib/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ class Helper {

}

/**
* Hook executed after each passed test
*
* @param {*} test
*/
_passed(test) {

}

/**
* Hook executed after each failed test
*
Expand Down
6 changes: 6 additions & 0 deletions lib/listener/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ module.exports = function () {
runAsyncHelpersHook('_before');
});

event.dispatcher.on(event.test.passed, (test) => {
runAsyncHelpersHook('_passed', test, true);
// should not fail test execution, so errors should be caught
recorder.catchWithoutStop(e => error(e));
});

event.dispatcher.on(event.test.failed, (test) => {
runAsyncHelpersHook('_failed', test, true);
// should not fail test execution, so errors should be caught
Expand Down
1 change: 1 addition & 0 deletions test/acceptance/codecept.Nightmare.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const TestHelper = require('../support/TestHelper');
const eventHandlers = require('../data/sandbox/eventHandlers');

module.exports.config = {
tests: './*_test.js',
Expand Down
3 changes: 2 additions & 1 deletion test/acceptance/codecept.Puppeteer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const TestHelper = require('../support/TestHelper.js');
const TestHelper = require('../support/TestHelper');
const eventHandlers = require('../data/sandbox/eventHandlers');

module.exports.config = {
tests: './*_test.js',
Expand Down
3 changes: 2 additions & 1 deletion test/acceptance/codecept.WebDriverIO.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const TestHelper = require('../support/TestHelper.js');
const TestHelper = require('../support/TestHelper');
const eventHandlers = require('../data/sandbox/eventHandlers');

module.exports.config = {
tests: './*_test.js',
Expand Down
54 changes: 54 additions & 0 deletions test/acceptance/event_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const event = require('../../lib').event;
const assert = require('assert');
const expect = require('chai').expect;
const eventHandlers = require('../data/sandbox/eventHandlers');

const expectedEvents = [];

Feature('Events', { retries: 0 });

BeforeSuite((I) => {
expectedEvents.push(...[
event.all.before,
event.suite.before,
]);
expect(eventHandlers.events).to.deep.equal(expectedEvents);
});

Before((I) => {
expectedEvents.push(...[
event.test.before,
]);
expect(eventHandlers.events).to.deep.equal(expectedEvents);
});

After((I) => {
expectedEvents.push(...[
event.test.passed,
// event.test.after, // Does not fire until after After()
]);
expect(eventHandlers.events).to.deep.equal(expectedEvents);
});

AfterSuite(() => {
expectedEvents.push(...[
event.test.after,
// event.suite.after, // Does not fire until after AfterSuite()
// event.all.result, // Does not fire until after AfterSuite()
// event.all.after, // Does not fire until after AfterSuite()
]);

expect(eventHandlers.events).to.deep.equal(expectedEvents);

expectedEvents.forEach((name) => {
assert.equal(eventHandlers.counter[name], 1, `${name} should have been fired`);
});
});

Scenario('Event Hooks @WebDriverIO @Protractor @Nightmare @Puppeteer', (I) => {
expectedEvents.push(...[
event.test.started,
]);
expect(eventHandlers.events).to.deep.equal(expectedEvents);
assert.ok(true);
});
4 changes: 2 additions & 2 deletions test/acceptance/within_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Scenario('within on iframe @WebDriverIO @Puppeteer', (I) => {
I.dontSee('Email Address');
});

Scenario('within on iframe without iframe navigation @WebDriverIO @nightmare @Puppeteer', (I) => {
Scenario('within on iframe without iframe navigation @WebDriverIO @Nightmare @Puppeteer', (I) => {
I.amOnPage('/iframe');
within({ frame: 'iframe' }, () => {
I.fillField('rus', 'Updated');
Expand All @@ -45,7 +45,7 @@ Scenario('within on iframe without iframe navigation @WebDriverIO @nightmare @Pu
I.dontSee('Sign in!');
});

Scenario('within on nested iframe without iframe navigation depth 2 @WebDriverIO @nightmare @Puppeteer', (I) => {
Scenario('within on nested iframe without iframe navigation depth 2 @WebDriverIO @Nightmare @Puppeteer', (I) => {
I.amOnPage('/iframe_nested');
within({ frame: ['[name=wrapper]', '[name=content]'] }, () => {
I.fillField('rus', 'Updated');
Expand Down
8 changes: 8 additions & 0 deletions test/data/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ class MyHelper extends Helper {
return 'hello world';
}

_passed() {
console.log('Event:test.passed (helper)');
}

_failed() {
console.log('Event:test.failed (helper)');
}

method2() {
return 'hello another world';
}
Expand Down
19 changes: 19 additions & 0 deletions test/data/sandbox/codecept.testevents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const eventHandlers = require('./eventHandlers');
require('../fake_driver');

eventHandlers.setConsoleLogging(true);

module.exports.config = {
tests: './*_test.testevents.js',
timeout: 10000,
output: './output',
helpers: {
FakeDriver: {
require: '../helper',
},
},
include: {},
bootstrap: false,
mocha: {},
name: 'sandbox',
};
47 changes: 47 additions & 0 deletions test/data/sandbox/eventHandlers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const event = require('../../../lib').event;

const eventTypes = [
// All Events
event.all.before,
event.all.result,
event.all.after,

// Suite events
event.suite.before,
event.suite.after,

// Test events
event.test.before,
event.test.started,
event.test.passed,
event.test.failed,
event.test.after,
];

let eventRecorder = [];
let eventTypeCounter = {};
const options = {
logToConsole: false,
};

const newEventHandler = (name) => {
event.dispatcher.on(name, () => {
eventRecorder.push(name);
eventTypeCounter[name] = (eventTypeCounter[name] || 0) + 1;
if (options.logToConsole) {
console.log(`Event:${name}`);
}
});
};

eventTypes.forEach(name => newEventHandler(name));

module.exports = {
events: eventRecorder,
counter: eventTypeCounter,
clearEvents: () => {
eventRecorder = [];
eventTypeCounter = {};
},
setConsoleLogging: on => options.logToConsole = !!on,
};
65 changes: 65 additions & 0 deletions test/data/sandbox/testevents_test.testevents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
Feature('Test hooks');

BeforeSuite(() => {
console.log('I\'m simple BeforeSuite hook');
});

Before(() => {
console.log('I\'m simple Before hook');
});

After(() => {
console.log('I\'m simple After hook');
});

AfterSuite(() => {
console.log('I\'m simple AfterSuite hook');
});

BeforeSuite(function* (I) {
const text = yield I.stringWithHook('BeforeSuite');
console.log(text);
});

Before(function* (I) {
const text = yield I.stringWithHook('Before');
console.log(text);
});

After(function* (I) {
const text = yield I.stringWithHook('After');
console.log(text);
});

AfterSuite(function* (I) {
const text = yield I.stringWithHook('AfterSuite');
console.log(text);
});

BeforeSuite(async (I) => {
const text = await I.asyncStringWithHook('BeforeSuite');
console.log(text);
});

Before(async (I) => {
const text = await I.asyncStringWithHook('Before');
console.log(text);
});

After(async (I) => {
const text = await I.asyncStringWithHook('After');
console.log(text);
});

AfterSuite(async (I) => {
const text = await I.asyncStringWithHook('AfterSuite');
console.log(text);
});

Scenario('Simple test 1 @willpass', () => {
console.log('It\'s first test');
});

Scenario('Simple test 2 with error', () => {
assert.ok(false);
});
60 changes: 60 additions & 0 deletions test/runner/codecept_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const expect = require('chai').expect;
const assert = require('assert');
const path = require('path');
const exec = require('child_process').exec;
const event = require('../../lib').event;
const eventHandlers = require('../data/sandbox/eventHandlers');

const runner = path.join(__dirname, '/../../bin/codecept.js');
const codecept_dir = path.join(__dirname, '/../data/sandbox');
Expand Down Expand Up @@ -156,3 +158,61 @@ describe('CodeceptJS Runner', () => {
});
});
});

describe('Codeceptjs Events', () => {
it('should fire events with only passing tests', (done) => {
exec(`${codecept_run_config('codecept.testevents.js')} --grep @willpass`, (err, stdout) => {
assert(!err);
const eventMessages = stdout.split('\n')
.filter(text => text.startsWith('Event:'))
.map(text => text.replace(/^Event:/i, ''));

expect(eventMessages).to.deep.equal([
event.all.before,
event.suite.before,
event.test.before,
event.test.started,
event.test.passed,
`${event.test.passed} (helper)`,
event.test.after,
event.suite.after,
event.all.result,
event.all.after,
]);
done();
});
});

it('should fire events with passing and failing tests', (done) => {
exec(codecept_run_config('codecept.testevents.js'), (err, stdout) => {
assert(err);
const eventMessages = stdout.split('\n')
.filter(text => text.startsWith('Event:'))
.map(text => text.replace(/^Event:/i, ''));

expect(eventMessages).to.deep.equal([
event.all.before,
event.suite.before,

// Test 1 (should pass)
event.test.before,
event.test.started,
event.test.passed,
`${event.test.passed} (helper)`,
event.test.after,

// Test 2 (should fail)
event.test.before,
event.test.started,
event.test.failed,
`${event.test.failed} (helper)`,
event.test.after,

event.suite.after,
event.all.result,
event.all.after,
]);
done();
});
});
});
1 change: 1 addition & 0 deletions test/runner/interface_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ describe('CodeceptJS Interface', () => {
'[1] Queued | return result',
'[1] Queued | fire test.passed',
'[1] Queued | finish test',
'[1] Queued | hook FileSystem._passed()',
'[1] Queued | hook FileSystem._after()',
'[1] Queued | hook FileSystem._afterSuite()',
'[1] Queued | hook FileSystem._finishTest()',
Expand Down