codeceptjs 4.0.0-rc.23 → 4.0.0-rc.24
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/README.md +9 -10
- package/docs/ai.md +3 -51
- package/docs/architecture.md +16 -0
- package/docs/bootstrap.md +1 -1
- package/docs/continuous-integration.md +16 -44
- package/docs/custom-helpers.md +1 -1
- package/docs/detox.md +1 -1
- package/docs/docker.md +1 -30
- package/docs/examples.md +0 -1
- package/docs/helpers/Appium.md +16 -2
- package/docs/helpers/Playwright.md +161 -160
- package/docs/helpers/Puppeteer.md +143 -250
- package/docs/helpers/WebDriver.md +134 -177
- package/docs/hooks.md +11 -1
- package/docs/index.md +1 -1
- package/docs/installation.md +2 -19
- package/docs/locators.md +1 -1
- package/docs/migrate-from-cypress.md +98 -0
- package/docs/migrate-from-java.md +108 -0
- package/docs/migrate-from-protractor.md +101 -0
- package/docs/migrate-from-testcafe.md +99 -0
- package/docs/migration-4.md +195 -8
- package/docs/plugins/aiTrace.md +49 -0
- package/docs/plugins/analyze.md +66 -0
- package/docs/plugins/auth.md +241 -0
- package/docs/plugins/autoDelay.md +48 -0
- package/docs/plugins/browser.md +41 -0
- package/docs/plugins/coverage.md +39 -0
- package/docs/plugins/customLocator.md +119 -0
- package/docs/plugins/customReporter.md +16 -0
- package/docs/plugins/expose.md +75 -0
- package/docs/plugins/heal.md +44 -0
- package/docs/plugins/junitReporter.md +51 -0
- package/docs/plugins/pageInfo.md +34 -0
- package/docs/plugins/pause.md +43 -0
- package/docs/plugins/pauseOnFail.md +18 -0
- package/docs/plugins/retryFailedStep.md +75 -0
- package/docs/plugins/screencast.md +55 -0
- package/docs/plugins/screenshot.md +58 -0
- package/docs/plugins/screenshotOnFail.md +18 -0
- package/docs/plugins/stepTimeout.md +65 -0
- package/docs/plugins.md +40 -862
- package/docs/reports.md +18 -4
- package/docs/retry.md +48 -18
- package/docs/store.md +94 -0
- package/docs/timeouts.md +1 -1
- package/docs/tutorial.md +207 -155
- package/docs/webdriver.md +6 -73
- package/lib/actor.js +0 -35
- package/lib/command/run-multiple.js +1 -2
- package/lib/helper/Playwright.js +1 -15
- package/lib/helper/Puppeteer.js +0 -103
- package/lib/helper/WebDriver.js +1 -28
- package/lib/helper/extras/PlaywrightLocator.js +10 -0
- package/lib/locator.js +0 -13
- package/lib/plugin/analyze.js +3 -4
- package/lib/plugin/pauseOnFail.js +3 -1
- package/lib/plugin/retryFailedStep.js +7 -7
- package/lib/plugin/screenshot.js +0 -5
- package/lib/plugin/screenshotOnFail.js +3 -1
- package/lib/plugin/stepTimeout.js +1 -1
- package/lib/recorder.js +1 -1
- package/lib/workers.js +0 -4
- package/package.json +3 -4
- package/docs/helpers/Mochawesome.md +0 -8
- package/docs/helpers/MockServer.md +0 -212
- package/docs/helpers/Polly.md +0 -44
- package/docs/helpers/Protractor.md +0 -1769
- package/docs/helpers/SoftExpectHelper.md +0 -352
- package/docs/react.md +0 -70
- package/lib/helper/Mochawesome.js +0 -96
- package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -61
- package/lib/helper/extras/React.js +0 -65
package/docs/hooks.md
CHANGED
|
@@ -40,7 +40,17 @@ event.dispatcher.on(event.test.before, () => {
|
|
|
40
40
|
})
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
A listener often needs to know *where* in the run it is — which test is active, or whether this is a dry run. Read that from [`store`](/store) instead of tracking it yourself:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import { event, store } from 'codeceptjs'
|
|
47
|
+
|
|
48
|
+
event.dispatcher.on(event.step.before, () => {
|
|
49
|
+
if (store.dryRun) return // skip side effects on a dry run
|
|
50
|
+
})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
See [Architecture › Events](/architecture#events) for the full event list and the test and step object fields, and the [Store reference](/store) for every state field.
|
|
44
54
|
|
|
45
55
|
## Plugins
|
|
46
56
|
|
package/docs/index.md
CHANGED
|
@@ -100,7 +100,7 @@ Scenario('Create a new store', async ({ I, login, SettingsPage }) => {
|
|
|
100
100
|
I.fillField('Email', faker.internet.email());
|
|
101
101
|
I.fillField('Telephone', faker.phone.phoneNumberFormat());
|
|
102
102
|
I.selectInDropdown('Status', 'Active'); // Use custom methods
|
|
103
|
-
I.
|
|
103
|
+
I.click('Create', step.retry(2)); // Retry flaky step
|
|
104
104
|
I.waitInUrl('/settings/setup/stores'); // Explicit waiter
|
|
105
105
|
I.see(storeName, '.settings'); // Assert text present inside an element (located by CSS)
|
|
106
106
|
const storeId = await I.grabTextFrom('#store-id'); // Use await to get information from browser
|
package/docs/installation.md
CHANGED
|
@@ -60,26 +60,9 @@ W3C WebDriver — runs Chrome, Firefox, Edge, Safari, and remote or cloud grids.
|
|
|
60
60
|
npm i webdriverio --save-dev
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
WebdriverIO 9 downloads and starts the matching driver automatically — no Selenium server, ChromeDriver, or GeckoDriver to install or run. Just set `browser` (`chrome`, `firefox`, `MicrosoftEdge`, `safari`) in `codecept.conf.js` — see the [WebDriver helper](/webdriver).
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
```sh
|
|
68
|
-
npm i selenium-standalone --save-dev
|
|
69
|
-
npx selenium-standalone install
|
|
70
|
-
npx selenium-standalone start
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
- **[Docker](https://github.com/SeleniumHQ/docker-selenium)** — a headless Selenium + browser container:
|
|
74
|
-
|
|
75
|
-
```sh
|
|
76
|
-
docker run --net=host --shm-size=2g selenium/standalone-chrome
|
|
77
|
-
# or selenium/standalone-firefox
|
|
78
|
-
```
|
|
79
|
-
|
|
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.
|
|
81
|
-
|
|
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).
|
|
65
|
+
To run against a cloud grid (Sauce Labs, BrowserStack, LambdaTest, and so on) instead, set the grid's `host`, `port`, `user`, and `key` (or `protocol` / `path`) in the helper config. For running this on CI, see [Continuous Integration](/continuous-integration).
|
|
83
66
|
|
|
84
67
|
## Appium (mobile)
|
|
85
68
|
|
package/docs/locators.md
CHANGED
|
@@ -22,7 +22,7 @@ I.click({ role: 'button', name: 'Submit' }, '#login-form')
|
|
|
22
22
|
|
|
23
23
|
The context narrows the search to one region of the page, and the semantic string says what the user actually clicks. This is **more precise than ARIA or CSS alone** because it combines structural scope with human-readable intent.
|
|
24
24
|
|
|
25
|
-
Supported strategies: `css`, `xpath`, `id`, `name`, `role`, `frame`, `shadow`, `pw`. Shadow DOM
|
|
25
|
+
Supported strategies: `css`, `xpath`, `id`, `name`, `role`, `frame`, `shadow`, `pw`. Shadow DOM has its own page — see [Shadow DOM](/shadow). Playwright-specific locators use the `pw` strategy: `{ pw: '[data-testid="save"]' }`. To test components by their accessible role, use [ARIA locators](#aria-locators).
|
|
26
26
|
|
|
27
27
|
## Locator types at a glance
|
|
28
28
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
permalink: /migrate-from-cypress
|
|
3
|
+
title: Migrate from Cypress to CodeceptJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Migrate from Cypress to CodeceptJS
|
|
7
|
+
|
|
8
|
+
## Start here: what Cypress boxes you into
|
|
9
|
+
|
|
10
|
+
A Cypress test runs inside the browser, in the same tab as your app. That keeps a simple test short, but it fixes the test to one tab, one browser, and one origin. A second tab, a second logged-in user, a different domain, or an API call between two clicks each needs a special workaround: `cy.origin`, `cy.session`, request plumbing, tab stubbing. Cross-browser is limited the same way: Chromium first, WebKit partial.
|
|
11
|
+
|
|
12
|
+
CodeceptJS runs the test in Node and controls the browser from the outside. The test is a normal Node script, so a second tab, a second user, an API call in the middle of a flow, and Firefox or WebKit are ordinary steps instead of workarounds. It drives the browser through Playwright by default, or Puppeteer or WebDriver if you prefer.
|
|
13
|
+
|
|
14
|
+
Migrating a Cypress suite looks like a lot of work. It is not. We prepared a set of skills, so you can relax and [let an agent do the migration](#let-an-agent-do-the-migration).
|
|
15
|
+
|
|
16
|
+
## Comparison
|
|
17
|
+
|
|
18
|
+
The original test in Cypress:
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
// Cypress
|
|
22
|
+
it('user can log in', () => {
|
|
23
|
+
cy.visit('/login');
|
|
24
|
+
cy.get('#username').type('alice');
|
|
25
|
+
cy.get('#password').type('secret');
|
|
26
|
+
cy.contains('Sign in').click();
|
|
27
|
+
cy.url().should('include', '/dashboard');
|
|
28
|
+
cy.contains('.welcome', 'Welcome, Alice');
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Will look in CodeceptJS:
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
// CodeceptJS
|
|
36
|
+
Scenario('user can log in', ({ I }) => {
|
|
37
|
+
I.amOnPage('/login');
|
|
38
|
+
I.fillField('Username', 'alice');
|
|
39
|
+
I.fillField('Password', 'secret');
|
|
40
|
+
I.click('Sign in');
|
|
41
|
+
I.seeInCurrentUrl('/dashboard');
|
|
42
|
+
I.see('Welcome, Alice', '.welcome');
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Cypress commands run on a `.then()` queue, so any condition or loop becomes nested callbacks. CodeceptJS is **async/await native**: complex tests stay flat JavaScript, and shared steps move into built-in page objects.
|
|
47
|
+
|
|
48
|
+
And here is how the test looks while it runs. Every step is printed live, in the same order it was written:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
user can log in
|
|
52
|
+
I am on page "/login"
|
|
53
|
+
I fill field "Username", "alice"
|
|
54
|
+
I fill field "Password", "secret"
|
|
55
|
+
I click "Sign in"
|
|
56
|
+
I see in current url "/dashboard"
|
|
57
|
+
I see "Welcome, Alice", ".welcome"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
When a step fails, the output stays on that line, with the locator that missed and a screenshot attached. There is no separate report step before you know what happened.
|
|
61
|
+
|
|
62
|
+
## Let an agent do the migration
|
|
63
|
+
|
|
64
|
+
The conversions are mechanical, so you do not have to do them by hand, and the work does not cost you working time. Install the skills bundle, point an agent at the repo, and check back when it reports.
|
|
65
|
+
|
|
66
|
+
The **`migrate-cypress-to-codeceptjs`** skill in the [CodeceptJS skills bundle](https://github.com/codeceptjs/skills) does the whole port:
|
|
67
|
+
|
|
68
|
+
1. Inventories the shared logic, custom commands, and page modules.
|
|
69
|
+
2. Sets up CodeceptJS beside the Cypress suite.
|
|
70
|
+
3. Ports the custom commands and page objects.
|
|
71
|
+
4. Converts each spec.
|
|
72
|
+
5. Runs the full suite.
|
|
73
|
+
|
|
74
|
+
First runs fail, because locators drift and timing changes. The agent then uses the `debugging-codeceptjs-tests` skill to fix each failure against the live browser before moving on. Your Cypress suite keeps running in CI until the port is green, so nothing is at risk while the agent works.
|
|
75
|
+
|
|
76
|
+
Install the bundle in Claude Code:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
/plugin marketplace add codeceptjs/skills
|
|
80
|
+
/plugin install codeceptjs@codeceptjs-skills
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Or any other agent:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npx skills add codeceptjs/skills
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Then ask: *"Migrate this Cypress suite to CodeceptJS."* The skill triggers on the Cypress signatures in your repo. Start it, do other work, and read the step output when it reports back.
|
|
90
|
+
|
|
91
|
+
## Pointers
|
|
92
|
+
|
|
93
|
+
- [/agents](/agents) for how the agent and MCP loop works
|
|
94
|
+
- [/playwright](/playwright) for the default helper in this migration
|
|
95
|
+
- [/locators](/locators) for semantic, ARIA, and `locate()` locators
|
|
96
|
+
- [/auth](/auth) for replacing `cy.session()` and programmatic login
|
|
97
|
+
- [/api](/api) for the REST helper used in `cy.request` ports
|
|
98
|
+
- [/pageobjects](/pageobjects) for ported page objects
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
permalink: /migrate-from-java
|
|
3
|
+
title: Migrate from Java Selenium to CodeceptJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Migrate from Java Selenium to CodeceptJS
|
|
7
|
+
|
|
8
|
+
## Start here: what changes when you leave the JVM
|
|
9
|
+
|
|
10
|
+
On the JVM, an end-to-end suite is basically its own product. It has its own Maven or Gradle build, its own dependencies, and a JVM that has to warm up before anything runs. In practice it ends up with its own team too — application engineers stay on the app, QA stays on the tests, and the suite drifts whenever nobody is watching it.
|
|
11
|
+
|
|
12
|
+
In Node there is no compile or build step. Running tests in NodeJS saves time. NodeJS ecosystem is fastest growing opensource ecosystem, with awesome depenency management tools like npm, bun, pnpm. While Java tests still work JS ecosystem is richer and easier to use. Tools like Playwright and Puppeteer originally started on NodeJS.
|
|
13
|
+
|
|
14
|
+
Even migrating from Java to JavaScript seems like a huge task, it is actually not.
|
|
15
|
+
We prepared a set of skills for, so you can relax and
|
|
16
|
+
[let an agent do the migration](#let-an-agent-do-the-migration).
|
|
17
|
+
|
|
18
|
+
## Comparison
|
|
19
|
+
|
|
20
|
+
The original test in Java Selenium:
|
|
21
|
+
|
|
22
|
+
```java
|
|
23
|
+
// Java + Selenium + JUnit
|
|
24
|
+
@Test
|
|
25
|
+
public void userCanLogin() {
|
|
26
|
+
WebDriver driver = new ChromeDriver();
|
|
27
|
+
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
|
|
28
|
+
|
|
29
|
+
driver.get("https://example.com/login");
|
|
30
|
+
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("username")));
|
|
31
|
+
|
|
32
|
+
driver.findElement(By.id("username")).sendKeys("alice");
|
|
33
|
+
driver.findElement(By.id("password")).sendKeys("secret");
|
|
34
|
+
driver.findElement(By.cssSelector("button[type=submit]")).click();
|
|
35
|
+
|
|
36
|
+
wait.until(ExpectedConditions.urlContains("/dashboard"));
|
|
37
|
+
WebElement welcome = wait.until(
|
|
38
|
+
ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".welcome"))
|
|
39
|
+
);
|
|
40
|
+
assertEquals("Welcome, Alice", welcome.getText());
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Will look in CodeceptJS:
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
// CodeceptJS
|
|
48
|
+
Scenario('user can log in', ({ I }) => {
|
|
49
|
+
I.amOnPage('/login');
|
|
50
|
+
I.fillField('Username', 'alice');
|
|
51
|
+
I.fillField('Password', 'secret');
|
|
52
|
+
I.click('Sign in');
|
|
53
|
+
I.seeInCurrentUrl('/dashboard');
|
|
54
|
+
I.see('Welcome, Alice', '.welcome');
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
And here is how this test looks while running — every step is printed live, in the same order it was written:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
user can log in
|
|
62
|
+
I am on page "/login"
|
|
63
|
+
I fill field "Username", "alice"
|
|
64
|
+
I fill field "Password", "secret"
|
|
65
|
+
I click "Sign in"
|
|
66
|
+
I see in current url "/dashboard"
|
|
67
|
+
I see "Welcome, Alice", ".welcome"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Let an agent do the migration
|
|
71
|
+
|
|
72
|
+
The conversions above are mechanical, so you do not have to do them by hand, and the work does not cost you working time. Install the skills bundle, point an agent at the repo, and check back when it reports.
|
|
73
|
+
|
|
74
|
+
The **`migrate-selenium-java-to-codeceptjs`** skill in the [CodeceptJS skills bundle](https://github.com/codeceptjs/skills) does the whole port:
|
|
75
|
+
|
|
76
|
+
1. Inventories the page objects, helper classes, hooks, and data providers.
|
|
77
|
+
2. Sets up CodeceptJS beside the Java suite with the WebDriver helper.
|
|
78
|
+
3. Ports the page objects and helpers.
|
|
79
|
+
4. Converts each spec.
|
|
80
|
+
5. Runs the full suite.
|
|
81
|
+
|
|
82
|
+
First runs fail, because locators drift and timing changes. The agent then uses the `debugging-codeceptjs-tests` skill to fix each failure against the live browser before moving on. Your Java suite keeps running in CI until the port is green, so nothing is at risk while the agent works.
|
|
83
|
+
|
|
84
|
+
Install the bundle in Claude Code:
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
/plugin marketplace add codeceptjs/skills
|
|
88
|
+
/plugin install codeceptjs@codeceptjs-skills
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Or any other agent:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npx skills add codeceptjs/skills
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Then ask: *"Migrate this Java Selenium suite to CodeceptJS."* The skill triggers on the Maven or Gradle and `org.openqa.selenium` signatures in your repo. Start it, do other work, and read the step output when it reports back.
|
|
98
|
+
|
|
99
|
+
## Pointers
|
|
100
|
+
|
|
101
|
+
- [/agents](/agents) for how the agent and MCP loop works
|
|
102
|
+
- [/webdriver](/webdriver) for the default helper in this migration, with driver auto-start
|
|
103
|
+
- [/playwright](/playwright) for the optional follow-up swap
|
|
104
|
+
- [/locators](/locators) for semantic, ARIA, and `locate()` locators
|
|
105
|
+
- [/pageobjects](/pageobjects) for ported `@FindBy` page objects
|
|
106
|
+
- [/auth](/auth) for login and session reuse
|
|
107
|
+
- [/api](/api) for the REST helper used in RestAssured ports
|
|
108
|
+
- [/bdd](/bdd) for CodeceptJS BDD in Cucumber-JVM ports
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
permalink: /migrate-from-protractor
|
|
3
|
+
title: Migrate from Protractor to CodeceptJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Migrate from Protractor to CodeceptJS
|
|
7
|
+
|
|
8
|
+
## Start here: a dead dependency with an Angular wrapper
|
|
9
|
+
|
|
10
|
+
Protractor was end-of-lifed in April 2023 and has shipped nothing since. Its design wrapped Selenium with two things: `waitForAngular`, which blocked each action until Angular's digest cycle settled, and the ControlFlow promise manager, which ordered commands so test code could be written as if it were synchronous. That is why a Protractor suite pins an old Selenium version and threads results through `.then()`. The dependency only ages from here.
|
|
11
|
+
|
|
12
|
+
CodeceptJS drops the Angular coupling. The helper waits on the element you are acting on, not on Angular's digest, so the same test works on an Angular app, a React app, or a static page. It still speaks the WebDriver protocol, so an existing Selenium Grid keeps serving the new suite, or you switch the config to Playwright and run the same test code faster.
|
|
13
|
+
|
|
14
|
+
Migrating a Protractor suite looks like a lot of work. It is not. We prepared a set of skills, so you can relax and [let an agent do the migration](#let-an-agent-do-the-migration).
|
|
15
|
+
|
|
16
|
+
## Comparison
|
|
17
|
+
|
|
18
|
+
The original test in Protractor:
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
// Protractor + Jasmine
|
|
22
|
+
describe('login', function () {
|
|
23
|
+
it('user can log in', function () {
|
|
24
|
+
browser.get('https://example.com/login');
|
|
25
|
+
element(by.model('user.email')).sendKeys('alice@example.com');
|
|
26
|
+
element(by.model('user.password')).sendKeys('secret');
|
|
27
|
+
element(by.css('button[type=submit]')).click();
|
|
28
|
+
expect(browser.getCurrentUrl()).toContain('/dashboard');
|
|
29
|
+
expect(element(by.css('.welcome')).getText()).toContain('Welcome, Alice');
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Will look in CodeceptJS:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
// CodeceptJS
|
|
38
|
+
Scenario('user can log in', ({ I }) => {
|
|
39
|
+
I.amOnPage('/login');
|
|
40
|
+
I.fillField('Email', 'alice@example.com');
|
|
41
|
+
I.fillField('Password', 'secret');
|
|
42
|
+
I.click('Sign in');
|
|
43
|
+
I.seeInCurrentUrl('/dashboard');
|
|
44
|
+
I.see('Welcome, Alice', '.welcome');
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The `describe`/`it` nesting, the `by.model` strategy, and the Jasmine assertions are gone. The steps read as a sequence instead of a chain of `.then()` calls.
|
|
49
|
+
|
|
50
|
+
And here is how the test looks while it runs. Every step is printed live, in the same order it was written:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
user can log in
|
|
54
|
+
I am on page "/login"
|
|
55
|
+
I fill field "Email", "alice@example.com"
|
|
56
|
+
I fill field "Password", "secret"
|
|
57
|
+
I click "Sign in"
|
|
58
|
+
I see in current url "/dashboard"
|
|
59
|
+
I see "Welcome, Alice", ".welcome"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
When a step fails, the output stays on that line, with the locator that missed and a screenshot attached. There is no separate report step before you know what happened.
|
|
63
|
+
|
|
64
|
+
## Let an agent do the migration
|
|
65
|
+
|
|
66
|
+
The conversions are mechanical, so you do not have to do them by hand, and the work does not cost you working time. Install the skills bundle, point an agent at the repo, and check back when it reports.
|
|
67
|
+
|
|
68
|
+
The **`migrate-protractor-to-codeceptjs`** skill in the [CodeceptJS skills bundle](https://github.com/codeceptjs/skills) does the whole port:
|
|
69
|
+
|
|
70
|
+
1. Inventories the page objects, shared helpers, and config hooks.
|
|
71
|
+
2. Sets up CodeceptJS beside the Protractor suite.
|
|
72
|
+
3. Ports the page objects and helpers.
|
|
73
|
+
4. Converts each spec.
|
|
74
|
+
5. Runs the full suite.
|
|
75
|
+
|
|
76
|
+
First runs fail, because locators drift and timing changes. The agent then uses the `debugging-codeceptjs-tests` skill to fix each failure against the live browser before moving on. Your Protractor suite keeps running in CI until the port is green, so nothing is at risk while the agent works.
|
|
77
|
+
|
|
78
|
+
Install the bundle in Claude Code:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
/plugin marketplace add codeceptjs/skills
|
|
82
|
+
/plugin install codeceptjs@codeceptjs-skills
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Or any other agent:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx skills add codeceptjs/skills
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Then ask: *"Migrate this Protractor suite to CodeceptJS."* The skill triggers on the Protractor signatures in your repo. Start it, do other work, and read the step output when it reports back.
|
|
92
|
+
|
|
93
|
+
## Pointers
|
|
94
|
+
|
|
95
|
+
- [/agents](/agents) for how the agent and MCP loop works
|
|
96
|
+
- [/playwright](/playwright) for the recommended target helper
|
|
97
|
+
- [/webdriver](/webdriver) for the target if you keep a Selenium Grid
|
|
98
|
+
- [/locators](/locators) for semantic, ARIA, `locate()`, and the `customLocator` plugin
|
|
99
|
+
- [/pageobjects](/pageobjects) for ported Protractor page objects
|
|
100
|
+
- [/auth](/auth) for programmatic login and session reuse
|
|
101
|
+
- [/api](/api) for the REST helper used in HTTP-call ports
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
permalink: /migrate-from-testcafe
|
|
3
|
+
title: Migrate from TestCafe to CodeceptJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Migrate from TestCafe to CodeceptJS
|
|
7
|
+
|
|
8
|
+
## Start here: what the proxy costs you
|
|
9
|
+
|
|
10
|
+
TestCafe does not drive a browser through a driver. It runs a proxy in front of the browser, rewrites every page and script as they load, and injects its automation into the rewritten page. That worked when it was built, but the web platform now fights it. Content Security Policy blocks the injected script. HSTS, SameSite cookies, and COOP/COEP assume the origin the browser actually requested, not a proxied one. Service workers cache the rewritten responses. The proxy has more to paper over every release, and every action in a test needs its own `await` because each one is a round trip through the injected runtime.
|
|
11
|
+
|
|
12
|
+
CodeceptJS drives a real browser through a driver: Playwright over CDP, across the same Chromium, Firefox, and WebKit engines TestCafe targeted, with nothing in the request path. The page the test sees is the page the server sent, so there is nothing to rewrite and nothing for the platform to break. Actions queue internally, so they read top to bottom without `await` on every line.
|
|
13
|
+
|
|
14
|
+
Migrating a TestCafe suite looks like a lot of work. It is not. We prepared a set of skills, so you can relax and [let an agent do the migration](#let-an-agent-do-the-migration).
|
|
15
|
+
|
|
16
|
+
## Comparison
|
|
17
|
+
|
|
18
|
+
The original test in TestCafe:
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
// TestCafe
|
|
22
|
+
fixture`Login`.page`https://example.com/login`;
|
|
23
|
+
|
|
24
|
+
test('user can log in', async t => {
|
|
25
|
+
await t.typeText(Selector('#username'), 'alice');
|
|
26
|
+
await t.typeText(Selector('#password'), 'secret');
|
|
27
|
+
await t.click(Selector('button').withText('Sign in'));
|
|
28
|
+
await t.expect(getLocation()).contains('/dashboard');
|
|
29
|
+
await t.expect(Selector('.welcome').innerText).contains('Welcome, Alice');
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Will look in CodeceptJS:
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
// CodeceptJS
|
|
37
|
+
Scenario('user can log in', ({ I }) => {
|
|
38
|
+
I.amOnPage('/login');
|
|
39
|
+
I.fillField('Username', 'alice');
|
|
40
|
+
I.fillField('Password', 'secret');
|
|
41
|
+
I.click('Sign in');
|
|
42
|
+
I.seeInCurrentUrl('/dashboard');
|
|
43
|
+
I.see('Welcome, Alice', '.welcome');
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Every `await`, every `t`, and every `Selector` is gone. The steps read as a sequence instead of a chain of awaited calls.
|
|
48
|
+
|
|
49
|
+
And here is how the test looks while it runs. Every step is printed live, in the same order it was written:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
user can log in
|
|
53
|
+
I am on page "/login"
|
|
54
|
+
I fill field "Username", "alice"
|
|
55
|
+
I fill field "Password", "secret"
|
|
56
|
+
I click "Sign in"
|
|
57
|
+
I see in current url "/dashboard"
|
|
58
|
+
I see "Welcome, Alice", ".welcome"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
When a step fails, the output stays on that line, with the locator that missed and a screenshot attached. There is no separate report step before you know what happened.
|
|
62
|
+
|
|
63
|
+
## Let an agent do the migration
|
|
64
|
+
|
|
65
|
+
The conversions are mechanical, so you do not have to do them by hand, and the work does not cost you working time. Install the skills bundle, point an agent at the repo, and check back when it reports.
|
|
66
|
+
|
|
67
|
+
The **`migrate-testcafe-to-codeceptjs`** skill in the [CodeceptJS skills bundle](https://github.com/codeceptjs/skills) does the whole port:
|
|
68
|
+
|
|
69
|
+
1. Inventories the shared logic: `Role` setup, `ClientFunction` wrappers, page models, and request mocks.
|
|
70
|
+
2. Sets up CodeceptJS beside the TestCafe suite with the Playwright helper.
|
|
71
|
+
3. Ports the abstractions into custom helpers and page objects.
|
|
72
|
+
4. Converts each spec.
|
|
73
|
+
5. Runs the full suite.
|
|
74
|
+
|
|
75
|
+
First runs fail, because locators drift and timing changes. The agent then uses the `debugging-codeceptjs-tests` skill to fix each failure against the live browser before moving on. Your TestCafe suite keeps running in CI until the port is green, so nothing is at risk while the agent works.
|
|
76
|
+
|
|
77
|
+
Install the bundle in Claude Code:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
/plugin marketplace add codeceptjs/skills
|
|
81
|
+
/plugin install codeceptjs@codeceptjs-skills
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or any other agent:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx skills add codeceptjs/skills
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Then ask: *"Migrate this TestCafe suite to CodeceptJS."* The skill triggers on the TestCafe signatures in your repo. Start it, do other work, and read the step output when it reports back.
|
|
91
|
+
|
|
92
|
+
## Pointers
|
|
93
|
+
|
|
94
|
+
- [/agents](/agents) for how the agent and MCP loop works
|
|
95
|
+
- [/playwright](/playwright) for the default helper in this migration
|
|
96
|
+
- [/locators](/locators) for semantic, ARIA, and `locate()` locators in place of `Selector` chains
|
|
97
|
+
- [/auth](/auth) for the plugin that replaces `Role` and `t.useRole`
|
|
98
|
+
- [/api](/api) for the REST helper used in API testing
|
|
99
|
+
- [/pageobjects](/pageobjects) for ported page objects
|