codeceptjs 4.0.0-rc.20 → 4.0.0-rc.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/hooks.md CHANGED
@@ -3,337 +3,136 @@ permalink: /hooks
3
3
  title: Extending CodeceptJS
4
4
  ---
5
5
 
6
- # Extending
6
+ # Extending CodeceptJS
7
7
 
8
- CodeceptJS provides API to run custom code before and after the test and inject custom listeners into the event system.
8
+ CodeceptJS has four extension points. Pick the lightest one that does the job:
9
9
 
10
+ | Use | To |
11
+ | --- | --- |
12
+ | [`bootstrap` / `teardown`](/bootstrap) | run setup or teardown code once, around the whole suite |
13
+ | [Event listeners](#event-listeners) | react to test, suite, or step events without packaging anything |
14
+ | [Plugins](#plugins) | bundle reusable behavior — listeners, recorder hooks, config — into a module |
15
+ | [Custom helpers](/helpers) | add new `I.*` actions backed by a browser or an HTTP library |
10
16
 
11
- ## Plugins
12
-
13
- Plugins allow to use CodeceptJS internal API to extend functionality. Use internal event dispatcher, container, output, promise recorder, to create your own reporters, test listeners, etc.
17
+ Listeners and plugins use CodeceptJS internals — the `event` dispatcher, the `recorder` promise chain, the `container`, `output`. See [Architecture](/architecture) for what those are and how a test runs.
14
18
 
15
- CodeceptJS includes [built-in plugins](/plugins/) which extend basic functionality and can be turned on and off on purpose. Taking them as [examples](https://github.com/codeceptjs/CodeceptJS/tree/master/lib/plugin) you can develop your custom plugins.
19
+ ## Event Listeners
16
20
 
17
- A plugin is a basic JS module returning a function. Plugins can have individual configs which are passed into this function:
21
+ Attach a listener to `event.dispatcher` to run code at any point in the [test lifecycle](/architecture#events). A listener can live in a [plugin](#plugins) or in your [`bootstrap`](/bootstrap) script.
18
22
 
19
23
  ```js
20
- const defaultConfig = {
21
- someDefaultOption: true
22
- }
24
+ import { event } from 'codeceptjs'
23
25
 
24
- export default function(config) {
25
- config = Object.assign(defaultConfig, config);
26
- // do stuff
27
- }
26
+ event.dispatcher.on(event.test.before, test => {
27
+ console.log(`starting ${test.title}`)
28
+ })
28
29
  ```
29
30
 
30
- Plugin can register event listeners or hook into promise chain with recorder. See [API reference](https://github.com/codeceptjs/CodeceptJS/tree/master/lib/helper).
31
-
32
- To enable your custom plugin in config add it to `plugins` section. Specify path to node module using `require`.
31
+ [Sync events](/architecture#events) run inline. For async work, queue it on the recorder so it runs in order with the test's steps:
33
32
 
34
33
  ```js
35
- "plugins": {
36
- "myPlugin": {
37
- "require": "./path/to/my/module",
38
- "enabled": true
39
- }
40
- }
41
- ```
34
+ import { event, recorder } from 'codeceptjs'
42
35
 
43
- * `require` - specifies relative path to a plugin file. Path is relative to config file.
44
- * `enabled` - to enable this plugin.
45
-
46
- If a plugin is disabled (`enabled` is not set or false) this plugin can be enabled from command line:
47
-
48
- ```
49
- npx codeceptjs run --plugin myPlugin
36
+ event.dispatcher.on(event.test.before, () => {
37
+ recorder.add('seed fixture data', async () => {
38
+ await api.post('/users', { name: 'john', email: 'john@example.com' })
39
+ })
40
+ })
50
41
  ```
51
42
 
52
- Several plugins can be enabled as well:
53
-
54
- ```
55
- npx codeceptjs run --plugin myPlugin,allure
56
- ```
43
+ See [Architecture Events](/architecture#events) for the full event list and the test and step object fields.
57
44
 
58
- ### Example: Execute code for a specific group of tests
45
+ ## Plugins
59
46
 
60
- If you need to execute some code before a group of tests, you can [mark these tests with a same tag](/advanced/#tags). Then to listen for tests where this tag is included (see [test object api](#test-object)).
47
+ A plugin packages listeners, recorder hooks, container changes, and config into one module. CodeceptJS ships [built-in plugins](/plugins) [their source](https://github.com/codeceptjs/CodeceptJS/tree/master/lib/plugin) doubles as example code.
61
48
 
62
- Let's say we need to populate database for a group of tests.
49
+ A plugin is a module that exports a function. CodeceptJS calls it once at startup with the plugin's config:
63
50
 
64
51
  ```js
65
- // populate database for slow tests
66
- import { event } from 'codeceptjs';
67
-
68
- export default function() {
69
-
70
- event.dispatcher.on(event.test.before, function (test) {
52
+ import { event } from 'codeceptjs'
71
53
 
72
- if (test.tags.indexOf('@populate') >= 0) {
73
- recorder.add('populate database', async () => {
74
- // populate database for this test
75
- })
76
- }
77
- });
54
+ const defaultConfig = {
55
+ someOption: true,
78
56
  }
79
- ```
80
-
81
- ### Example: Check URL before running a test
82
-
83
- If you want to share bootstrap script or run multiple bootstraps, it's a good idea to wrap that script into a plugin.
84
- Plugin can also execute JS before tests but you need to use internal APIs to synchronize promises.
85
-
86
- ```js
87
- import { recorder } from 'codeceptjs';
88
57
 
89
- export default function(options) {
58
+ export default function (config) {
59
+ config = { ...defaultConfig, ...config }
90
60
 
91
- event.dispatcher.on(event.all.before, function () {
92
- recorder.startUnlessRunning(); // start recording promises
93
- recorder.add('do some async stuff', async () => {
94
- // your code
95
- });
96
- });
61
+ event.dispatcher.on(event.test.before, test => {
62
+ // use config, register listeners, hook into the recorder
63
+ })
97
64
  }
98
65
  ```
99
66
 
100
- ## API
67
+ ### Enabling a plugin
101
68
 
102
- **Use local CodeceptJS installation to get access to `codeceptjs` module**
103
-
104
- CodeceptJS provides an API which can be loaded via `import codeceptjs, { recorder, event, output } from 'codeceptjs'` when CodeceptJS is installed locally.
105
- These internal objects are available:
106
-
107
- * [`codecept`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/codecept.js): test runner class
108
- * [`config`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/config.js): current codecept config
109
- * [`event`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/event.js): event listener
110
- * [`recorder`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/recorder.js): global promise chain
111
- * [`output`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/output.js): internal printer
112
- * [`container`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/container.js): dependency injection container for tests, includes current helpers and support objects
113
- * [`helper`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/helper.js): basic helper class
114
- * [`actor`](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/actor.js): basic actor (I) class
115
-
116
- [API reference](https://github.com/codeceptjs/CodeceptJS/tree/master/docs/api) is available on GitHub.
117
- Also please check the source code of corresponding modules.
118
-
119
- ### Event Listeners
120
-
121
- CodeceptJS provides a module with [event dispatcher and set of predefined events](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/event.js).
122
-
123
- It can be required from codeceptjs package if it is installed locally.
69
+ Add it to the `plugins` section of the config and point `require` at the module:
124
70
 
125
71
  ```js
126
- import { event } from 'codeceptjs';
127
-
128
- export default function() {
129
-
130
- event.dispatcher.on(event.test.before, function (test) {
131
-
132
- console.log('--- I am before test --');
133
-
134
- });
72
+ plugins: {
73
+ myPlugin: {
74
+ require: './path/to/plugin', // relative to the config file
75
+ enabled: true,
76
+ }
135
77
  }
136
78
  ```
137
79
 
138
- Available events:
139
-
140
- * `event.test.before(test)` - *async* when `Before` hooks from helpers and from test is executed
141
- * `event.test.after(test)` - *async* after each test
142
- * `event.test.started(test)` - *sync* at the very beginning of a test. Passes a current test object.
143
- * `event.test.passed(test)` - *sync* when test passed
144
- * `event.test.failed(test, error)` - *sync* when test failed
145
- * `event.test.finished(test)` - *sync* when test finished
146
- * `event.suite.before(suite)` - *async* before a suite
147
- * `event.suite.after(suite)` - *async* after a suite
148
- * `event.step.before(step)` - *async* when the step is scheduled for execution
149
- * `event.step.after(step)` - *async* after a step
150
- * `event.step.started(step)` - *sync* when step starts.
151
- * `event.step.passed(step)` - *sync* when step passed.
152
- * `event.step.failed(step, err)` - *sync* when step failed.
153
- * `event.step.finished(step)` - *sync* when step finishes.
154
- * `event.step.comment(step)` - *sync* fired for comments like `I.say`.
155
- * `event.bddStep.before(bddStep)` - *async* when the gherkin step is scheduled for execution
156
- * `event.bddStep.after(bddStep)` - *async* after a gherkin step
157
- * `event.all.before` - before running tests
158
- * `event.all.after` - after running tests
159
- * `event.all.result` - when results are printed
160
-
161
- * *sync* - means that event is fired in the moment of action happens.
162
- * *async* - means that event is fired when an actions is scheduled. Use `recorder` to schedule your actions.
163
-
164
- For further reference look for [currently available listeners](https://github.com/codeceptjs/CodeceptJS/tree/master/lib/listener) using event system.
165
-
166
- #### Test Object
167
-
168
- Test events provide a test object with following fields:
169
-
170
- * `title` title of a test
171
- * `body` test function as a string
172
- * `opts` additional test options like retries, and others
173
- * `pending` true if test is scheduled for execution and false if a test has finished
174
- * `tags` array of tags for this test
175
- * `file` path to a file with a test.
176
- * `steps` array of executed steps (available only in `test.passed`, `test.failed`, `test.finished` event)
177
- * `skipInfo` additional test options when test skipped
178
- * * `message` string with reason for skip
179
- * * `description` string with test body
180
- and others
181
-
182
- #### Step Object
183
-
184
- Step events provide step objects with following fields:
185
-
186
- * `name` name of a step, like 'see', 'click', and others
187
- * `actor` current actor, in most cases it `I`
188
- * `helper` current helper instance used to execute this step
189
- * `helperMethod` corresponding helper method, in most cases is the same as `name`
190
- * `status` status of a step (passed or failed)
191
- * `prefix` if a step is executed inside `within` block contain within text, like: 'Within .js-signup-form'.
192
- * `args` passed arguments
193
-
194
- ### Recorder
195
-
196
- To inject asynchronous functions in a test or before/after a test you can subscribe to corresponding event and register a function inside a recorder object. [Recorder](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/recorder.js) represents a global promises chain.
197
-
198
- Provide a function description as a first parameter, function should return a promise:
80
+ - `require` — path to the plugin file, relative to the config file.
81
+ - `enabled` — set `true` to load it.
82
+ - any other key is passed straight to the plugin function as config.
199
83
 
200
- ```js
201
- import { event, recorder } from 'codeceptjs';
202
- import request from 'request';
203
-
204
- export default function() {
205
-
206
- event.dispatcher.on(event.test.before, function (test) {
207
-
208
- recorder.add('create fixture data via API', function() {
209
- return new Promise((doneFn, errFn) => {
210
- request({
211
- baseUrl: 'http://api.site.com/',
212
- method: 'POST',
213
- url: '/users',
214
- json: { name: 'john', email: 'john@john.com' }
215
- }), (err, httpResponse, body) => {
216
- if (err) return errFn(err);
217
- doneFn();
218
- }
219
- });
220
- }
221
- });
222
- }
84
+ A disabled or unlisted plugin can be turned on for a single run from the command line:
223
85
 
224
86
  ```
225
-
226
- Whenever you execute tests with `--verbose` option you will see registered events and promises executed by a recorder.
227
-
228
-
229
- ### Output
230
-
231
- Output module provides 4 verbosity levels. Depending on the mode you can have different information printed using corresponding functions.
232
-
233
- * `default`: prints basic information using `output.print`
234
- * `steps`: toggled by `--steps` option, prints step execution
235
- * `debug`: toggled by `--debug` option, prints steps, and debug information with `output.debug`
236
- * `verbose`: toggled by `--verbose` prints debug information and internal logs with `output.log`
237
-
238
- It is recommended to avoid `console.log` and use output.* methods for printing.
239
-
240
- ```js
241
- import { output } from 'codeceptjs';
242
-
243
- output.print('This is basic information');
244
- output.debug('This is debug information');
245
- output.log('This is verbose logging information');
87
+ npx codeceptjs run --plugin myPlugin
88
+ npx codeceptjs run --plugin myPlugin,allure
246
89
  ```
247
90
 
248
- ### Container
249
-
250
- CodeceptJS has a dependency injection container with Helpers and Support objects.
251
- They can be retrieved from the container:
252
-
253
- ```js
254
- import { container } from 'codeceptjs';
255
-
256
- // get object with all helpers
257
- let helpers = container.helpers();
258
-
259
- // get helper by name
260
- let WebDriver = container.helpers('WebDriver');
261
-
262
- // get support objects
263
- let support = container.support();
91
+ ### Example: run code for a tagged group of tests
264
92
 
265
- // get support object by name
266
- let UserPage = container.support('UserPage');
267
-
268
- // get all registered plugins
269
- let plugins = container.plugins();
270
- ```
271
-
272
- New objects can also be added to container in runtime:
93
+ [Tag](/test-structure#tags) the tests you want to target, then check the tag on `event.test.before`:
273
94
 
274
95
  ```js
275
- import { container } from 'codeceptjs';
276
- import UserPage from './pages/user.js';
277
-
278
- container.append({
279
- helpers: { // add helper
280
- MyHelper: new MyHelper({ config1: 'val1' });
281
- },
282
- support: { // add page object
283
- UserPage,
284
- }
285
- })
286
- ```
96
+ import { event, recorder } from 'codeceptjs'
287
97
 
288
- Container also contains current Mocha instance:
98
+ export default function () {
99
+ event.dispatcher.on(event.test.before, test => {
100
+ if (!test.tags.includes('@populate')) return
289
101
 
290
- ```js
291
- let mocha = container.mocha();
102
+ recorder.add('populate database', async () => {
103
+ // seed data for this test
104
+ })
105
+ })
106
+ }
292
107
  ```
293
108
 
294
- ### Config
109
+ ### Example: run async setup before all tests
295
110
 
296
- CodeceptJS config can be accessed from `import { config } from 'codeceptjs'` then `config.get()`:
111
+ `event.all.before` can fire before the recorder chain is running, so start it first:
297
112
 
298
113
  ```js
299
- import { config } from 'codeceptjs';
300
-
301
- if (config.get().myKey == 'value') {
302
- // run hook
114
+ import { event, recorder } from 'codeceptjs'
115
+
116
+ export default function () {
117
+ event.dispatcher.on(event.all.before, () => {
118
+ recorder.startUnlessRunning()
119
+ recorder.add('warm up cache', async () => {
120
+ // your async setup
121
+ })
122
+ })
303
123
  }
304
124
  ```
305
125
 
126
+ Wrapping bootstrap logic in a plugin like this lets you share it across projects and combine several setup scripts.
306
127
 
307
- ## Custom Runner
128
+ ## Custom Helpers
308
129
 
309
- > 📺 [Watch this](https://www.youtube.com/watch?v=3eZtVL0Ad0A) material on YouTube
130
+ To add new `I.*` actions — a higher-level step, a wrapper around a browser SDK, an assertion against your backend — write a helper class. Helpers can also be published as npm packages. See [Custom Helpers](/helpers).
310
131
 
311
- CodeceptJS can be imported and used in custom runners.
312
- To initialize Codecept you need to create Config and Container objects.
132
+ ## Bootstrap & Teardown
313
133
 
314
- ```js
315
- import { codecept as Codecept } from 'codeceptjs';
316
-
317
- const config = { helpers: { WebDriver: { browser: 'chrome', url: 'http://localhost' } } };
318
- const opts = { steps: true };
319
-
320
- const codecept = new Codecept(config, options);
321
- codecept.init(testRoot);
322
-
323
- // run tests
324
- try {
325
- await codecept.bootstrap();
326
- codecept.loadTests('*_test.js');
327
- await codecept.run(test);
328
- } catch (err) {
329
- printError(err);
330
- process.exitCode = 1;
331
- } finally {
332
- await codecept.teardown();
333
- }
134
+ For setup and teardown that needs no packaging — start a server, create a database — use the `bootstrap` and `teardown` config hooks. In [parallel runs](/parallel), `bootstrapAll` / `teardownAll` run once in the parent process. See [Bootstrap & Teardown](/bootstrap).
334
135
 
136
+ ---
335
137
 
336
- ```
337
-
338
- In this way Codecept runner class can be extended.
339
-
138
+ **See also:** [Architecture](/architecture) · [Plugins reference](/plugins) · [Custom Helpers](/helpers) · [Bootstrap & Teardown](/bootstrap)
@@ -5,79 +5,134 @@ title: Installation
5
5
 
6
6
  # Installation
7
7
 
8
- ## QuickStart Via Installer
8
+ For the quickest start (CodeceptJS + Playwright) follow the [Quickstart](/quickstart). This page covers every browser, mobile, and API helper and what each one needs installed.
9
9
 
10
- Creating a new project via [`create-codeceptjs` installer](https://github.com/codeceptjs/create-codeceptjs) is the simplest way to start
10
+ ## Set up a project
11
11
 
12
- Install CodeceptJS + Playwright into current directory
13
-
14
- ```
15
- npx create-codeceptjs .
12
+ ```sh
13
+ npm init -y # if you don't have a package.json yet
14
+ npm i codeceptjs --save-dev
16
15
  ```
17
16
 
18
- Install CodeceptJS + Puppeteer into current directory
17
+ Install one of the helpers below, then scaffold the config and a sample test:
19
18
 
20
- ```
21
- npx create-codeceptjs . --puppeteer
19
+ ```sh
20
+ npx codeceptjs init
22
21
  ```
23
22
 
24
- Install CodeceptJS + webdriverio into current directory
23
+ `init` runs a short wizard, writes `codecept.conf.js` and a sample test, and installs the helper's driver package if it's missing. The [Quickstart](/quickstart) walks through the questions.
25
24
 
26
- ```
27
- npx create-codeceptjs . --webdriverio
28
- ```
25
+ ## Playwright
29
26
 
30
- Install CodeceptJS + webdriverio into `e2e-tests` directory:
27
+ Fast, modern browser automation the recommended helper for web testing.
31
28
 
32
- ```
33
- npx create-codeceptjs e2e-tests --webdriverio
29
+ ```sh
30
+ npm i playwright --save-dev
31
+ npx playwright install --with-deps
34
32
  ```
35
33
 
36
- If you plan to use CodeceptJS for **API testing** only proceed to standard installation
34
+ `playwright install` downloads the browser binaries; `--with-deps` also installs the Linux system libraries they need (run it with `sudo` if your user can't install packages).
37
35
 
38
- ## Standard Installation
36
+ Set `browser` in the helper config to one of:
39
37
 
40
- Open a directory where you want to install CodeceptJS tests.
41
- If it is an empty directory - create a new NPM package with
38
+ - `chromium` default
39
+ - `firefox`
40
+ - `webkit` — the open-source Safari engine
41
+ - `electron` — test an Electron app (set `electron.executablePath`)
42
42
 
43
- ```
44
- npm init -y
43
+ To drive branded Chrome or Edge instead of bundled Chromium, install that channel — `npx playwright install chrome` (or `msedge`) — and set `channel` in the config. See the [Playwright helper](/playwright).
44
+
45
+ ## Puppeteer
46
+
47
+ Chrome/Chromium automation over the DevTools protocol.
48
+
49
+ ```sh
50
+ npm i puppeteer --save-dev
45
51
  ```
46
52
 
47
- Install CodeceptJS with NPM:
53
+ Puppeteer downloads a matching Chromium when it installs — nothing else to set up. To drive an existing Chrome instead, set `chrome.executablePath` in the helper config (or install `puppeteer-core` and point it at your browser). See the [Puppeteer helper](/puppeteer).
54
+
55
+ ## WebDriver
56
+
57
+ W3C WebDriver — runs Chrome, Firefox, Edge, Safari, and remote or cloud grids.
48
58
 
49
59
  ```sh
50
- npx codeceptjs init
60
+ npm i webdriverio --save-dev
51
61
  ```
52
62
 
53
- After choosing default helper (Playwright, Puppeteer, WebDriver, etc) a corresponding package should be installed automatically.
63
+ WebDriver talks to a Selenium server (or a cloud grid). Pick one:
54
64
 
55
- > If you face issues installing additional packages while running `npx codeceptjs init` command, install required packages manually using npm
65
+ - **[`selenium-standalone`](https://www.npmjs.com/package/selenium-standalone)** one npm package that installs and runs Selenium with ChromeDriver and GeckoDriver:
56
66
 
57
- Unless you are using WebDriver - CodeceptJS is ready to go!
58
- For WebDriver installation Selenium Server is required 👇
67
+ ```sh
68
+ npm i selenium-standalone --save-dev
69
+ npx selenium-standalone install
70
+ npx selenium-standalone start
71
+ ```
59
72
 
60
- ## ESM Support
73
+ - **[Docker](https://github.com/SeleniumHQ/docker-selenium)** — a headless Selenium + browser container:
61
74
 
62
- CodeceptJS v4.x supports ECMAScript Modules (ESM) format. To use ESM:
75
+ ```sh
76
+ docker run --net=host --shm-size=2g selenium/standalone-chrome
77
+ # or selenium/standalone-firefox
78
+ ```
63
79
 
64
- 1. Add `"type": "module"` to your `package.json`
65
- 2. Update import syntax in configuration files to use ESM format
80
+ - **A cloud grid** — Sauce Labs, BrowserStack, LambdaTest, and so on. Set the grid's `host`, `port`, `user`, and `key` (or `protocol` / `path`) in the helper config.
66
81
 
67
- For detailed migration instructions and important behavioral changes, see the **[3.x 4.x Migration Guide](migration-4.md)**.
82
+ Set `browser` (`chrome`, `firefox`, `MicrosoftEdge`, `safari`) and the server `host` / `port` in `codecept.conf.js` — see the [WebDriver helper](/webdriver). For running this on CI, see [Continuous Integration](/continuous-integration).
68
83
 
69
- ## WebDriver
84
+ ## Appium (mobile)
85
+
86
+ Native iOS and Android testing. Appium speaks the WebDriver protocol, so CodeceptJS drives it through `webdriverio`:
87
+
88
+ ```sh
89
+ npm i webdriverio --save-dev
90
+ npm i -g appium
91
+ ```
70
92
 
71
- WebDriver based helpers like WebDriver will require [Selenium Server](https://codecept.io/helpers/WebDriver/#selenium-installation) installed. They will also require ChromeDriver or GeckoDriver to run corresponding browsers.
93
+ Install the platform driver(s) and start the server:
72
94
 
73
- We recommend to install them manually or use NPM packages:
95
+ ```sh
96
+ appium driver install uiautomator2 # Android
97
+ appium driver install xcuitest # iOS
98
+ appium
99
+ ```
74
100
 
75
- [Selenium Standalone](https://www.npmjs.com/package/selenium-standalone) to install and run Selenium, ChromeDriver, Firefox Driver with one package.
101
+ You'll also need the Android SDK and an emulator or device, or Xcode and a simulator or device (or a device-cloud account). Set `platformName`, `deviceName`, and `app` in the helper config see [Mobile Testing](/mobile).
76
102
 
77
- Alternatively, you can execute headless Selenium in [Docker](https://github.com/SeleniumHQ/docker-selenium) for headless browser testing.
103
+ ## API testing
78
104
 
79
- Launch Selenium with Chrome browser inside a Docker container:
105
+ REST and GraphQL tests need no browser the helpers are built in (they use `axios`, already a dependency):
80
106
 
81
107
  ```sh
82
- docker run --net=host selenium/standalone-chrome
108
+ npm i codeceptjs --save-dev
83
109
  ```
110
+
111
+ Choose `REST` or `GraphQL` when `init` asks, set `endpoint` in the config, and add the `JSONResponse` helper if you want response assertions. See [Testing APIs](/api).
112
+
113
+ ## ESM
114
+
115
+ CodeceptJS 4.x uses ECMAScript Modules. A project created by `init` is set up for it; an existing project needs `"type": "module"` in `package.json` and `import` syntax in the config and tests. Coming from 3.x — see the [Migration Guide](/migration-4).
116
+
117
+ ## TypeScript
118
+
119
+ `npx codeceptjs init` scaffolds a TypeScript project when you answer **Yes** to "Do you plan to write tests in TypeScript?" — it writes `codecept.conf.ts` and `*_test.ts` files.
120
+
121
+ The config file (`codecept.conf.ts`) and helpers are transpiled automatically. Test files need a loader; install [`tsx`](https://tsx.is) and add it to `require`:
122
+
123
+ ```sh
124
+ npm i tsx --save-dev
125
+ ```
126
+
127
+ ```ts
128
+ // codecept.conf.ts
129
+ export const config = {
130
+ tests: './**/*_test.ts',
131
+ require: ['tsx/cjs'], // loads the *_test.ts files
132
+ helpers: {
133
+ Playwright: { url: 'http://localhost', browser: 'chromium' },
134
+ },
135
+ }
136
+ ```
137
+
138
+ Run tests as usual with `npx codeceptjs run`. For promise-based typings, types for page objects and custom helpers, and custom locator types, see the [TypeScript guide](/typescript).