mcpField
M
migrate-protractor-to-codeceptjs

migrate-protractor-to-codeceptjs

github.com/codeceptjsテスト・品質250 回インストール1 週間前に更新
リポジトリ

migrate-protractor-to-codeceptjs について

ProtractorのE2EテストをCodeceptJS 4へ移行するためのスキルです。プロジェクト調査、設定、共有ヘルパーやページオブジェクトの変換を案内し、扱いが変わる旧機能も示します。

主な機能

  1. 01Protractorプロジェクトの調査
  2. 02CodeceptJSへの設定マッピング
  3. 03WebDriverまたはPlaywrightの設定
  4. 04カスタムヘルパーの変換
  5. 05ページオブジェクト移行の指針
  6. 06旧動作の置き換え案内

活用シーン

  1. 01段階的なProtractor移行の計画
  2. 02Protractor設定の変換
  3. 03共有ヘルパーとページオブジェクトの移行
  4. 04Angular待機やPromiseチェーンの置き換え

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/codeceptjs/skills --skill migrate-protractor-to-codeceptjs

インストール後、Claude Code で/migrate-protractor-to-codeceptjsを入力して読み込まれたか確認します。

詳細

Protractor → CodeceptJS 4 への移行

Protractor は 2023 年 4 月にサポート終了となりました。CodeceptJS 4 は有力な移行先です。Protractor が基盤としていた WebDriver をネイティブに扱えるほか、より高速で不安定さが少なく、新規開発に推奨される Playwright もサポートしています。また、この移行により、Protractor 自体ですでに非推奨となっていた 3 つのレガシー機能、すなわち Selenium ControlFlow、Angular 同期フック(waitForAngular)、ブラウザー操作をキューに登録するための .then() プロミスチェーンも廃止できます。

押さえておくべき基本的な違いは 3 つあります。

  1. プロミスチェーンは不要です。 Protractor の .then() チェーンは Selenium ControlFlow に操作をキュー登録していました。CodeceptJS は内部レコーダーを介して I.* の呼び出しを自動でキューに登録するため、テストを同期的に記述できます。await が必要なのは値を取得するときだけです(await I.grabTextFrom(...))。
  2. browser / driver ではなくヘルパーを使います。 I.* は設定済みのヘルパーに処理を振り分けます。Playwright を推奨しますが、テストスイートを Selenium Grid 上で動かし続ける必要がある場合は WebDriver も利用できます。どちらを使ってもテストコードは同じです。
  3. Angular の待機ではなく、自動待機を使います。 browser.waitForAngular() と browser.ignoreSynchronization は削除します。Playwright と WebDriver のヘルパーは DOM と要素の安定性を待機するため、フレームワーク固有のフックがなくても Angular のレンダリングサイクルに対応できます。

信頼できるリファレンス:node_modules/codeceptjs/docs/(basics、locators、playwright、webdriver、custom-helpers、pageobjects)。

移行を開始する条件

以下のいずれかに該当する場合です。

  • リポジトリのルートに protractor.conf.{js,ts がある。
  • devDependencies に protractor が記載されている(多くの場合、@types/jasmine、jasmine、jasmine-spec-reporter も併せて記載されています)。
  • e2e/ または protractor/ ディレクトリにスペックファイルがある(一般的なファイル名は *.e2e-spec.{js,ts} または *.spec.{js,ts} です)。
  • protractor からインポートしている(browser、element、by、ExpectedConditions、ElementFinder、ElementArrayFinder)。
  • コード内で element(by.X(...))、element.all(...)、by.addLocator(...)、browser.get(...)、browser.executeScript(...)、browser.wait(EC.*)、browser.waitForAngular()、browser.ignoreSynchronization、browser.params.*、または browser.driver.* を呼び出している。
  • ユーザーが「Protractor から移行/ポート/変換」と述べている。

移行されないもの

事前に明確に伝えてください。

  • Selenium ControlFlow — 廃止されています。移行には、残っている ControlFlow 形式の処理順序を通常の async/await に変換する作業が含まれます。プロジェクトですでに SELENIUM_PROMISE_MANAGER が無効になっていた場合、ほとんどは機械的な変換です。有効なままだった場合は、暗黙の実行順序がないか、すべてのスペックを監査してください。
  • browser.waitForAngular() / browser.ignoreSynchronization / browser.waitForAngularEnabled(false) — 削除してください。CodeceptJS は DOM の安定性を自動で待機します。これは Angular に必要な処理でもあります。Angular の同期によって実際の競合状態が隠れていた場合、移行後にエラーが顕在化します。その場合は、具体的な I.waitFor* で対処してください。
  • Angular 固有のロケーター戦略 — by.binding(...)、by.repeater(...)、by.model(...)、by.options(...) に対応する CodeceptJS の組み込み機能はありません。CSS 属性セレクター({ css: '[ng-model="user.email"]' })に置き換えるか、広く使われている場合は WebExtra / customLocator にカスタムロケーター戦略を登録してください。
  • Jasmine のテスト基盤 — jasmineNodeOpts、カスタムマッチャー(jasmine.addMatchers)、jasmine-spec-reporter は対象外です。CodeceptJS は Mocha を使用します。マッチャーは ExpectHelper / codeceptjs/assertions に、レポーターは CodeceptJS プラグイン(@testomatio/reporter、mochawesome など)に置き換えます。
  • browser.params — 通常の process.env.* に置き換えます。Protractor の型付き params オブジェクトに相当するものはありません。

ワークフロー

各フェーズを順番に実行してください。回帰を二分探索できるよう、各段階の区切りでコミットしてください。

1. Protractor プロジェクトを棚卸しする

何かに手を加える前に、全体像を把握します。2 回に分けて確認します。

プロジェクトの構成 — コストの予測に役立つ項目を grep/wc -l で確認します。

  • protractor.conf.{js,ts} — 使用中のキー(seleniumAddress、directConnect、capabilities、baseUrl、specs、params、onPrepare、onComplete、framework、jasmineNodeOpts、allScriptsTimeout)
  • **/*.e2e-spec.{js,ts}(または e2e/ ディレクトリ内の **/*.spec.{js,ts})— スペック数
  • protractor のインポート — browser、element、by、ExpectedConditions を使用するすべてのファイル
  • .then(、by.addLocator(、browser.waitForAngular(、browser.executeScript(、browser.ignoreSynchronization、browser.params.、EC. の出現回数 — それぞれ既知の置き換えパターンに対応します。

共通ロジックとページオブジェクト — Protractor プロジェクトには、ほぼ必ず明示的なページオブジェクトパターンがあります(Protractor の公式ドキュメントでも推奨されている慣用パターンです)。スペックに手を加える前に見つけてください。

  • ページオブジェクト — 通常は e2e/page-objects/、e2e/pages/、e2e/po/、または e2e/<feature>/<feature>.po.ts の下にあります。element(by.X(...)) プロパティ(遅延評価される ElementFinder 参照)や操作を行うメソッドを持つクラス(またはプレーンオブジェクト)をエクスポートするモジュールです。これらは第一級の抽象化です。CodeceptJS のページオブジェクトにそのまま移行します。
  • カスタムロケーター — by.addLocator('<name>', fn) をすべて探します。通常は onPrepare またはヘルパーファイルにあります。それぞれを WebExtra のカスタムストラテジー、または customLocator プラグイン設定の項目にします。
  • ヘルパーモジュール — e2e/helpers/ または e2e/utils/ の下にあります。UI ヘルパー(DOM の操作、executeScript)は WebExtra に移し、HTTP ヘルパー(プログラムによるログイン、データのシード/後処理)は ApiExtras に移します。
  • onPrepare/onComplete フック — Protractor のグローバルなセットアップ/後処理です。単発のセットアップには codecept.conf.{js,ts} の bootstrap()/teardown() に移し、スイートごとのセットアップにはベーススペックの Before/BeforeSuite に移します。
  • Jasmine カスタムマッチャー — jasmine.addMatchers({ ... }) の定義は、codeceptjs/assertions ファクトリーを使ったカスタムヘルパー内の再利用可能なアサーションにします。

短い棚卸しリストを作成します。各共通抽象化の現在の場所と、CodeceptJS での移行先を記載してください。コードを書く前に、ユーザーが内容を確認します。

2. Protractor と並行して CodeceptJS をインストールする

npx codeceptjs init を実行し、Playwright ヘルパーを選択します(Selenium よりモダンで高速、かつ不安定さが少ないためです)。チームが Selenium Grid での実行を維持する必要がある場合に限り、代わりに WebDriver を選択してください。どちらを選んでもテストコードは同じです。Protractor はまだ削除しないでください。移行中は両方を並行して実行するため、半分しか変換されていないテストスイートでもカバレッジを維持できます。

3. 設定を移行する

protractor.conf.{js,ts} のキーを codecept.conf.{js,ts} に対応付けます。

ProtractorCodeceptJS 4(Playwright ヘルパー)
baseUrlhelpers.Playwright.url
capabilities.browserName(chrome/firefox)helpers.Playwright.browser(chromium/firefox/webkit)
capabilities.chromeOptions.argshelpers.Playwright.chromium.args/launchOptions.args
directConnect: true削除 — Playwright がブラウザーを管理します
seleniumAddress削除(Playwright の場合)、または helpers.WebDriver.host/port(WebDriver ヘルパーの場合)
specs: ['./e2e/**/*.e2e-spec.ts']tests: './tests/**/*_test.{js,ts}'
allScriptsTimeout/defaultTimeoutIntervalhelpers.Playwright.waitForTimeout、トップレベルの timeout
params: { ... }process.env.*
framework: 'jasmine'/jasmineNodeOpts削除 — CodeceptJS は Mocha を使用します
onPrepare(...)bootstrap()
onComplete(...)teardown()
SELENIUM_PROMISE_MANAGER: false削除 — CodeceptJS では async/await が必須です
useAllAngular2AppRoots/rootElement削除 — 不要です
4. 共通抽象化を移行する

ここが土台です。スペックを書き換える前に実施してください。必要な動詞(I.doSmth(...))がすでに用意されていれば、スペックの書き換え量はすべて少なくなります。 共有ヘルパーコードに関する厳格なルール。 Protractor ヘルパーモジュールのすべてのメソッドは、カスタム CodeceptJS ヘルパーのメソッドになります。操作の種類に応じて、2 つのヘルパーに分けてください — アクセス方法も適切な API も異なります。

  • WebExtra(lib/helpers/WebExtra.js)は、ブラウザー駆動の操作に使用します — 開いているページ、DOM、evaluate、初期化スクリプト、ストレージ、ネットワークレスポンスの待機などが必要な操作です。すべての browser.executeScript(...) 呼び出しはここに配置し、page.evaluate(...) に置き換えます。this.helpers['Playwright'].page / .browserContext にアクセスします。
  • ApiExtras(lib/helpers/ApiExtras.js)は、純粋な HTTP 操作に使用します — プログラムによるログイン、データのシード/ティアダウン、API に対する CRUD などです。this.helpers['REST'](または GraphQL)にアクセスします。REST ヘルパーの設定については、node_modules/codeceptjs/docs/api.md を参照してください。

codecept.conf.{js,ts} の helpers に両方のヘルパーを登録してください。

API 操作で this.helpers['Playwright'].browserContext.request.* を呼び出さないでください。 これは REST + JSONResponse のスタックを迂回するため、ステップのログ記録、I.seeResponseCodeIsSuccessful アサーション、共有ヘッダーが利用できません。API でブラウザーと同じ認証が必要な場合は、設定の最初に一度だけ Cookie を共有してください。

import { setSharedCookies } from '@codeceptjs/configure'
setSharedCookies()

…または、トークンベースの認証には REST ヘルパーで defaultHeaders を設定するか、テストごとに I.amBearerAuthenticated(secret(token)) を使用してください。これら 3 つの方法はすべて api.md で説明しています。

WebExtra の例 — 正式な browser.executeScript → page.evaluate への置き換えを含む、ブラウザー駆動の操作:

import Helper from '@codeceptjs/helper'

export default class WebExtra extends Helper {
  async setLocalStorage(key, value) {
    const { page } = this.helpers['Playwright']
    await page.evaluate(([k, v]) => localStorage.setItem(k, v), [key, value])
  }

  async scrollIntoView(selector) {
    const { page } = this.helpers['Playwright']
    await page.locator(selector).scrollIntoViewIfNeeded()
  }

  async waitForAngularRouterEvents(timeout = 10000) {
    const { page } = this.helpers['Playwright']
    await page.waitForFunction(
      () => !document.querySelector('.cdk-overlay-backdrop, .mat-progress-bar'),
      { timeout },
    )
  }
}

ApiExtras の例 — REST ヘルパー経由で実行する、純粋な HTTP 操作:

import Helper from '@codeceptjs/helper'

export default class ApiExtras extends Helper {
  async loginViaApi(email, password) {
    const REST = this.helpers['REST']
    await REST.sendPostRequest('/api/auth/login', { email, password })
  }

  async seedUser(user) {
    const REST = this.helpers['REST']
    const { data } = await REST.sendPostRequest('/api/users', user)
    return data
  }
}

ヘルパーコードのスタイル — どちらのヘルパーにも適用されます。

  • すべての import 文はファイルの先頭に置きます。メソッド内で const fs = await import('node:fs/promises') のように記述しないでください。
  • 組み込みアサーション(API には I.seeResponseCodeIsSuccessful、ブラウザーには I.seeElement)、ExpectHelper、または codeceptjs/assertions のファクトリーを使用してください — if (cond) throw new Error('...') は使用しないでください。失敗は適切なアサーションエラーとして表示される必要があります。node_modules/codeceptjs/docs/assertions.md を参照してください。

カスタムロケーター戦略(by.addLocator)— 移行先は 2 つあります。

  • 単純な属性戦略(内部で CSS / XPath に変換されるもの)→ customLocator プラグインを有効にし、各戦略を設定します。有効にすると、I.click('$submit') で submit 戦略が解決されます。
  • 複雑な戦略(DOM に対して JavaScript を実行するもの)→ 一致した要素を返す WebExtra のメソッドと、必要に応じて薄い I.click* / I.see* ラッパーを作成します。

フェーズ 1 のインベントリにあるその他の移行先:

  • Protractor のページオブジェクト → pages/ 配下の CodeceptJS ページオブジェクトクラス。慎重に移植してください — 元のページオブジェクトにあったメソッドだけを残し、移行時に新しいラッパーを作らないでください。ElementFinder プロパティ(get usernameField() { return element(by.id('user')) })は、ロケーター文字列のフィールド(fields = { usernameField: '#user' })になります。メソッドは先頭で const { I } = inject() を呼び出すように書き換え、I.fillField、I.click と、WebExtra / ApiExtras ヘルパーが提供する I.* の動詞を呼び出します。codecept.conf.{js,ts} の include に登録すると、ページオブジェクトが Scenarios に自動で注入されます。

    避けるべきページオブジェクトのアンチパターン(元の Protractor ページオブジェクトにすでに含まれていた場合を除く):

    • アサーションメソッド(checkTitle() { I.seeElement(...) }) — ページオブジェクトにはアクション動詞(fillForm、submitOrder)を置き、アサーションはテスト内に記述してください。
    • 単一の I.click / I.see* / I.grabTextFrom を囲む一行だけのラッパー — テストから I.* を直接呼び出す方が簡潔です。
    • 1 つのテストだけで使用されるメソッド — 手順はテスト内に記述してください。
    • いずれかのメソッドでの if (cond) throw new Error(...) — 代わりに I.see*、I.seeNumberOfElements、ExpectHelper、または codeceptjs/assertions のファクトリーを使用してください。
  • 共有セレクター定数 → 該当するページオブジェクトのフィールドにします。独立した selectors.{js,ts} は作成しません。

  • ブラウザーに触れない 純粋なユーティリティモジュール → プレーンな ES モジュールにし、必要な場所でインポートします。

  • onPrepare / onComplete → codecept.conf.{js,ts} の bootstrap / teardown にするか、作業がスペック単位の場合は BeforeSuite / AfterSuite にします。

次に進む前の健全性チェック:npx codeceptjs check -c <config> が成功し、npx codeceptjs list -c <config> に、移植したすべてのヘルパーメソッドが WebExtra または ApiExtras によって追加された I.* アクションとして表示されることを確認します。

5. スペックファイルを変換する

フェーズ 4 の抽象化を活用しながら、1 ファイルずつ進めます。スペックごとの作業は writing-codeceptjs-tests スキルに引き継ぎます。このスキルは MCP 経由で実際のブラウザーを操作し、コミット前に各ステップを検証します。

ProtractorCodeceptJS 4
ファイル *.e2e-spec.{js,ts}*_test.{js,ts}
describe('X', () => { ... })ファイルの先頭に Feature('X')。1 ファイルにつき Feature は 1 つ
it('Y', () => { ... })Scenario('Y', ({ I }) => { ... })
beforeEach(() => { ... })Before(({ I }) => { ... })
afterEach(() => { ... })After(({ I }) => { ... })
beforeAll(...) / afterAll(...)BeforeSuite(...) / AfterSuite(...)
browser.get('/x')I.amOnPage('/x')
await loginPage.login(u, p)loginPage.login(u, p)(アクションをラップする void のページオブジェクトメソッドには await を付けません)

browser.waitForAngular() / browser.ignoreSynchronization は、すべての呼び出し箇所で完全に削除します。 CodeceptJS が自動で待機します。

Promise チェーン — アクションはレコーダーがキューに入れるため、ほとんどの .then(...) チェーンは通常のステートメントに置き換えられます。await は grab にのみ使用します。

const text = await I.grabTextFrom('.foo')
I.expectEqual(text, 'Hello')

反復処理 — テスト、ページオブジェクト、ヘルパーでは、I.* 呼び出しを含むループに for...of を使用します。Array.prototype.forEach は使用しないでください。.forEach は反復コールバックの戻り値を無視するため、その中の await は外側の関数をブロックしません。その結果、レコーダーがステップを順不同でキューに入れたり、ループの完了前に Scenario を終了したりすることがあります。for...of ならループを順次実行でき、書き換えずに後から await を追加できます。

for (const sort of testSort) {
  I.click(locate(this.filterFormLabel).withText(sort))
}
for (const row of await I.grabWebElements('.row')) {
  const text = await row.getText()
  I.expectNotEmpty(text)
}

バッチごとに:npx codeceptjs dry-run --steps -c <config> を実行します。すべての Scenario を読み込み、すべての I.* 呼び出しを解決しますが、ブラウザーは起動しません。タイプミス、インポート漏れ、include に含まれていないページオブジェクト、存在しない動詞を数秒で検出できます。実際の実行に進む前に修正してください。

次に、バッチを実行します:npx codeceptjs run --steps -c <config>。

  • 最初の実行はほぼ必ず失敗します。ロケーターのずれ、ControlFlow が独自のキュー処理の背後に隠していたタイミングの問題、認証やセッションの違い、データに関する前提などが原因です。これは想定内であり、修正も移行作業の一部です。
  • 失敗するたびに debugging-codeceptjs-tests を呼び出し、その場で修正します(ブレークポイント、実際のページの検査、修正の検証)。やみくもな書き換えや、問題を覆い隠す retry は使いません。
  • バッチの完了条件は、ドライランの成功ではなく、実行がすべて成功することです。
6. ロケーターの優先順位

すべてのロケーターにコンテキストを指定します。 各アクションの最後の引数で検索対象の領域を絞り込みます — I.click('Save', '.toolbar')、I.fillField('Email', '[email protected]', '#login-form')、I.click({ role: 'button', name: 'Delete' }, '.modal')。短いセマンティックロケーターやARIAロケーターにコンテキストを加えるほうが、長くて範囲を絞らないロケーターより適切です。ページに沿った記述になり、重複するラベルを長くせずに区別でき、マークアップの変更にも強くなります。以下の表のすべての行に適用してください — 変換元フレームワークのチェーンは通常、領域 と ユーザーに見える要素 にすっきり分割できます。

CodeceptJS の優先順位 — 適合するもののうち最も上位を選び、コンテキストを加えます。

  1. セマンティック文字列 — ボタンテキスト、ラベル、プレースホルダー、リンクテキスト:I.click('Save', '.toolbar')、I.fillField('Email', '[email protected]', '#login-form')。Protractor の by.linkText、by.buttonText、by.partialButtonText、by.partialLinkText にそのまま対応します。 通常の文字列はすでに aria-label にも一致するため、aria-label="Save" を持つアイコンのみのコントロールには I.click('Save', <context>) を使います — 'aria-label=Save' や { css: '[aria-label="Save"]' } は使わないでください。
  2. ARIA ロール — I.click({ role: 'button', name: 'Sign In' }, '#login-form')。Material や ARIA に準拠したコンポーネントを採用する Angular アプリでは、強力なデフォルトの選択肢です。
  3. customLocator プラグイン経由の $name — アプリが要素に data-qa / data-test を付与する場合に使います。呼び出し箇所ごとに属性セレクターを繰り返すより適しています。
  4. locate() ビルダー — I.click(locate('.row').withText('Acme').inside('table'))。by.cssContainingText と要素のトラバーサルチェーンに相当します — ただし、通常は I.click('Edit', locate('tr').withText('Acme')) のように分けるほうが適切です。
  5. CSS / XPath / 属性オブジェクト — { id: 'foo' }、{ name: 'email' }、{ css: '[ng-model="user.email"]' }、{ xpath: '//div[@id="x"]' }。Angular のディレクティブ属性には、この方法を代替手段として使います。
Protractor ロケーターCodeceptJS 4
by.css('.btn')'.btn'
by.id('foo'){ id: 'foo' }
by.name('email'){ name: 'email' }
by.tagName('input'){ css: 'input' }
by.linkText('Sign In')'Sign In'(セマンティック)
by.partialLinkText('Sig')'Sig'(セマンティック、デフォルトで部分一致)
by.buttonText('Submit')'Submit'(セマンティック)
by.partialButtonText('Sub')'Sub'(セマンティック)
by.xpath('//div[@id="x"]'){ xpath: '//div[@id="x"]' }
by.cssContainingText('.row', 'Acme')locate('.row').withText('Acme')
by.binding('user.name'){ css: '[ng-bind="user.name"]' } またはカスタムロケーター
by.model('user.email'){ css: '[ng-model="user.email"]' }
by.repeater('item in items'){ css: '[ng-repeat="item in items"]' }
by.options('opt for opt in options'){ css: '[ng-options="opt for opt in options"]' }
by.addLocator('myLocator', fn)customLocator プラグイン、または WebExtra のメソッド

要素のトラバーサル — Protractor のチェーン(element(...).element(...)、.all(...)、.first()、.get(N))は、CodeceptJS のコンテキスト引数、locate() チェーン、step.opts に置き換えられます。

ProtractorCodeceptJS 4
element(by.X)ロケーター単独('.foo'、{ role: ... } など)
element.all(by.X)await I.grabWebElements(sel)
element.all(by.X).count()(アサーション)I.seeNumberOfElements(sel, N)
element.all(by.X).first()step.opts({ elementIndex: 'first' })(または 1)
element.all(by.X).last()step.opts({ elementIndex: 'last' })
element.all(by.X).get(N)step.opts({ elementIndex: N + 1 })
element(by.X).element(by.Y)コンテキスト引数:I.click(Y, X) — または locate(Y).inside(X)
element(by.X).$('.foo')同様

step.opts(...) は import step from 'codeceptjs/steps' からインポートします。

7. アクション、アサーション、値の取得
ProtractorCodeceptJS 4
element(sel).click()I.click(sel)
element(sel).sendKeys('x')I.fillField(sel, 'x')
element(sel).clear()I.clearField(sel)
element(sel).submit()I.click('Submit', form) or I.pressKey('Enter')
element(sel).getText().then(...)const t = await I.grabTextFrom(sel)
element(sel).getAttribute('data-id')await I.grabAttributeFrom(sel, 'data-id')
element(sel).isDisplayed() (asserted)I.seeElement(sel)
element(sel).isPresent() (asserted)I.seeElementInDOM(sel)
expect(element(sel).getText()).toEqual('X')I.see('X', sel)
expect(element.all(sel).count()).toBe(N)I.seeNumberOfElements(sel, N)
expect(browser.getCurrentUrl()).toContain('/x')I.seeInCurrentUrl('/x')
browser.executeScript(fn, args)inside a helper: await page.evaluate(fn, args)
browser.refresh()I.refreshPage()
browser.getCurrentUrl()await I.grabCurrentUrl()
browser.getTitle()await I.grabTitle()
browser.sleep(N)I.wait(N / 1000) — CodeceptJS は 秒 を使用します。コミットするテストでは、そのままの待機を避けてください
browser.wait(EC.visibilityOf(el), 5000)I.waitForVisible(sel, 5)
browser.wait(EC.invisibilityOf(el), 5000)I.waitForInvisible(sel, 5)
browser.wait(EC.presenceOf(el), 5000)I.waitForElement(sel, 5)
browser.wait(EC.textToBePresentInElement(el, 'X'), 5000)I.waitForText('X', 5, sel)
browser.wait(EC.urlContains('/x'), 5000)I.waitInUrl('/x', 5)
browser.waitForAngular()削除
browser.params.userprocess.env.USER

await を付けるのは値の取得処理だけです。通常のアクションは自動的にキューに追加されます。

8. セッションと認証

Protractor にはセッションを再利用する標準機能がありませんでした。ほとんどのプロジェクトでは、各 beforeEach で UI からログインするか、簡便な方法として browser.driver.manage().addCookie(...) を直接呼び出していました。どちらも auth プラグイン に置き換えてください。設定手順については codeceptjs-auth を参照してください。フェーズ 4 ですでにログイン処理を ApiExtras の I.loginViaApi(...) または WebExtra の I.login(...) に移植している場合、auth プラグインのロール定義からその処理を呼び出すだけです。複数ユーザーのシナリオ(Protractor には標準の同等機能がありませんでした)では、codeceptjs/effects の session(...) を使用してください。

9. フィクスチャ、リクエスト、タスク
ProtractorCodeceptJS 4
require('./fixtures/users.json')import users from './fixtures/users.json' with { type: 'json' }
http.request(...) inside onPrepareREST ヘルパー経由の await I.sendPostRequest(...)。再利用可能なフローはフェーズ 4 の ApiExtras ヘルパーでラップしてください
protractor-cucumber-framework / Cucumber hooksCodeceptJS BDD(gherkin:steps)または通常の bootstrap / teardown

REST ヘルパーの認証:@codeceptjs/configure の setSharedCookies() はブラウザーのセッションを REST と共有するため、両方で同じユーザーがログインした状態になります。別の方法として、静的トークンには defaultHeaders を設定するか、テストごとに I.amBearerAuthenticated(secret(token)) を使用してください。node_modules/codeceptjs/docs/api.md を参照してください。

10. ネットワークのモック

Protractor にはネットワークインターセプト機能が組み込まれていませんでした。通常、プロジェクトでは browser.executeScript で XMLHttpRequest にパッチを適用するか、バックエンドのスタブを使って独自に対応していました。Playwright ベースの CodeceptJS への移行では、代わりに I.mockRoute(url, route => route.fulfill({ ... })) を使用するか、I.stopMockingRoute(url) で無効にしてください。node_modules/codeceptjs/docs/playwright.md § ネットワークリクエストのモックを参照してください。

11. Protractor の廃止

すべての spec の移植が完了し、CI が正常に動作するようになってから、e2e/(または Protractor の spec を配置していたディレクトリ)、protractor.conf.* を削除し、devDependencies から protractor、@types/jasmine、jasmine、jasmine-spec-reporter を削除してください。また、Protractor の CI ジョブを削除し、対応する Chrome / Selenium webdriver-manager のバイナリをアンインストールしてください。

検証

  1. npx codeceptjs check -c <config> — config、ヘルパー、プラグインの整合性を確認します。
  2. npx codeceptjs list -c <config> — 移植したすべてのヘルパーメソッドが、WebExtra または ApiExtras の I.* アクションとして表示されること、およびすべてのページオブジェクトのメソッドが表示されることを確認します。
  3. npx codeceptjs dry-run --steps -c <config> — すべての Scenario が読み込まれることを確認します。
  4. 全テストを実行します:npx codeceptjs run --steps -c <config>。初回の実行では失敗が予想されます。debugging-codeceptjs-tests スキルを使って、各失敗を修正してください(retry や、根拠のない書き直しはしないでください)。変換後のテストスイート全体が成功して初めて、移行は完了です。
  5. codeceptjs-run-analysis に引き継ぎ、output/trace_*/ の成果物を調べてもらいます(aiTrace プラグインを有効にする必要があります)。
  6. grep -rE "\\bbrowser\\.|\\bby\\.|\\.then\\(|waitForAngular" e2e/ — e2e/ を削除する前に、結果が空であることを確認します。

関連スキル

  • writing-codeceptjs-tests — spec ごとの書き換え手順(MCP を活用した、検証済みの手順)
  • debugging-codeceptjs-tests — 初回の全テスト実行から、失敗したテストすべてに使用します
  • codeceptjs-auth — すべての beforeEach での UI 再ログインや、手動での Cookie 注入を置き換えます
  • codeceptjs-fundamentals — 移行後に実行し、配線を確認します
  • 参考ドキュメント:node_modules/codeceptjs/docs/(basics、playwright、webdriver、locators、custom-helpers、api、assertions、pageobjects、sessions、effects)

コメント