Skip to content

Commit ee69b18

Browse files
author
DavertMik
committed
updated docs
1 parent 8d4478c commit ee69b18

9 files changed

Lines changed: 556 additions & 6001 deletions

File tree

CHANGELOG.md

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

docs/advanced.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ Feature('My feature', {key: val});
134134
Scenario('My scenario', {key: val},({ I }) => {});
135135
```
136136
137-
You can use this options for build your own [plugins](https://codecept.io/hooks/#plugins) with [event listners](https://codecept.io/hooks/#api). Example:
137+
You can use these options to build your own [plugins](https://codecept.io/hooks#plugins) with [event listeners](https://codecept.io/architecture#events). Example:
138138
139139
```js
140140
// for test

docs/architecture.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
---
2+
permalink: /architecture
3+
title: Architecture
4+
---
5+
6+
# CodeceptJS Architecture
7+
8+
How CodeceptJS runs a test, and the internal modules you build [plugins, listeners, and helpers](/hooks) against.
9+
10+
## How a Test Runs
11+
12+
CodeceptJS is built on top of [Mocha](https://mochajs.org). A run goes through these stages:
13+
14+
1. **Load.** CodeceptJS reads the config, builds the [container](#container) (helpers, support objects, plugins), and runs the `bootstrap` hook. `event.all.before` fires.
15+
2. **Suite.** For each suite, `event.suite.before` fires. Helper `_beforeSuite` hooks run.
16+
3. **Test.** For each test: `event.test.started` fires; `Before` hooks from helpers (`_before`) and from the suite run, then `event.test.before` fires; the scenario function runs; `event.test.passed` or `event.test.failed` fires; `After` hooks run; `event.test.after` and then `event.test.finished` fire.
17+
4. **Step.** Each `I.*` call inside a scenario becomes a step. It is *scheduled* onto the [recorder](#the-recorder)`event.step.before` fires — then executed: `event.step.started`, `event.step.passed` or `event.step.failed`, `event.step.after`, `event.step.finished`.
18+
5. **Finish.** `event.suite.after` fires after each suite, `event.all.after` after the last one, and `event.all.result` when results are printed. The `teardown` hook runs.
19+
20+
The key idea is step 4: **a scenario doesn't execute its steps as it runs** — it queues them. `I.click()` returns immediately; the [recorder](#the-recorder) runs the queued action later. This is why scenarios rarely need `await`, and why anything that injects async work has to go through the recorder.
21+
22+
## The Internal API
23+
24+
CodeceptJS exposes its internals as named exports of the `codeceptjs` package. Import only what you need:
25+
26+
```js
27+
import { recorder, event, output, container, config } from 'codeceptjs'
28+
```
29+
30+
| Export | What it is |
31+
| --- | --- |
32+
| [`codecept`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/codecept.js) | the test runner class |
33+
| [`config`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/config.js) | the loaded configuration |
34+
| [`container`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/container.js) | dependency-injection container: helpers, support objects, plugins, the Mocha instance |
35+
| [`recorder`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/recorder.js) | the global promise chain that orders every step |
36+
| [`event`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/event.js) | the event dispatcher and the names of all lifecycle events |
37+
| [`output`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/output.js) | the printer used for all console output |
38+
| [`helper`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/helper.js) | the base class every helper extends |
39+
| [`actor`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/actor.js) | the base class behind the `I` object |
40+
41+
> Older code relied on a global `codeceptjs` object (`const { recorder } = codeceptjs`). That global only exists under `noGlobals: false`, the deprecated 3.x default — prefer named imports.
42+
43+
The [API reference](https://github.com/codeceptjs/CodeceptJS/tree/master/docs/api) on GitHub documents these modules; the source is the final word.
44+
45+
## The Recorder
46+
47+
The recorder is a single global promise chain. Every step a scenario "calls" is appended to it, and the chain runs the steps one after another. To run your own async code at the right point in a test, append it to the recorder too:
48+
49+
```js
50+
import { event, recorder } from 'codeceptjs'
51+
52+
event.dispatcher.on(event.test.before, () => {
53+
recorder.add('seed fixture data', async () => {
54+
await api.post('/users', { name: 'john', email: 'john@example.com' })
55+
})
56+
})
57+
```
58+
59+
- `recorder.add(name, fn)` — append `fn` (async, or returning a promise) to the chain. The name shows up in `--verbose` output.
60+
- `recorder.startUnlessRunning()` — start a chain if none is running. Call it before `add()` from a listener that may fire outside a running chain, such as `event.all.before`.
61+
- `recorder.retry({ retries, when })` — retry failing steps that match `when`. See [conditional retries](/helpers#conditional-retries).
62+
63+
Run tests with `--verbose` to watch the recorder schedule and execute each entry.
64+
65+
## Container
66+
67+
The container resolves helpers and support objects by name:
68+
69+
```js
70+
import { container } from 'codeceptjs'
71+
72+
const helpers = container.helpers() // every helper, keyed by name
73+
const { Playwright } = container.helpers() // one helper
74+
const support = container.support() // every support object
75+
const { UserPage } = container.support() // one page object
76+
const plugins = container.plugins() // enabled plugins
77+
const mocha = container.mocha() // the current Mocha instance
78+
```
79+
80+
Add objects at runtime — useful from a `bootstrap` script:
81+
82+
```js
83+
import { container } from 'codeceptjs'
84+
import UserPage from './pages/user.js'
85+
86+
container.append({
87+
helpers: { MyHelper: new MyHelper({ host: 'http://example.com' }) },
88+
support: { UserPage },
89+
})
90+
```
91+
92+
## Events
93+
94+
`event.dispatcher` is a Node `EventEmitter`. Attach listeners to it from a [plugin](/hooks#plugins) or `bootstrap` script.
95+
96+
Events are **sync** or **async**:
97+
98+
- **sync** — fires the moment the action happens. Do synchronous work only.
99+
- **async** — fires when the action is *scheduled*. To do async work in the right order, queue it with `recorder.add()`.
100+
101+
| Event | Kind | When |
102+
| --- | --- | --- |
103+
| `event.all.before` || before any test runs |
104+
| `event.suite.before(suite)` | async | before a suite |
105+
| `event.test.started(test)` | sync | at the very start of a test |
106+
| `event.test.before(test)` | async | after `Before` hooks from helpers and the test are run |
107+
| `event.test.passed(test)` | sync | test passed |
108+
| `event.test.failed(test, err)` | sync | test failed |
109+
| `event.test.skipped(test)` | sync | test skipped |
110+
| `event.test.after(test)` | async | after each test |
111+
| `event.test.finished(test)` | sync | test finished |
112+
| `event.suite.after(suite)` | async | after a suite |
113+
| `event.step.before(step)` | async | step scheduled for execution |
114+
| `event.step.started(step)` | sync | step starts executing |
115+
| `event.step.passed(step)` | sync | step passed |
116+
| `event.step.failed(step, err)` | sync | step failed |
117+
| `event.step.after(step)` | async | after a step |
118+
| `event.step.finished(step)` | sync | step finished |
119+
| `event.step.comment(step)` | sync | a comment such as `I.say(...)` |
120+
| `event.bddStep.before(step)` / `event.bddStep.after(step)` | async | around a Gherkin step |
121+
| `event.hook.started(hook)` / `event.hook.passed` / `event.hook.failed` / `event.hook.finished` | sync | around `Before` / `After` / `BeforeSuite` / `AfterSuite` hooks |
122+
| `event.all.after` || after all tests |
123+
| `event.all.result(result)` || when results are printed |
124+
| `event.all.failures(failures)` || when a run reports failures |
125+
| `event.workers.before` / `event.workers.after` / `event.workers.result(result)` || around a [parallel run](/parallel) (parent process only) |
126+
127+
The [built-in listeners](https://github.com/codeceptjs/CodeceptJS/tree/master/lib/listener) are working examples — every reporter and several plugins are listeners.
128+
129+
### Test object
130+
131+
Test events pass a test object with these fields:
132+
133+
- `title` — the test title
134+
- `body` — the test function as a string
135+
- `opts` — test options such as `retries` (see [test options](/advanced#test-options))
136+
- `pending``true` while scheduled, `false` once finished
137+
- `tags` — array of [tags](/test-structure#tags) for this test
138+
- `artifacts` — files attached to this test (screenshots, videos, …), shared across reporters
139+
- `file` — path to the test file
140+
- `steps` — executed steps (only on `test.passed`, `test.failed`, `test.finished`)
141+
- `skipInfo` — present when the test was skipped: `{ message, description }`
142+
143+
### Step object
144+
145+
Step events pass a step object with these fields:
146+
147+
- `name` — the step name, such as `see` or `click`
148+
- `actor` — the current actor, usually `I`
149+
- `helper` — the helper instance that executes this step
150+
- `helperMethod` — the helper method, usually the same as `name`
151+
- `status``passed` or `failed`
152+
- `prefix` — for a step inside a `within` block, the within text (e.g. `Within .js-signup-form`)
153+
- `args` — the arguments passed to the step
154+
155+
## Config
156+
157+
```js
158+
import { config } from 'codeceptjs'
159+
160+
config.get() // the full config object
161+
config.get('myKey') // one value
162+
config.get('myKey', 'fallback') // one value, with a default
163+
```
164+
165+
## Output
166+
167+
Output has four verbosity levels, each toggled by a CLI flag:
168+
169+
| Level | Flag | Use |
170+
| --- | --- | --- |
171+
| default || `output.print` — basic information |
172+
| steps | `--steps` | step execution |
173+
| debug | `--debug` | steps plus `output.debug` |
174+
| verbose | `--verbose` | debug plus `output.log` (internal logs and recorder activity) |
175+
176+
```js
177+
import { output } from 'codeceptjs'
178+
179+
output.print('basic information')
180+
output.debug('debug information')
181+
output.log('verbose logging information')
182+
```
183+
184+
Use these instead of `console.log` so messages respect the chosen verbosity.
185+
186+
## Helpers and the Actor
187+
188+
The `I` object is an **actor** assembled from the enabled helpers. Each `I.method()` call delegates to the matching helper method and is wrapped as a step. Methods whose names start with `_` are private to the helper and not exposed on `I`. To add your own actions, write a [custom helper](/helpers).
189+
190+
## Running CodeceptJS from Code
191+
192+
CodeceptJS can be driven from your own script. Create the runner with a config and options, initialize it, then bootstrap, load tests, and run:
193+
194+
```js
195+
import { codecept as Codecept } from 'codeceptjs'
196+
197+
const config = { helpers: { Playwright: { browser: 'chromium', url: 'http://localhost' } } }
198+
const opts = { steps: true }
199+
200+
const codecept = new Codecept(config, opts)
201+
codecept.init(import.meta.dirname) // the test root directory
202+
203+
try {
204+
await codecept.bootstrap()
205+
codecept.loadTests('**/*_test.js')
206+
await codecept.run() // pass a test file path to run only that file
207+
} catch (err) {
208+
console.error(err)
209+
process.exitCode = 1
210+
} finally {
211+
await codecept.teardown()
212+
}
213+
```
214+
215+
> To run tests inside workers from a script, see [parallel execution](/parallel).
216+
217+
---
218+
219+
**See also:** [Extending CodeceptJS](/hooks) · [Custom Helpers](/helpers) · [Plugins](/plugins) · [Bootstrap & Teardown](/bootstrap)

0 commit comments

Comments
 (0)