Skip to content

Commit 49a3de5

Browse files
DavertMikclaude
andauthored
4.x docs update (#5519)
* DOC: rewrite retry.md — remove duplication, clarify healing section - Remove repeated "Common Patterns" and "Configuration Reference" sections - Move self-healing to step-level position (after retryTo, before scenario retries) - Explain AI healing flow as bullet list showing what happens at each stage - Link to /heal and /ai instead of duplicating their content Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * DOC: update locators.md — add ARIA/role locators, context param, and ID locator types Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * remvoed bad file * refactored documentation; improved locator docs --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 909c877 commit 49a3de5

File tree

8 files changed

+290
-634
lines changed

8 files changed

+290
-634
lines changed

docs/books.md

Lines changed: 0 additions & 37 deletions
This file was deleted.

docs/bootstrap.md

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

1313

14-
> ⚠ 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.
15-
1614
### Example: Bootstrap & Teardown
1715

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

2018
```js
21-
var server = require('./app_server');
19+
import server from './app_server.js';
2220

23-
exports.config = {
21+
export default {
2422
tests: "./*_test.js",
2523
helpers: {},
2624

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

6462

6563
```js
66-
const fs = require('fs');
64+
import fs from 'fs';
6765
const tempFolder = process.cwd() + '/tmpFolder';
6866

69-
exports.config = {
67+
export default {
7068
tests: "./*_test.js",
7169
helpers: {},
7270

@@ -95,13 +93,12 @@ exports.config = {
9593

9694
## Combining Bootstrap & BootstrapAll
9795

98-
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:
96+
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:
9997

10098
```js
10199
// inside codecept.conf.js
102100

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

106103
async function startServer() {
107104
// implement starting server logic here
@@ -111,20 +108,20 @@ async function stopServer() {
111108
}
112109

113110

114-
exports.config = {
111+
export default {
115112
// codeceptjs config goes here
116113

117114
async bootstrapAll() {
118115
await startServer();
119116
},
120117
async bootstrap() {
121118
// start a server only if we are not in worker
122-
if (isMainThread) return startServer();
119+
if (!store.workerMode) return startServer();
123120
}
124121

125122
async teardown() {
126-
// start a server only if we are not in worker
127-
if (isMainThread) return stopServer();
123+
// stop a server only if we are not in worker
124+
if (!store.workerMode) return stopServer();
128125
}
129126

130127
async teardownAll() {

docs/data.md

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,90 @@ API is supposed to be a stable interface and it can be used by acceptance tests.
2222

2323
## Data Objects
2424

25-
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.
25+
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.
26+
27+
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.
28+
29+
### Defining a Data Object
30+
31+
```js
32+
const { I } = inject();
33+
34+
class UserData {
35+
constructor() {
36+
this._created = [];
37+
}
38+
39+
async createUser(data = {}) {
40+
const response = await I.sendPostRequest('/api/users', {
41+
name: data.name || 'Test User',
42+
email: data.email || `test-${Date.now()}@example.com`,
43+
...data,
44+
});
45+
this._created.push(response.data.id);
46+
return response.data;
47+
}
48+
49+
async createPost(userId, data = {}) {
50+
const response = await I.sendPostRequest('/api/posts', {
51+
userId,
52+
title: data.title || 'Test Post',
53+
body: data.body || 'Test body',
54+
...data,
55+
});
56+
this._created.push({ type: 'post', id: response.data.id });
57+
return response.data;
58+
}
59+
60+
async _after() {
61+
for (const record of this._created.reverse()) {
62+
const id = typeof record === 'object' ? record.id : record;
63+
const type = typeof record === 'object' ? record.type : 'user';
64+
try {
65+
await I.sendDeleteRequest(`/api/${type}s/${id}`);
66+
} catch (e) {
67+
// cleanup errors should not fail the test
68+
}
69+
}
70+
this._created = [];
71+
}
72+
}
73+
74+
export default UserData
75+
```
76+
77+
### Configuration
78+
79+
Add the REST helper and the Data Object to your config:
80+
81+
```js
82+
helpers: {
83+
Playwright: { url: 'http://localhost', browser: 'chromium' },
84+
REST: {
85+
endpoint: 'http://localhost/api',
86+
defaultHeaders: { 'Content-Type': 'application/json' },
87+
},
88+
},
89+
include: {
90+
I: './steps_file.js',
91+
userData: './data/UserData.js',
92+
}
93+
```
94+
95+
### Usage in Tests
96+
97+
```js
98+
Scenario('user sees their profile', async ({ I, userData }) => {
99+
const user = await userData.createUser({ name: 'John Doe' });
100+
I.amOnPage(`/users/${user.id}`);
101+
I.see('John Doe');
102+
// userData._after() runs automatically — deletes the created user
103+
});
104+
```
105+
106+
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.
107+
108+
**Learn more:** See [Page Objects](/pageobjects) for general page object patterns.
26109

27110
## REST
28111

docs/element-based-testing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ Scenario('filter products by price', async ({ I }) => {
272272
## API Reference
273273

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

277277
## Portability
278278

0 commit comments

Comments
 (0)