refactoring-codeceptjs-tests
About refactoring-codeceptjs-tests
A skill for refactoring CodeceptJS 4 tests while preserving behavior. It helps teams move repeated UI flows, locators, and browser-side logic into appropriate page objects, actor steps, or custom helpers, with proposals and verification between batches.
Key features
- 01Finds duplicated flows and oversized locators
- 02Moves flows into page objects or actor steps
- 03Extracts raw browser logic into custom helpers
- 04Proposes grouped edits before applying
- 05Reruns affected Scenarios after each batch
Use cases
- 01Cleaning up repeated UI test sequences
- 02Reducing locator duplication across tests
- 03Moving browser or data setup logic out of Scenarios
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ codeceptjs/ skills --skill refactoring-codeceptjs-testsAfter installing, type/refactoring-codeceptjs-testsin Claude Code to confirm it loaded.
Details
From the project READMERefactoring CodeceptJS 4 Tests
Suites rot in three predictable ways: duplicated UI flows copy-pasted across files, fat locators repeated everywhere, raw JS escaping into Scenarios. The fix for each is moving the pattern to its proper home without changing behaviour.
Works targeted (a file or Scenario the user named) or global (the whole configured tests glob). Either way: propose first, apply in reviewable batches after approval.
Workflow
- Fundamentals — run
codeceptjs-fundamentals. You need: page objects underinclude, the actor file, custom helpers, auth roles. Without this you don't know where extractions land. - Pick scope:
- Targeted — read once, propose, apply.
- Global — multi-pass cycle: inventory → propose grouped → approve → apply a batch → re-run affected Scenarios → next batch. Never one big edit.
- Inventory — flag:
- Repeated
I.*sequences across 2+ Scenarios - Locators used in 2+ places; multi-line XPath / deeply nested CSS
- Unscoped locators carrying their own region (
'.sidebar nav a.settings'),'aria-label=X'spellings, raw[data-testid=...]at call sites - Multi-statement
I.executeScript;usePlaywrightTo/usePuppeteerTo/useWebDriverTodoing business work - Hardcoded credentials, URLs, magic strings
I.wait(N)and strayawaiton plain actions — fix while you're there
- Repeated
- Duplicate flows → page-object methods named for user intent (
loginPage.signIn(email, pass),cartPage.removeItem(name)). Rule of three: extract at the second occurrence; one-off code stays put. - Fat locators — split before reaching for the builder: structural half becomes the context argument, rest stays a semantic string.
I.click('.sidebar nav a.settings')→I.click('Settings', '.sidebar')I.click({ css: '[aria-label="Save"]' })→I.click('Save', '.toolbar')I.click({ css: '[data-qa=submit]' })→I.click('$submit', '.checkout')withcustomLocatorOnly what survives the split needslocate(): used once → inline at call site; used 2+ times → named PO field with.as('description')so failures point at a meaningful name.
- Raw JS → custom helper —
I.executeScriptblocks,usePlaywrightTodoing DOM walking or business logic, hand-rolled fetches inside Scenarios. Remember the fundamentals rule:Idoes not exist inside a helper — compose viathis.helpers['<Name>']. Tests stay in theI.*vocabulary. - Login duplication — don't build a
loginPage.signInmethod. Hand off tocodeceptjs-auth: that's what theauthplugin exists for. Login POs are a smell when session reuse applies. - Site-wide actions (
I.acceptCookies(),I.goToBilling()) — actor file (custom_steps.js), not any single page's PO. Right home when no single page owns the action.
Decision tree
| Pattern | Where it goes |
|---|---|
| UI flow on one page | Method on that page's PO |
| UI flow spanning pages, site-wide | Actor (custom_steps.js) |
| Login | auth plugin (see codeceptjs-auth) |
| Long locator carrying its own region | Short semantic locator + context arg |
| Long locator used once | locate() inline |
| Long locator used 2+ times | locate() stored as PO field |
| Raw browser API / file system / DB / mail | Custom helper |
| Test-data setup hitting an API | REST helper + Data Object |
Propose, then apply
Group proposals by destination file (pages/loginPage.js, helpers/DbHelper.js, tests/checkout_test.js). Show the list before editing. In global mode: explicit approval, batches of three to five files, re-run after each batch:
npx codeceptjs run --grep '<scenario or feature>' --steps
Hand output to codeceptjs-run-analysis — confirm every affected Scenario still passes and no failure shifted to a new step. Refactors that don't run aren't refactors.
Things to avoid
- Refactoring without re-running the affected Scenarios afterwards.
- Extracting a flow used only once — wait for the second occurrence.
- Renaming PO methods/fields without grepping every caller.
- A custom helper where a page object would do.
- Squashing distinct flows into one method (
loginPage.do(thing)is a smell). - Touching Scenario names or tags — CI and
--grepreference them. - Mass-applying in global mode without batching and re-running.
Related skills
codeceptjs-fundamentals— Main rule, Where things go, Architecture (I-unreachable rule)codeceptjs-auth— login deduplicationcodeceptjs-run-analysis— post-refactor verification