docs/internal-api.md
In this guide we will overview the internal API of CodeceptJS. This knowledge is required for customization, writing plugins, etc.
CodeceptJS provides an API which can be loaded via require('codeceptjs') when CodeceptJS is installed locally. Otherwise, you can load codeceptjs API via global codeceptjs object:
// via module
const { recorder, event, output } = require('codeceptjs');
// or using global object
const { recorder, event, output } = codeceptjs;
These internal objects are available:
codecept: test runner classconfig: current codecept configevent: event listenerrecorder: global promise chainoutput: internal printercontainer: dependency injection container for tests, includes current helpers and support objectshelper: basic helper classactor: basic actor (I) classAPI reference is available on GitHub. Also please check the source code of corresponding modules.
CodeceptJS has a dependency injection container with helpers and support objects. They can be retrieved from the container:
const { container } = require('codeceptjs');
// get object with all helpers
const helpers = container.helpers();
// get helper by name
const { WebDriver } = container.helpers();
// get support objects
const supportObjects = container.support();
// get support object by name
const { UserPage } = container.support();
// get all registered plugins
const plugins = container.plugins();
New objects can also be added to container in runtime:
const { container } = require('codeceptjs');
container.append({
helpers: { // add helper
MyHelper: new MyHelper({ config1: 'val1' });
},
support: { // add page object
UserPage: require('./pages/user');
}
})
Use this trick to define custom objects inside
boostrapscript
The container also contains the current Mocha instance:
const mocha = container.mocha();
CodeceptJS provides a module with an event dispatcher and set of predefined events.
It can be required from codeceptjs package if it is installed locally.
const { event } = require('codeceptjs');
module.exports = function() {
event.dispatcher.on(event.test.before, function (test) {
console.log('--- I am before test --');
});
}
Available events:
event.test.before(test) - async when Before hooks from helpers and from test is executedevent.test.after(test) - async after each testevent.test.started(test) - sync at the very beginning of a test.event.test.passed(test) - sync when test passedevent.test.failed(test, error) - sync when test failedevent.test.finished(test) - sync when test finishedevent.suite.before(suite) - async before a suiteevent.suite.after(suite) - async after a suiteevent.step.before(step) - async when the step is scheduled for executionevent.step.after(step)- async after a stepevent.step.started(step) - sync when step starts.event.step.passed(step) - sync when step passed.event.step.failed(step, err) - sync when step failed.event.step.finished(step) - sync when step finishes.event.step.comment(step) - sync fired for comments like I.say.event.all.before - before running testsevent.all.after - after running testsevent.all.result - when results are printedevent.workers.before - before spawning workers in parallel runevent.workers.after - after workers finished in parallel runevent.workers.result - test results after workers finished in parallel runsync - means that event is fired in the moment of the action happening. async - means that event is fired when an action is scheduled. Use
recorderto schedule your actions.
For further reference look for currently available listeners using the event system.
To inject asynchronous functions in a test or before/after a test you can subscribe to corresponding event and register a function inside a recorder object. Recorder represents a global promises chain.
Provide a function in the first parameter, a function must be async or must return a promise:
const { event, recorder } = require('codeceptjs');
module.exports = function() {
event.dispatcher.on(event.test.before, function (test) {
const request = require('request');
recorder.add('create fixture data via API', function() {
return new Promise((doneFn, errFn) => {
request({
baseUrl: 'http://api.site.com/',
method: 'POST',
url: '/users',
json: { name: 'john', email: '[email protected]' }
}), (err, httpResponse, body) => {
if (err) return errFn(err);
doneFn();
}
});
}
});
}
CodeceptJS config can be accessed from require('codeceptjs').config.get():
const { config } = require('codeceptjs');
// config object has access to all values of the current config file
if (config.get().myKey == 'value') {
// run something
}
Output module provides four verbosity levels. Depending on the mode you can have different information printed using corresponding functions.
default: prints basic information using output.printsteps: toggled by --steps option, prints step executiondebug: toggled by --debug option, prints steps, and debug information with output.debugverbose: toggled by --verbose prints debug information and internal logs with output.logIt is recommended to avoid console.log and use output.* methods for printing.
const output = require('codeceptjs').output;
output.print('This is basic information');
output.debug('This is debug information');
output.log('This is verbose logging information');
The test events are providing a test object with following properties:
title title of the testbody test function as a stringopts additional test options like retries, and otherspending true if test is scheduled for execution and false if a test has finishedtags array of tags for this testartifacts list of files attached to this test. Screenshots, videos and other files can be saved here and shared accross different reportersfile path to a file with a teststeps array of executed steps (available only in test.passed, test.failed, test.finished event)skipInfo additional test options when test skippedmessage string with reason for skipdescription string with test body
and othersStep events provide step objects with following fields:
name name of a step, like 'see', 'click', and othersactor current actor, in most cases it is Ihelper current helper instance used to execute this stephelperMethod corresponding helper method, in most cases is the same as namestatus status of a step (passed or failed)prefix if a step is executed inside within block contain within text, like: 'Within .js-signup-form'.args passed argumentsWhenever you execute tests with --verbose option you will see registered events and promises executed by a recorder.
You can run CodeceptJS tests from your script.
const { codecept: Codecept } = require('codeceptjs');
// define main config
const config = {
helpers: {
WebDriver: {
browser: 'chrome',
url: 'http://localhost'
}
}
};
const opts = { steps: true };
// run CodeceptJS inside async function
(async () => {
const codecept = new Codecept(config, options);
codecept.init(__dirname);
try {
await codecept.bootstrap();
codecept.loadTests('**_test.js');
// run tests
await codecept.run(test);
} catch (err) {
printError(err);
process.exitCode = 1;
} finally {
await codecept.teardown();
}
})();
Also, you can run tests inside workers in a custom scripts. Please refer to the parallel execution guide for more details.