E2E テスト規約(Playwright・EC-CUBE 4.4)
対象: e2e/tests/*.spec.ts, e2e/{pages,models,helpers,fixtures}/*.ts
前提: Playwright(TypeScript)。cd e2e && npm ci 済み。baseURL は環境変数 BASE_URL(既定 http://127.0.0.1:8000)。
EC-CUBE の E2E は
e2e/配下の Playwright が正。codeception/はレガシー残置で CI 無効(AGENTS.md参照)。 混同しないこと。
基本ルール
- spec ファイル名の接頭辞 = プロジェクト = 認証状態(
e2e/playwright.config.tsのtestMatch)。新規 spec はこの規則で命名する:admin-*/plugin-*… storageState=.auth/admin.jsonで管理者ログイン済み → spec 側でログイン不要。front-*/deny*… 空 state({ cookies: [], origins: [] })で未認証 → 会員操作は spec 内でログインするか、admin 経由で会員を作成する。
- 命名規約:
test.describe('… (EFxx)')(フロント)/(EAxx)(管理)。test 名はEF0401-UC01-T01 会員登録 …(機能ID-ユースケース-テストID + 日本語説明)。既存front-customer.spec.ts/admin-customer.spec.tsに倣う。 - 状態を引き継ぐ一連のテスト(create→search→edit→delete 等)は
test.describe.configure({ mode: 'serial' })を付ける。playwright.config.tsはworkers: 1/fullyParallel: false。 - テストデータは投入済み前提:
global-setup.tsがsetup-fixtures.phpを実行し、会員・商品・受注を投入する。固定会員playwright@test.test(ACTIVE)などを再利用し、新規作成データはメール等をnist_${Date.now()}@example.comのように一意化して衝突を避ける。 - パスは baseURL 相対(
page.goto('/entry'))。ホスト/ポートの直書きは禁止(環境差・ローカル/CI 差を吸収するため)。
実装パターン
- 認証: admin/plugin spec はログイン不要。認証フロー自体を検証するときだけ
test.use({ storageState: { cookies: [], origins: [] } })で上書きして毎回ログインする(admin-auth.spec.ts)。 - POM(Page Object Model):
tsconfig.jsonのパスエイリアスで import する。@pages/*… UI ページ単位の操作(例PluginManagePage)。static at(page)でページ到達を検証して返す。@models/*… 操作チェーン+DB/FS 検証(例StorePlugin.インストール()が UI 操作後にdb.getPlugin()で状態確認)。@helpers/*… 低レベル:db-client(テーブル/カラム/プラグイン状態)、file-helper(proxy への trait 注入確認)、tar-helper(プラグイン .tgz 圧縮)。
- plugin 系 spec は拡張 fixture(
e2e/fixtures/plugin-test.ts)の{ page, db, config }を test 引数で受け取る。 - 待機は web-first assertion を使う:
await expect(locator).toBeVisible()/toContainText()/page.waitForURL()。expect.timeout/actionTimeoutは 30s に設定済み。 - 入力ページ残留の判定は、確認画面でパスワードが hidden になる性質を使い、入力欄(例
#entry_plain_password_first)のtoBeVisible()で行う。
よくある間違い
- ❌
waitForTimeout(固定ms)で同期を取る → ✅ web-first assertion で「状態」を待つ。外部 JS 由来の待機だけ例外とし、理由をコメントに書く。 - ❌
front-*spec で管理者ログイン済みを前提にする → ✅ front は未認証 state。spec 内でログインするか admin 経由で会員作成する。 - ❌ 固定件数で assert(
検索結果:1件が該当)→ ✅ 正規表現(/検索結果:\d+件が該当/)。retry 時の重複データに強くする(admin-product.spec.ts修正例)。 - ❌ セレクタが複数要素にマッチ(strict mode violation)→ ✅
.first()かdata-*属性で一意化する。 - ❌ テスト境界で管理者セッションが切れて 401 → ✅
ensureAdminLoggedIn()等で再ログインしてから操作(admin-basicinfo.spec.ts修正例)。 - ❌ retry でプラグイン/データが残留し再失敗 → ✅
beforeEach/afterEachで cleanup(無効化 → 削除 → ディレクトリ削除)。 - ❌ パスワードを見た目の文字数で作る → ✅ NFKC 正規化後で 15 文字以上か数える(min15。
[...str.normalize('NFKC')].lengthで確認。#6488)。 - ❌ 新規 spec を作ったのに CI で実行されない → ✅
e2e-test.ymlのsuite:配列にファイル名(.spec.ts抜き)を追加する。
実行・確認方法
cd e2e && npm ci
# project は接頭辞で決まる。setup(ログイン/データ投入の前段)を併せて指定する
npx playwright test --project=setup --project=front-tests front-product.spec.ts
npx playwright test --project=setup --project=admin-tests admin-customer.spec.ts
npx playwright test --project=setup --project=plugin-tests plugin-install.spec.ts
CI 構造(spec 群ごとに担当ワークフローが分かれている):
e2e-test.yml…admin-*/front-*をmatrix.suiteで 1 ファイル = 1 シャード実行。新規 admin-/front- spec はここに追加。plugin-test.yml… plugin 系をnpx playwright test plugin-install --grep "${METHOD}"等で method 単位実行。e2e-test-throttling.yml…front-throttling.spec.tsを-g "${METHOD}"で実行。deny-test.yml…deny.spec.tsを実行。