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
2 changes: 1 addition & 1 deletion docs/custom-helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ _before() {
}
```

`recorder.retry` acts similarly to `I.retry()` and accepts the same parameters. It expects the `when` parameter to be set so it would handle only specific errors and not to retry for every failed step.
`recorder.retry` registers a retry rule at the recorder level and accepts the same options as `step.retry()` (`retries`, `minTimeout`, `when`, ...). It expects the `when` parameter to be set so it would handle only specific errors and not to retry for every failed step.

Retry rules are available in array `recorder.retries`. The last retry rule can be disabled by running `recorder.retries.pop()`;

Expand Down
2 changes: 1 addition & 1 deletion docs/detox.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ CodeceptJS provides next features over standard Detox:

* **Unified API**. The same test can be executed in Appium or Detox. Unified API helps different teams to use the same syntax and easy port tests from one engine to another.
* [Interactive pause](/basics#pause). When starting/stopping an application takes a long time, debugging and writing tests can be hard. CodeceptJS solves this by pausing an execution and letting you try different commands and locators. With this feature a test can be writtern during one running session.
* [Auto-retries](/basics#retries) using `retryFailedStepPlugin` and `I.retry()`
* [Auto-retries](/basics#retries) using the `retryFailedStep` plugin and `step.retry()`
* **Cross-Platform testing** - one test can be executed on different engines. When needed, platform-specific actions and locators can be easily applied.

## A Test
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Scenario('Create a new store', async ({ I, login, SettingsPage }) => {
I.fillField('Email', faker.internet.email());
I.fillField('Telephone', faker.phone.phoneNumberFormat());
I.selectInDropdown('Status', 'Active'); // Use custom methods
I.retry(2).click('Create'); // Retry flaky step
I.click('Create', step.retry(2)); // Retry flaky step
I.waitInUrl('/settings/setup/stores'); // Explicit waiter
I.see(storeName, '.settings'); // Assert text present inside an element (located by CSS)
const storeId = await I.grabTextFrom('#store-id'); // Use await to get information from browser
Expand Down
16 changes: 12 additions & 4 deletions docs/migration-4.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,18 +473,26 @@ Use one of:

The `customLocators` strategy registration in Playwright config is removed. Use the `customLocator` plugin or built-in ARIA locators (`{ role: 'button', name: 'Submit' }`).

### `I.retry()` is deprecated
### `I.retry()` and `I.limitTime()` removed

Use the step options API:
Both were deprecated in 3.x and are **removed in 4.x**. They configured the *next* step through a chained call; the replacement is the step options API — pass a `step.*` config as the **last argument** of the step itself.

```js
import step from 'codeceptjs/steps'

I.click('Submit', step.retry(3))
I.fillField('Email', 'a@b.c', step.timeout(10))
// 3.x (removed) → 4.x
I.retry(3).click('Submit') // I.click('Submit', step.retry(3))
I.limitTime(10).fillField('Email', 'a@b.c') // I.fillField('Email', 'a@b.c', step.timeout(10))
```

`step.*` configs are also composable with the other step options:

```js
I.click('Add', step.opts({ elementIndex: 2 }))
```

The behavior is unchanged — the option applies only to the step it is attached to, not to subsequent steps (this also fixes the 3.x footgun where `I.retry()` could leak retry settings onto the following step). `recorder.retry()` is unaffected and remains available for custom helpers.

### `within` Is Now an Effect

In 3.x, `within(...)` was a global statement available everywhere. In 4.x it's an effect alongside `tryTo`, `retryTo`, and `hopeThat`. Under `noGlobals: true` you must import it:
Expand Down
2 changes: 1 addition & 1 deletion docs/plugins/retryFailedStep.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ plugins: {

#### Disable Per Test

This plugin can be disabled per test. In this case you will need to stet `I.retry()` to all flaky steps:
This plugin can be disabled per test. In this case you will need to add `step.retry()` to all flaky steps:

Use scenario configuration to disable plugin for a test

Expand Down
2 changes: 1 addition & 1 deletion docs/plugins/stepTimeout.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Run tests with plugin enabled:

* `timeout` - global step timeout, default 150 seconds

* `overrideStepLimits` - whether to use timeouts set in plugin config to override step timeouts set in code with I.limitTime(x).action(...), default false
* `overrideStepLimits` - whether to use timeouts set in plugin config to override step timeouts set in code with `I.action(..., step.timeout(x))`, default false

* `noTimeoutSteps` - an array of steps with no timeout. Default:

Expand Down
2 changes: 1 addition & 1 deletion docs/timeouts.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ plugins: {
When multiple timeouts are configured, CodeceptJS applies them in priority order:

1. **stepTimeoutHard** — plugin with `overrideStepLimits: true`
2. **codeLimitTime** — `step.timeout()` or `I.limitTime()`
2. **codeLimitTime** — `step.timeout()`
3. **stepTimeoutSoft** — plugin with `overrideStepLimits: false`
4. **testOrSuite** — global test/suite timeout

Expand Down
35 changes: 0 additions & 35 deletions lib/actor.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import Step, { MetaStep } from './step.js'
import recordStep from './step/record.js'
import retryStep from './step/retry.js'
import { methodsOfObject } from './utils.js'
import { TIMEOUT_ORDER } from './timeout.js'
import event from './event.js'
import store from './store.js'
import output from './output.js'
import Container from './container.js'

Expand All @@ -30,38 +27,6 @@ class Actor {
output.say(msg, `${color}`)
})
}

/**
* set the maximum execution time for the next step
* @function
* @param {number} timeout - step timeout in seconds
* @return {this}
* @inner
*/
limitTime(timeout) {
if (!store.timeouts) return this

console.log('I.limitTime() is deprecated, use step.timeout() instead')

event.dispatcher.prependOnceListener(event.step.before, step => {
output.log(`Timeout to ${step}: ${timeout}s`)
step.setTimeout(timeout * 1000, TIMEOUT_ORDER.codeLimitTime)
})

return this
}

/**
* @function
* @param {*} [opts]
* @return {this}
* @inner
*/
retry(opts) {
console.log('I.retry() is deprecated, use step.retry() instead')
retryStep(opts)
return this
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/plugin/retryFailedStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const RETRY_PRIORITIES = {
*
* #### Disable Per Test
*
* This plugin can be disabled per test. In this case you will need to stet `I.retry()` to all flaky steps:
* This plugin can be disabled per test. In this case you will need to add `step.retry()` to all flaky steps:
*
* Use scenario configuration to disable plugin for a test
*
Expand Down
2 changes: 1 addition & 1 deletion lib/plugin/stepTimeout.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const defaultConfig = {
* #### Configuration:
*
* * `timeout` - global step timeout, default 150 seconds
* * `overrideStepLimits` - whether to use timeouts set in plugin config to override step timeouts set in code with I.limitTime(x).action(...), default false
* * `overrideStepLimits` - whether to use timeouts set in plugin config to override step timeouts set in code with `I.action(..., step.timeout(x))`, default false
* * `noTimeoutSteps` - an array of steps with no timeout. Default:
* * `amOnPage`
* * `wait*`
Expand Down
4 changes: 3 additions & 1 deletion test/data/sandbox/configs/step_timeout/first_test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import step from 'codeceptjs/steps'

const { I } = inject()

Feature('Steps')
Expand All @@ -11,7 +13,7 @@ Scenario('Wait command timeout', ({ I }) => {
})

Scenario('Rerun sleep', ({ I }) => {
I.retry(2).statefulSleep(2250)
I.statefulSleep(2250, step.retry(2))
})

Scenario('Wait with longer timeout', ({ I }) => {
Expand Down
5 changes: 0 additions & 5 deletions test/data/sandbox/configs/timeouts/suite_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ Scenario('timeout test in 0.5 #second', { timeout: 0.5 }, ({ I }) => {
I.waitForSleep(1000)
})

Scenario('timeout step in 0.5 old syntax', ({ I }) => {
I.limitTime(0.2).waitForSleep(100)
I.limitTime(0.2).waitForSleep(3000)
})

Scenario('timeout step in 0.5 new syntax', ({ I }) => {
I.waitForSleep(100, step.timeout(0.2))
I.waitForSleep(3000, step.timeout(0.2))
Expand Down
7 changes: 4 additions & 3 deletions test/data/sandbox/flaky_test.retry.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import assert from 'assert';
import step from 'codeceptjs/steps';

const recorder = codeceptjs.recorder;

Expand All @@ -8,10 +9,10 @@ Feature('Retry');

Scenario('flaky step @test1', async ({ I }) => {
tries++;
await I.retry(3).failWhen(() => {
await I.failWhen(() => {
tries++;
return tries < 4;
});
}, step.retry(3));
assert.equal(tries, 4);
});

Expand All @@ -20,7 +21,7 @@ Scenario('flaky step passed globally @test2', ({ I }) => {
retries: 3,
when: () => false,
});
I.retry(5).asyncStep();
I.asyncStep(step.retry(5));
I.failWhen(() => {
tries++;
return tries < 4;
Expand Down
15 changes: 3 additions & 12 deletions test/unit/actor_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { fileURLToPath } from 'url'
import actor from '../../lib/actor.js'
import container from '../../lib/container.js'
import recorder from '../../lib/recorder.js'
import step from '../../lib/steps.js'
import event from '../../lib/event.js'
import store from '../../lib/store.js'

Expand Down Expand Up @@ -107,7 +108,7 @@ describe('Actor', () => {
})

it('should take all methods from helpers and built in', () => {
;['hello', 'bye', 'die', 'failAfter', 'say', 'retry', 'greeting'].forEach(key => {
;['hello', 'bye', 'die', 'failAfter', 'say', 'greeting'].forEach(key => {
expect(I).toHaveProperty(key)
})
})
Expand Down Expand Up @@ -135,16 +136,6 @@ describe('Actor', () => {
})
})

it('should retry failed step with #retry', () => {
recorder.start()
return I.retry({ retries: 2, minTimeout: 0 }).failAfter(1)
})

it('should retry once step with #retry', () => {
recorder.start()
return I.retry().failAfter(1)
})

it('should alway use the latest global retry options', () => {
recorder.start()
recorder.retry({
Expand All @@ -168,7 +159,7 @@ describe('Actor', () => {
minTimeout: 0,
when: () => true,
})
I.retry(1).failAfter(1) // before fix: this changed the order of retries
I.failAfter(1, step.retry(1)) // before fix: this changed the order of retries
return I.failAfter(2)
})

Expand Down
11 changes: 4 additions & 7 deletions typings/tests/actor.types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { expectError } from 'tsd';

// @ts-ignore
const I = actor();

I.retry();
I.retry(1);
I.retry({ retries: 3, minTimeout: 100 });
// Removed: expectError(I.retry(1, 2)); - retry accepts 'any' type so this doesn't error

// I.retry() and I.limitTime() were removed in 4.x.
// Use step.retry() / step.timeout() as the last step argument instead.
// `I` resolves to `any` in this typing test, so the removal cannot be
// asserted at the type level here.
1 change: 0 additions & 1 deletion typings/tests/helpers/Playwright.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ expectType<Promise<void>>(playwright.handleDownloads(str));
expectType<void>(playwright.click(str));
expectType<void>(playwright.click(str, str));
expectType<void>(playwright.click(str, null, { position }));
expectType<void>(playwright.clickLink());
expectType<void>(playwright.forceClick(str));
expectType<void>(playwright.focus(str));
expectType<void>(playwright.blur(str));
Expand Down
1 change: 0 additions & 1 deletion typings/tests/helpers/PlaywrightTs.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ expectType<Promise<void>>(playwright.handleDownloads(str));
expectType<Promise<any>>(playwright.click(str));
expectType<Promise<any>>(playwright.click(str, str));
expectType<Promise<any>>(playwright.click(str, null, { position }));
expectType<Promise<any>>(playwright.clickLink());
expectType<Promise<any>>(playwright.forceClick(str));
expectType<Promise<any>>(playwright.focus(str));
expectType<Promise<any>>(playwright.blur(str));
Expand Down