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
37 changes: 0 additions & 37 deletions docs/books.md

This file was deleted.

23 changes: 10 additions & 13 deletions docs/bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,14 @@ you can use the `bootstrap` and `teardown` config. Use it to start and stop a we
When using the [parallel execution](/parallel) mode, there are two additional hooks available; `bootstrapAll` and `teardownAll`. See [bootstrapAll & teardownAll](#bootstrapall-teardownall) for more information.


> ⚠ In CodeceptJS 2 bootstrap could be set as a function with `done` parameter. This way of handling async function was replaced with native async functions in CodeceptJS 3.

### Example: Bootstrap & Teardown

If you are using JavaScript-style config `codecept.conf.js`, bootstrap and teardown functions can be placed inside of it:

```js
var server = require('./app_server');
import server from './app_server.js';

exports.config = {
export default {
tests: "./*_test.js",
helpers: {},

Expand Down Expand Up @@ -63,10 +61,10 @@ Using JavaScript-style config `codecept.conf.js`, bootstrapAll and teardownAll f


```js
const fs = require('fs');
import fs from 'fs';
const tempFolder = process.cwd() + '/tmpFolder';

exports.config = {
export default {
tests: "./*_test.js",
helpers: {},

Expand Down Expand Up @@ -95,13 +93,12 @@ exports.config = {

## Combining Bootstrap & BootstrapAll

It is quite common that you expect that bootstrapAll and bootstrap will do the same thing. If an application server is already started in `bootstrapAll` we should not run it again inside `bootstrap` for each worker. To avoid code duplication we can run bootstrap script only when we are not inside a worker. And we will use NodeJS `isMainThread` Workers API to detect that:
It is quite common that you expect that bootstrapAll and bootstrap will do the same thing. If an application server is already started in `bootstrapAll` we should not run it again inside `bootstrap` for each worker. To avoid code duplication we can run bootstrap script only when we are not inside a worker. CodeceptJS provides `store.workerMode` to detect if code is running in a worker process:

```js
// inside codecept.conf.js

// detect if we are in a worker thread
const { isMainThread } = require('worker_threads');
import store from 'codeceptjs/lib/store.js';

async function startServer() {
// implement starting server logic here
Expand All @@ -111,20 +108,20 @@ async function stopServer() {
}


exports.config = {
export default {
// codeceptjs config goes here

async bootstrapAll() {
await startServer();
},
async bootstrap() {
// start a server only if we are not in worker
if (isMainThread) return startServer();
if (!store.workerMode) return startServer();
}

async teardown() {
// start a server only if we are not in worker
if (isMainThread) return stopServer();
// stop a server only if we are not in worker
if (!store.workerMode) return stopServer();
}

async teardownAll() {
Expand Down
85 changes: 84 additions & 1 deletion docs/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,90 @@ API is supposed to be a stable interface and it can be used by acceptance tests.

## Data Objects

For a lightweight, class-based approach to managing test data, see **[Data Objects](/pageobjects#data-objects)** in the Page Objects documentation. Data Objects let you create page object classes that manage API data with automatic cleanup via the `_after()` hook — no factory configuration needed.
Data Objects are page object classes designed to manage test data via API. They use the REST helper (through `I`) to create data in a test and clean it up automatically via the `_after()` hook.

This is a lightweight alternative to [ApiDataFactory](#api-data-factory) — ideal when you want full control over data creation and cleanup logic without factory configuration.

### Defining a Data Object

```js
const { I } = inject();

class UserData {
constructor() {
this._created = [];
}

async createUser(data = {}) {
const response = await I.sendPostRequest('/api/users', {
name: data.name || 'Test User',
email: data.email || `test-${Date.now()}@example.com`,
...data,
});
this._created.push(response.data.id);
return response.data;
}

async createPost(userId, data = {}) {
const response = await I.sendPostRequest('/api/posts', {
userId,
title: data.title || 'Test Post',
body: data.body || 'Test body',
...data,
});
this._created.push({ type: 'post', id: response.data.id });
return response.data;
}

async _after() {
for (const record of this._created.reverse()) {
const id = typeof record === 'object' ? record.id : record;
const type = typeof record === 'object' ? record.type : 'user';
try {
await I.sendDeleteRequest(`/api/${type}s/${id}`);
} catch (e) {
// cleanup errors should not fail the test
}
}
this._created = [];
}
}

export default UserData
```

### Configuration

Add the REST helper and the Data Object to your config:

```js
helpers: {
Playwright: { url: 'http://localhost', browser: 'chromium' },
REST: {
endpoint: 'http://localhost/api',
defaultHeaders: { 'Content-Type': 'application/json' },
},
},
include: {
I: './steps_file.js',
userData: './data/UserData.js',
}
```

### Usage in Tests

```js
Scenario('user sees their profile', async ({ I, userData }) => {
const user = await userData.createUser({ name: 'John Doe' });
I.amOnPage(`/users/${user.id}`);
I.see('John Doe');
// userData._after() runs automatically — deletes the created user
});
```

Data Objects can use any helper methods available via `I`, including `sendGetRequest`, `sendPutRequest`, and browser actions. They combine the convenience of managed test data with the flexibility of page objects.

**Learn more:** See [Page Objects](/pageobjects) for general page object patterns.

## REST

Expand Down
2 changes: 1 addition & 1 deletion docs/element-based-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ Scenario('filter products by price', async ({ I }) => {
## API Reference

- **[Element Access](els.md)** - Complete reference for `element()`, `eachElement()`, `expectElement()`, `expectAnyElement()`, `expectAllElements()` functions
- **[WebElement API](WebElement.md)** - Complete reference for WebElement class methods (`getText()`, `getAttribute()`, `click()`, `$$()`, etc.)
- **[WebElement API](web-element.md)** - Complete reference for WebElement class methods (`getText()`, `getAttribute()`, `click()`, `$$()`, etc.)

## Portability

Expand Down
Loading