About migrate-codeceptjs-4
A migration skill for teams upgrading CodeceptJS 3.x projects to the ESM-only, TypeScript-first 4.x release. It guides code, configuration, dependency, and test updates, including a user decision point for Mochawesome.
Key features
- 01Detects CodeceptJS 3.x migration signals
- 02Converts project files to ESM
- 03Maps removed helpers and plugins to replacements
- 04Updates changed APIs and dependencies
- 05Runs configuration and test verification
Use cases
- 01Upgrading an existing CodeceptJS 3.x test suite
- 02Migrating CommonJS helpers and configuration
- 03Resolving removed plugins and changed APIs
- 04Validating a migration before merging changes
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ codeceptjs/ skills --skill migrate-codeceptjs-4After installing, type/migrate-codeceptjs-4in Claude Code to confirm it loaded.
Details
From the project READMEMigrate CodeceptJS 3.x → 4.x
CodeceptJS 4 is ESM-only and TypeScript-first. There is no compatibility shim for CommonJS — every helper, page object, custom step, and config file must be ESM. This skill drives a project through the upgrade end-to-end.
The authoritative reference is node_modules/codeceptjs/docs/migration-4.md (after npm install codeceptjs@4). Read it once; this skill orchestrates the work and surfaces the parts agents miss.
When to trigger
Detect before acting. Look for any of:
package.jsonlists"codeceptjs": "^3"/"3.x", or has no"type": "module".- Tests, page objects, helpers, or config use
require()/module.exportsagainst CodeceptJS. - Config still references removed helpers (
Nightmare,Protractor,TestCafe,AI,SoftExpectHelper,Mochawesome) or removed plugins (autoLogin,tryTo,retryTo,eachElement,commentStep,fakerTransform,enhancedRetryFailedStep,allure,htmlReporter,wdio,selenoid,screenshotOnFail,pauseOnFail,stepByStepReport). - 3.x APIs:
ai.request, Joi schemas inseeResponseMatchesJsonSchema,restart: 'browser',I.retry(),I.limitTime(), PlaywrightcustomLocators,I.softExpect*/I.flushSoftAssertions. --reporter mochawesomein scripts/CI, ormochawesomeinpackage.json/mocha.reporterOptions.
If none of these hint at 3.x, the project is likely on 4.x already — hand back to codeceptjs-fundamentals.
Workflow
Phases run in order. Commit at each boundary so any regression is bisectable.
1. Bump Node and CodeceptJS
- Confirm Node ≥ 16 (recommended 20+); update
engines.nodeand CI runners. npm install codeceptjs@4.- TypeScript projects:
npm install --save-dev tsx. Replacests-node/esm, which now warns.
2. Convert the project to ESM
- Add
"type": "module"topackage.json. Without this, every.jsfile parses as CommonJS and ESM imports throw at load time. - Convert config, page objects, custom helpers, custom steps, programmatic usage:
const Helper = require('@codeceptjs/helper')→import Helper from '@codeceptjs/helper'module.exports = X→export default X(or named exports)const { codecept, container, event } = require('codeceptjs')→import codeceptjs, { container, event } from 'codeceptjs'
Container.create()andConfig.load()are now async —awaitthem.- Files that genuinely need CJS (rare; usually third-party shims): rename to
.cjs.
3. Remove or replace deleted helpers and plugins
| Old | Replacement |
|---|---|
Helper Nightmare / Protractor / TestCafe | Playwright, Puppeteer, or WebDriver. |
Helper AI | Top-level ai: config + aiTrace plugin. |
Helper SoftExpectHelper | import { hopeThat } from 'codeceptjs/effects'; call hopeThat.noErrors() at end of scenario. |
Helper Mochawesome | Stop and ask the user — see "Mochawesome decision" below. Do not silently delete it. |
Plugin autoLogin | auth plugin (see the codeceptjs-auth skill). |
Plugin tryTo / retryTo | import { tryTo, retryTo } from 'codeceptjs/effects' |
Plugin eachElement | import { eachElement } from 'codeceptjs/els' |
Plugin commentStep | import step from 'codeceptjs/steps' → step.section('name') / step.endSection() |
Plugin fakerTransform | import { faker } from '@faker-js/faker' directly in tests. |
Plugin enhancedRetryFailedStep | Renamed to retryFailedStep. |
Plugin allure / htmlReporter | @testomatio/reporter (HTML pipe). For JUnit XML, the junitReporter plugin. |
Plugin wdio / selenoid | Configure via helpers.WebDriver, or run externally. |
Plugin screenshotOnFail / pauseOnFail / stepByStepReport | Renamed screenshot / pause / screenshot with slides: true. Old names still resolve but emit a deprecation warning. |
Mochawesome decision
The bundled Mochawesome helper is removed in 4.x (the helper class, the mochawesome dependency, and the worker report-dir wiring). The mochawesome reporter itself still works — it is a stock Mocha reporter and never needed CodeceptJS to bundle it.
This is a user choice — do not pick for them. When you detect Mochawesome (the helper in helpers:, --reporter mochawesome, or mochawesome in package.json/mocha.reporterOptions), stop and ask which path they want:
- Switch to
@testomatio/reporter(recommended). Richer HTML report (steps, screenshots, videos, traces), worker-safe, no helper or internal coupling.npm install --save-dev @testomatio/reporter, enable thetestomatioplugin, run withTESTOMATIO_DISABLE_UPLOAD=1. For JUnit XML add thejunitReporterplugin. This is the path to recommend. - Keep Mochawesome — report only. Remove the
Mochawesomehelper fromhelpers:, keepnpm i -D mochawesomeand--reporter mochawesome --reporter-options reportDir=output. Loses the auto-embedded failure screenshots the helper provided. - Keep Mochawesome — with embedded screenshots. Remove the helper from
helpers:and re-create it as a project-local custom helper that wrapsmochawesome/addContext(a faithful port is in the migration guide, section "Keeping Mochawesome"). Flag the two caveats: it imports non-semver-stablecodeceptjs/lib/*internals (pin the version), and the screenshot-plugin filename sync is no longer automatic (setuniqueScreenshotNamesidentically on the helper and thescreenshotplugin).
In all cases also: remove mochawesome report-dir handling from any custom worker scripts, and replace any reliance on I.addMochawesomeContext() (only option 3 keeps it).
Present options 1–3 explicitly and let the user decide before changing anything. Default the recommendation to option 1. The full reference (before/after configs + the custom-helper port) is in node_modules/codeceptjs/docs/migration-4.md → "Mochawesome → Testomat.io Reporter".
4. Update changed APIs
- AI config — delete the
requestfunction. Install Vercel AI SDK + provider (npm install ai @ai-sdk/openai) and setai: { model: openai('gpt-5') }. Same shape for@ai-sdk/anthropic,@ai-sdk/google, etc. - JSON schemas —
I.seeResponseMatchesJsonSchema()now uses Zod, not Joi. Rewrite (Joi.object().keys({...})→z.object({...}),Joi.string().required()→z.string(), etc.) andnpm uninstall joi. - Playwright — replace
restart: 'browser'with'session'(default),'context', or'keep'. DropcustomLocatorsconfig; use thecustomLocatorplugin or ARIA locators ({ role: 'button', name: 'Submit' }). I.retry()/I.limitTime()— removed (not just deprecated). Replace with the step options API:import step from 'codeceptjs/steps', then pass the config as the last argument of the step.I.retry(3).click('Submit')→I.click('Submit', step.retry(3));I.limitTime(10).fillField('Email', x)→I.fillField('Email', x, step.timeout(10)). Alsostep.opts({ elementIndex: 2 }). Behavior is unchanged except the option no longer leaks onto the following step.recorder.retry()is unaffected (custom helpers only).withinandsession— no longer global.import { within, session } from 'codeceptjs'(orwithinfromcodeceptjs/effects). Both return Promises —awaitwhen you need the return value.- Subpath imports —
codeceptjs/effects,codeceptjs/els,codeceptjs/steps,codeceptjs/store,codeceptjs/assertions. See the migration guide for the full list. tryTo/hopeThat— returnPromise<boolean>(the 3.xPromise<T | false>shape is gone).
5. Adopt noGlobals: true
3.x leaked Helper, actor, inject, share, secret, locate, dataTable, within, session, codecept_dir, output_dir as globals. 4.x defaults noGlobals: true in new configs and warns for projects without it. Add it to config and replace globals with explicit imports from codeceptjs / @codeceptjs/helper. Test-runner globals (Feature, Scenario, Before, After, BeforeSuite, AfterSuite, pause, inject, share) and BDD step-definition globals (Given, When, Then, And) stay — they're scope-injected by the runner.
6. Bump dependent packages
If your project depends directly on these, verify nothing breaks: chai (4 → 6, ESM-only), chai-as-promised (7 → 8), commander (11 → 14), @faker-js/faker (9 → 10), chokidar (4 → 5), @cucumber/gherkin (35 → 38), webdriverio (9.12 → 9.23). joi and testcafe are removed. See migration guide §7 for the full table.
7. Verify
Run, in order:
npx codeceptjs check -c <config>— surfaces config / helper / plugin / page object issues without spinning up a browser.npx codeceptjs run --debugon a small smoke scenario. Confirm steps execute and the report is sane.npx codeceptjs run-workers 2— confirms the worker event dispatcher fires per-test events the same way it does in single-process mode (4.x change).- TypeScript users: confirm error stack traces point at
.tssource lines (provestsxis loaded, notts-node/esm). - Grep the repo for
tryTo(,retryTo(,eachElement(,commentStep(,softExpect,I.softExpect,Joi.,restart: 'browser',I.retry(,I.limitTime(, and (unless the user chose to keep it)Mochawesome/--reporter mochawesome— none should remain.step.retry(/step.timeout(passed as a step argument is the expected replacement, not a leftover. - If the project used
autoLogin: confirm theauthplugin restores sessions and roles.
Related skills
codeceptjs-auth— replacement for the removedautoLoginplugincodeceptjs-fundamentals— run after migration to confirm wiring- Full reference:
node_modules/codeceptjs/docs/migration-4.md