Skip to main content

Mocha

Mocha.js is a universal test runner providing a number of useful features, such as automatic retry of failed tests. If your project already uses Mocha to run its unit tests, you can use the same runner for your acceptance tests too.

In this article, you will learn:

Examples and Project Templates

If you'd like to dive straight into the code, Serenity/JS GitHub repository provides:

Using Serenity/JS reporting services

To use Serenity/JS reporting services in a Mocha project, you need to:

Serenity/JS test runner adapters

Serenity/JS test runner adapters turn internal, test runner-specific events into Serenity/JS domain events that can contribute to test execution reports produced by Serenity/JS reporting services.

@serenity-js/mocha module provides a test runner adapter you can attach to your Mocha test runner.

Integration architecture described in this section applies to invoking mocha command line interface directly, for example for domain-level, REST/HTTP API-level, or web-based testing using Playwright.

If you want your Mocha scenarios to interact with web interfaces using Selenium Webdriver protocol, or connect them to a Selenium Grid, you should do so via Protractor or WebdriverIO instead.

Serenity/JS + Mocha integration architecture

Installing Serenity/JS test runner adapter

Assuming you already have a Node.js project and Serenity/JS runtime dependencies set up, add the following Node modules:

To do that, run the following command in your terminal:

npm install --save-dev @serenity-js/core @serenity-js/mocha mocha

If you'd like to implement your test suite in TypeScript, also run:

npm install --save-dev typescript ts-node @types/mocha @types/node

Configuring Serenity/JS

If you intend to run your Mocha scenarios using the Mocha CLI, the best way to configure Serenity/JS is to invoke the Serenity/JS configure function in a beforeAll hook, defined in a Mocha support file required upon test execution:

spec/support/serenity.config.ts
import 'mocha'

import { configure } from '@serenity-js/core'

beforeAll(async () => {
// Configure Serenity/JS
configure({
crew: [
'@serenity-js/console-reporter',
'@serenity-js/serenity-bdd',
[ '@serenity-js/core:ArtifactArchiver', { outputDirectory: 'target/site/serenity' } ],
// ... any other reporting services
],
})
})

To learn more about installing and configuring Serenity/JS reporting services appropriate for your project, follow the Serenity/JS reporting guide.

Configuring Mocha

To make sure Mocha loads your Serenity/JS configuration file and correctly interprets TypeScript (if you're using it), create one of the supported Mocha configuration files in your project root directory, e.g. .mocharc.yml:

.mocharc.yml
check-leaks: false
full-trace: true
reporter: '@serenity-js/mocha'
require:
- ts-node/register
- spec/support/serenity.config.ts
spec: 'spec/**/*.spec.ts'
timeout: 5000
v8-stack-trace-limit: 100

Defining Mocha test scenarios

When Serenity/JS reports on Mocha test scenarios, it assumes you're following a common convention where the outermost describe block describes the name of the feature or component under test, and any nested describe blocks contribute to the name of the test scenario.

For example, Serenity/JS will report the below scenario as:

  • feature: Todo List App
  • scenario: when the user is a guest their list is empty
import 'mocha'

describe('Todo List App', () => { // - feature or component name

describe('when the user is', () => { // - one or more nested `describe` blocks
describe('a guest', () => { // to group scenarios
describe('their list', () => { // by context in which they apply

it('is empty', async () => { // - expected behaviour of the feature or component

})
})
})
})
})
Feature coverage

Using the same name for the outermost describe block in several different spec files makes Serenity BDD associate the different test scenarios with the same logical "feature" or "component" and produce feature coverage metrics.

Using Serenity/JS Screenplay Pattern APIs

Serenity/JS actor model works great with Mocha and Serenity/JS Screenplay Pattern APIs can help your team implement Mocha test scenarios that are easy to read and understand.

The fastest way to get started with Serenity/JS and Mocha is to use one of the Serenity/JS + Mocha project templates. However, if you're adding Serenity/JS to an existing project or simply want to understand how the integration works, this guide is for you.

Configuring a cast of actors

Serenity/JS Screenplay Pattern is an actor-centred model, so the first thing you need to do is to tell Serenity/JS what cast of actors you want to use.

If you're planning to run Mocha scenarios using the Mocha CLI directly, you can configure the actors in a beforeAll hook, for example:

spec/support/serenity.config.ts
import 'mocha'

import { configure, Cast } from '@serenity-js/core'
import { BrowseTheWebWithPlaywright } from '@serenity-js/playwright'

import * as playwright from 'playwright'

let browser: playwright.Browser;

beforeAll(async () => {

// Launch the browser once before all the tests
// Serenity/JS will take care of managing Playwright browser context and browser tabs.
browser = await playwright.chromium.launch({
headless: true,
});

// Configure Serenity/JS
configure({
actors: Cast.where(actor =>
actor.whoCan(BrowseTheWebWithPlaywright.using(browser, {
baseURL: 'https://todo-app.serenity-js.org/',
}))
),
crew: [
'@serenity-js/console-reporter',
'@serenity-js/serenity-bdd',
[ '@serenity-js/core:ArtifactArchiver', { outputDirectory: 'target/site/serenity' } ],
// ... any other reporting services
],
})
})

afterAll(async () => {
// Close the browser after all the tests are finished
await browser?.close()
})

Consult the respective test runner instructions if you're invoking Mocha indirectly, so via Protractor or WebdriverIO.

Referring to actors in test scenarios

Serenity/JS actors are often used to represent user personas or important external systems interacting with the system under test. In those scenarios, a common strategy is to give actors names indicating their persona, and refer to them in your test scenarios using functions actorCalled and actorInTheSpotlight:

spec/todo-list.spec.ts
import 'mocha'

import { Ensure, equals } from '@serenity-js/assertions'
import { actorCalled } from '@serenity-js/core'
import { Navigate, PageElements, By } from '@serenity-js/web'

describe('Todo List App', () => {

const displayedItems = () =>
PageElements.located(By.css('.todo-list li'))
.describedAs('displayed items')

describe('when the user is', () => {
describe('a guest', () => {
describe('their list', () => {

it('is empty', async () => {
await actorCalled('Alice').attemptsTo(
Navigate.to('https://todo-app.serenity-js.org/'),
Ensure.that(displayedItems().count(), equals(0))
)
})
})
})
})
})