ローカルの開発環境では、一般的に「開発用DB」と「テスト用DB」を分けて運用します。テストのリセット処理(migrate:freshなど)によって開発中のデータまで消えてしまったり、予期せず書き換わってしまうことがあるからです。Playwrightでも同様に、同じ環境でテストするならDBを分けておくのがベストです。今回は、開発DBとテストDBの切り替え手順について解説します。
プロジェクトの構成
今回の記事で扱うPlaywrightは、Laravelプロジェクトの中にe2eディレクトリとして存在しており、以下のような構成になっています。
laravel-project/
├── app/
├── …
└── e2e/(Playwright)
そして今回はDBだけではなく、それぞれの環境が干渉しないようサーバのポートも以下のように使い分けることにします。
ローカルの開発環境:8000
Playwrightの実行環境:8001
ではここから設定を進めていきます。
順を追って進めるためconfigファイルが複数回に分けて登場しますが、最後にconfigの全体もご紹介します。
.env.playwright
まずは.env.playwrightを作成します。以下のように最小限に内容のみ記載します。
APP_ENV=playwright DB_DATABASE=database/playwright.sqlite
APP_ENVは今回の設定上必須ではありませんが、Laravelの動作中localと認識されないように環境をplaywrightと明示しておきます。そしてplaywright用のDBとして、今回はsqliteを使用します。
gitignoreに追加することもお忘れなく。
・・・・・ .env.playwright
.env.playwrightをconfigファイルに追加
次に、作成した.env.playwrightをplaywright.config.tsに追加します。(TypeScriptの記述となっています)
import { defineConfig, devices } from '@playwright/test';
import dotenv from 'dotenv';
import { fileURLToPath } from 'url';
import path from 'path';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// .env を読み込んだあと、.env.playwright で差分を上書き
dotenv.config({ path: path.resolve(__dirname, '.env') });
dotenv.config({ path: path.resolve(__dirname, '.env.playwright'), override: true });
・・・・・
dotenv.config()を使用して.envと.env.playwrightの両方を読み込んでいます。その際.env → .env.playwrightの順で読み込み、後者で上書きする形としています。そうすることで.env.playwrightの記述は最低限の変更箇所のみで済みます。
環境にdotenvがインストールされていない場合はテスト実行時にコケてしまうので、以下のコマンドでインストールしておいてくださいね。
$ npm install dotenv
Playwright用のSeeder
次にSeederを作成します。Laravelプロジェクトならすでに存在しているであろうDatabaseSeederはユニットテストで使用するため、Playwright専用のSeederを作成することにします。
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
class PlaywrightSeeder extends Seeder
{
public function run(): void
{
$user = User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
]);
$this->callWith(FavoriteFoodSeeder::class, ['user' => $user]);
$this->callWith(MealSeeder::class, ['user' => $user]);
}
}
ユーザーと、ユーザーに紐づく食事データなどの基本情報を作成するシンプルな内容となっています。
Seeder実行ファイルの作成と設定
次に、作成したSeederを実行するためのセットアップファイルを作成します。ファイル名はなんでも良いですが、今回はdb.setup.tsとしました。
import { test as setup } from '@playwright/test';
import { execSync } from 'child_process';
import { existsSync, writeFileSync } from 'fs';
setup('reset database', async () => {
// SQLiteファイルが存在しない場合は作成する
if (!existsSync('database/playwright.sqlite')) {
writeFileSync('database/playwright.sqlite', '');
}
execSync('php artisan migrate:fresh --seeder=PlaywrightSeeder', { stdio: 'inherit' });
});
setup()を使用して、その中に実行内容を定義します。第1引数に指定している文字列はテスト実行後のHTMLレポートに表示されるので、何をしているのかわかるような内容にしたほうが良いです。
そしてexecSync()を使ってartisanコマンドを実行します。先ほどconfigファイルで設定した.env.playwrightの情報を元に実行されますので、マイグレーションはテスト用DBであるdatabase/playwright.sqliteに対して行われます。
また{ stdio: 'inherit' }を指定することで、マイグレーション実行時の進捗状況や、成功・エラーメッセージがターミナルに表示されるようになります。
DBセットアップファイルをconfigファイルで読み込む
再びplaywright.config.tsに戻ります。先ほど作成したdb.setup.tsをconfigファイルのprojectsに追加します。
少しわかりにくいので、追加前の該当部分を先にお見せします。もともとは以下のように「setup(認証情報のセットアップ)」と、「chromium(ブラウザテスト)」の2つのプロジェクトがありました。
・・・・・
projects: [
// Setup project for authentication
{ name: 'setup', testMatch: '**/auth.setup.ts' },
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
// Use prepared auth state.
storageState: 'playwright/.auth/user.json',
},
dependencies: ['setup'],
},
],
・・・・・
ここにDBのセットアッププロジェクトを追加すると、以下のようになります。
・・・・・
projects: [
// DB reset and seeding
{ name: 'db-setup', testMatch: '**/db.setup.ts' }, // ここを追加
// Setup project for authentication
{ name: 'setup', testMatch: '**/auth.setup.ts', dependencies: ['db-setup'] }, // ここを追加
{
name: 'chromium', // ここは変更なし
use: {
...devices['Desktop Chrome'],
// Use prepared auth state.
storageState: 'playwright/.auth/user.json',
},
dependencies: ['setup'],
},
],
・・・・・
追加したのは{ name: 'db-setup', testMatch: '**/db.setup.ts' },の行と、setupプロジェクトへの依存関係dependencies: ['db-setup'] の部分です。
元からあったchromiumプロジェクトにも依存関係dependencies: ['setup']がありますので、今回の変更により、テスト開始時の実行順序は以下のようになります。
- db-setup:まずDBをリセットしてデータを投入する
- setup:DBの準備が整ったあとで、ログイン認証を行い状態を保存する
- chromium:全ての準備(DBと認証)が終わったあとで、実際のテストを開始する
webServerの設定
最後は、テスト用サーバを起動するための設定です。
Playwrightには、テスト開始時に自動でローカルサーバを立ち上げてくれるwebServerという機能があります。これを利用して、開発用の8000番とは異なるテスト専用ポートの8001番でアプリを起動するようconfigファイルを編集します。
・・・・・
export default defineConfig({
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: 'http://127.0.0.1:8001',
・・・・・
},
webServer: {
command: 'php artisan serve --port=8001',
url: 'http://127.0.0.1:8001',
reuseExistingServer: !process.env.CI,
stdout: 'ignore',
stderr: 'pipe',
},
});
useセクションのbaseURLを、ポート8000から8001に変更。そしてwebServerセクションを新規に追加しました。webServerでは以下のような項目を設定しています。
- command:テスト開始前に実行するシェルコマンドを指定
- url:サーバーの起動完了を判定するためのURL(このURLにアクセス可能になるまでテストを待機)
-
reuseExistingServer:すでにサーバーが起動している場合の挙動を制御(
!process.env.CIとすることで、ローカルなどCI以外の環境の場合、既存サーバーがあれば再利用、無ければ起動する、という動作になる) -
stdout:通常ログの出力設定(
ignoreを指定すると、正常時のログは表示しない) -
stderr:エラーログの出力設定(
pipeを指定すると、起動失敗やエラー時のみターミナルに表示)
このようにwebServerを設定しておくことで、テスト用サーバーを手動でオン・オフにする必要がなく、またテスト中に意図しない開発用DBに接続してしまう危険を回避できます。
これでテスト環境とのDB分離・リセットの設定が完了しました!
最終的なplaywright.config.ts
ここまでの設定を反映した、最終的なplaywright.config.tsは以下のようになります。
import { defineConfig, devices } from '@playwright/test';
import dotenv from 'dotenv';
import { fileURLToPath } from 'url';
import path from 'path';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// .env を読み込んだあと、.env.playwright で差分を上書き
dotenv.config({ path: path.resolve(__dirname, '.env') });
dotenv.config({ path: path.resolve(__dirname, '.env.playwright'), override: true });
/**
* Playwright E2E Test Configuration
* @see https://playwright.dev/docs/test-configuration
*/
export default defineConfig({
testDir: './e2e',
/* Run tests in files in parallel */
fullyParallel: false,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
// workers: process.env.CI ? 1 : undefined,
workers: 1,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: 'http://127.0.0.1:8001',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
/* Screenshot on failure */
screenshot: 'only-on-failure',
/* Video on failure */
video: 'retain-on-failure',
},
/* Configure projects for major browsers */
projects: [
// DB reset and seeding
{ name: 'db-setup', testMatch: '**/db.setup.ts' },
// Setup project for authentication
{ name: 'setup', testMatch: '**/auth.setup.ts', dependencies: ['db-setup'] },
// Authenticated tests
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
// Use prepared auth state.
storageState: 'playwright/.auth/user.json',
},
dependencies: ['setup'],
},
],
/* Run your local dev server before starting the tests */
webServer: {
command: 'php artisan serve --port=8001',
url: 'http://127.0.0.1:8001',
reuseExistingServer: !process.env.CI,
stdout: 'ignore',
stderr: 'pipe',
},
});
メルマガ購読の申し込みはこちらから。
