CodeceptJS is a modern end to end testing framework with a special BDD-style syntax. The test is written as a linear scenario of user's action on a site.

Feature('CodeceptJS demo');

Scenario('check Welcome page on site', (I) => {

Tests are expected to be written in ECMAScript 6. Each test is described inside a Scenario function with I object passed into it. I object is an actor, an abstraction for a testing user. I is a proxy object for currently enabled Helpers.

  "helpers": {
    "WebDriverIO": {
      "url": "http://localhost",
      "browser": "chrome"

For current config all methods of I will be taken from WebDriverIO helper. This is done to allow easy switching of running backends so you could replace WebDriverIO with Protractor or Nightmare helpers.

How It Works

Tests are written in synchronous way. Test scenarios should be linear, so tests by themselves should not include promises or callbacks as well. However, behind the scene all actions are wrapped in promises inside the I object. Global promise chain is initialized before each test and all I.* calls will be appended to it as well as setup and teardown.

If you want to get information from a running test you can use yield inside a generator function and special methods of helpers started with grab prefix.

Scenario('try grabbers', async (I) => {
  var title = await I.grabTitle();

then you can use those variables in assertions:

var title = await I.grabTitle();
var assert = require('assert');
assert.equal(title, 'CodeceptJS');


Test execution can be paused in any place of a test with pause() call. This also launches interactive console where you can call actions of I object.


You can also use pause() to check the web application in a browser. Press ENTER to resume test execution.

Interactive shell can be started outside test context by running

codeceptjs shell


Common preparation steps like opening a web page, logging in a user, can be placed in Before or Background hook:

Feature('CodeceptJS Demonstration');

Before((I) => { // or Background

Scenario('test some forms', (I) => {'Create User');
  I.see('User is valid');

Scenario('test title', (I) => {
  I.seeInTitle('Example application');

Same as Before you can use After to run teardown for each scenario.


If you need to run complex setup before all tests and teardown this afterwards you can use BeforeSuite and AfterSuite functions. BeforeSuite and AfterSuite have access to I object, but BeforeSuite/AfterSuite don't have an access to the browser because it's not running at this moment. You can use them to execute handlers that will setup your environment. BeforeSuite/AfterSuite will work only for a file where it was declared (so you can declare different setups for files)

BeforeSuite((I) => {

AfterSuite((I) => {

Here are some ideas where to use BeforeSuite hooks.


To specify the exact area on a page where actions can be performed you can use within function. Everything executed in its context will be narrowed to context specified by locator:

Usage: within('section', ()=>{})

within('.js-signup-form', () => {
  I.fillField('user[login]', 'User');
  I.fillField('user[email]', '[email protected]');
  I.fillField('user[password]', '[email protected]');'button');
I.see('There were problems creating your account.');

within can also work with iframes

When running steps inside a within block will be shown with a shift:



There is a simple way to add additional comments to your test scenario. Use say command to print information to screen:

I.say('I am going to publish post');
I.say('I enter title and body');
I.say('I expect post is visible on site');


If you are using Visual Studio Code or other IDE that supports TypeScript Definitions, you can generate step definitions with

codeceptjs def

Now you should include /// <reference path="./steps.d.ts" /> into your test files to get method autocompletion while writing tests.


Like in Mocha you can use x and only to skip tests or making a single test to run.


CodeceptJS supports Mocha Reporters. They can be used with --reporter options. By default a custom console reporter is enabled.

We are currently working on improving reporters support.


Because CodeceptJS tests use high level DSL it is possible to write tests using different languages. Tests can be written in Portuguese, Russian, Italian, Polish languages using predefined translations.

Test Options

Features and Scenarios have their options that can be set by passing a hash after their names:

Feature('My feature', {key: val});

Scenario('My scenario', {key: val}, (I) => {});


By default there is no timeout for tests, however you can change this value for a specific suite:

Feature('Stop me', {timeout: 5000}); // set timeout to 5s

or for the test:

// set timeout to 1s
Scenario("Stop me faster", {timeout: 1000}, (I) => {});

// disable timeout for this scenario
Scenario("Don't stop me", {timeout: 0}, (I) => {});


Retry Feature

Browser tests can be very fragile and some time you need to re run the few times just to make them pass. This can be done with retries option added to Feature declaration.

CodeceptJS implements retries the same way Mocha do; You can set number of a retries for a feature:

Feature('Complex JS Stuff', {retries: 3})

Scenario('Really complex', (I) => {
  // test goes here

Every Scenario inside this feature will be rerun 3 times. You can make an exception for a specific scenario by passing retries option to a Scenario.

Retry Scenario

Scenario('Really complex', {retries: 2}, (I) => {
  // test goes here

This scenario will be restarted two times on a failure

Retry Step

If you have a step which often fails you can retry execution for this single step. Use retry() function before an action to ask CodeceptJS to retry this step on failure:


If you'd like to retry step more than once pass the amount as parameter:


Additional options can be provided to retry so you can set the additional options (defined in promise-retry library).

// retry action 3 times waiting for 0.1 second before next try
I.retry({ retries: 3, minTimeout: 100 }).see('Hello');

// retry action 3 times waiting no more than 3 seconds for last retry
I.retry({ retries: 3, maxTimeout: 3000 }).see('Hello');

// retry 2 times if error with message 'Node not visible' happens
  retries: 2,
  when: err => err.message === 'Node not visible'

Pass a function to when option to retry only when error matches the expected one.