Migrate from Protractor to CodeceptJS
Start here: a dead dependency with an Angular wrapper
Section titled “Start here: a dead dependency with an Angular wrapper”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.
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.
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.
Comparison
Section titled “Comparison”The original test in Protractor:
// Protractor + Jasminedescribe('login', function () { it('user can log in', function () { browser.get('https://example.com/login'); element(by.model('user.email')).sendKeys('alice@example.com'); element(by.model('user.password')).sendKeys('secret'); element(by.css('button[type=submit]')).click(); expect(browser.getCurrentUrl()).toContain('/dashboard'); expect(element(by.css('.welcome')).getText()).toContain('Welcome, Alice'); });});Will look in CodeceptJS:
// CodeceptJSScenario('user can log in', ({ I }) => { I.amOnPage('/login'); I.fillField('Email', 'alice@example.com'); I.fillField('Password', 'secret'); I.click('Sign in'); I.seeInCurrentUrl('/dashboard'); I.see('Welcome, Alice', '.welcome');});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.
And here is how the test looks while it runs. Every step is printed live, in the same order it was written:
user can log in I am on page "/login" I fill field "Email", "alice@example.com" I fill field "Password", "secret" I click "Sign in" I see in current url "/dashboard" I see "Welcome, Alice", ".welcome"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.
Let an agent do the migration
Section titled “Let an agent do the migration”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.
The migrate-protractor-to-codeceptjs skill in the CodeceptJS skills bundle does the whole port:
- Inventories the page objects, shared helpers, and config hooks.
- Sets up CodeceptJS beside the Protractor suite.
- Ports the page objects and helpers.
- Converts each spec.
- Runs the full suite.
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.
Install the bundle in Claude Code:
/plugin marketplace add codeceptjs/skills/plugin install codeceptjs@codeceptjs-skillsOr any other agent:
npx skills add codeceptjs/skillsThen 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.
Pointers
Section titled “Pointers”- /agents for how the agent and MCP loop works
- /playwright for the recommended target helper
- /webdriver for the target if you keep a Selenium Grid
- /locators for semantic, ARIA,
locate(), and thecustomLocatorplugin - /pageobjects for ported Protractor page objects
- /auth for programmatic login and session reuse
- /api for the REST helper used in HTTP-call ports