Contents
はじめに
@wordpress/scripts
のバージョン26.13.0で、Playwright がサポートされました。そこでこの記事では、ブロック開発における Playwright を使用した簡単な e2e テストの導入方法をご紹介します。
注意事項
この記事は、@wordpress/scripts
のバージョン26.16.0で検証しています。バージョンが26.13.0~26.15.0の場合は、「(補足) コンフィグファイルの準備」セクションをご覧ください。
ブロックの雛形を作る
@wordpress/create-block
を使って、ブロックを一つ持つプラグインの雛形を作成します。ついでにローカル環境も立ち上げられるように、--wp-env
オプションを追加しておきます。
npx @wordpress/create-block playwright-test --wp-env
ローカル環境を起動
npm run env start
とりあえず、ブロックを挿入出来る事を確認します。
デフォルトでは決まったテキストしか表示されないので、中のテキストを編集可能な仕様に変更します。
{
...
"attributes": {
"content": {
"type": "string",
"source": "html",
"selector": "p"
}
},
...
}
import {
RichText,
useBlockProps,
} from '@wordpress/block-editor';
export default function Edit( { attributes, setAttributes } ) {
const { content } = attributes;
return (
<RichText
tagName="p"
{ ...useBlockProps() }
value={ content }
onChange={ ( newContent ) =>
setAttributes( { content: newContent } )
}
/>
);
}
import { RichText, useBlockProps } from '@wordpress/block-editor';
export default function save( { attributes } ) {
const { content } = attributes;
return (
<p { ...useBlockProps.save() }>
<RichText.Content value={ content } />
</p>
);
}
あらためてビルドしてみます。これで、挿入したブロックのテキストが編集・保存可能になっているはずです。
npm run build
Playwright の準備
最新の @wordpress/scripts
をインストールしている時点で必要なライブラリは依存関係に入っているので、特に新しく npm パッケージを入れる必要はありません。
$ npm ls @playwright/test
playwright-test@0.1.0 /home/username/projects/playwright-test
└─┬ @wordpress/scripts@26.16.0
├── @playwright/test@1.39.0
└─┬ @wordpress/e2e-test-utils-playwright@0.13.0
└── @playwright/test@1.39.0 deduped
$ npm ls @wordpress/e2e-test-utils-playwright
playwright-test@0.1.0 /home/wildworks/projects/playwright-test
└─┬ @wordpress/scripts@26.16.0
└── @wordpress/e2e-test-utils-playwright@0.13.0
e2e テストを実行するためのスクリプトを登録
{
...
"scripts": {
"test:e2e": "wp-scripts test-playwright",
"test:e2e:debug": "wp-scripts test-playwright --debug"
}
...
}
@wordpress/scripts
は Playwright 用のデフォルトのコンフィグファイルを持っているため、e2e テストを実行するための準備はこれで完了です。
注: @wordpress/scripts
のバージョンが26.13.0~26.15.0の場合は、「(補足) コンフィグファイルの準備」セクションをご覧ください。
テストファイルはまだないですが、一旦ここで Playwright による e2e テストを実行してみます。
npm run test:e2e
> playwright-test@0.1.0 test:e2e
> wp-scripts test-playwright
Error: No tests found
テストが見つからないよというメッセージは出ましたが、とりあえずエラーなく動作する事は確認出来ました。
ここでは、デフォルトのコンフィグファイルの上書きを試してみるために、テストで参照するディレクトリをデフォルトの specs
から tests/e2e
ディレクトリをに変更してみます。
import { defineConfig } from '@playwright/test';
const baseConfig = require( '@wordpress/scripts/config/playwright.config.js' );
const config = defineConfig( {
...baseConfig,
testDir: './tests/e2e',
} );
export default config;
テストを書く
実際に簡単なテストを書いてみます。まずは、カスタムブロックがちゃんとエラーなく挿入されることを確認しています。
import { test, expect } from '@wordpress/e2e-test-utils-playwright';
test.describe( 'Block', () => {
test.beforeEach( async ( { admin } ) => {
// それぞれのテストの前に新しい投稿を作成する
await admin.createNewPost();
} );
test( 'should be created', async ( { editor } ) => {
// ブロックを挿入する
await editor.insertBlock( { name: 'create-block/playwright-test' } );
// 投稿コンテンツがスナップショットと一致する事をテストする
expect( await editor.getEditedPostContent() ).toMatchSnapshot();
} );
} );
e2e テストを実行します。
npm run test:e2e
はじめて実行した時はスナップショットがないので、以下のようなエラーが表示され失敗するはずです。
Error: A snapshot doesn't exist at /home/username/projects/playwright-test/tests/e2e/__snapshots__/Block-should-be-created-1-chromium.txt, writing actual.
代わりに、以下の内容でスナップショットが作成されます。このスナップショットはカスタムブロックがちゃんと挿入された事をあらわしているので、期待したスナップショットです。
tests/e2e/__snapshots__/Block-should-be-created-1-chromium.txt
<!-- wp:create-block/playwright-test -->
<p class="wp-block-create-block-playwright-test"></p>
<!-- /wp:create-block/playwright-test -->
もう一度 e2e テストを実行します。
npm run test:e2e
今度はテストが成功するはずです。
$ npm run test:e2e
> playwright-test@0.1.0 test:e2e
> wp-scripts test-playwright
Running 1 test using 1 worker
✓ 1 [chromium] › test.spec.js:9:6 › Block › should be created (2.2s)
1 passed (3.1s)
テストをデバッグする
デバッグモードでテストを実行してみます。これは複雑なテストを書く時に、期待した通りに操作が行われているかをトレースする時に便利だと思います。
npm run test:e2e:debug
以下のように、二つのウィンドウが立ち上がるはずです。小さいほうのウィンドウのステップオーバーボタンを一度クリックしてください。
ステップオーバーボタンを押す度に、期待通りにテスト手順が実行されるのが分かります。
新しいテストを書く
今回のカスタムブロックは、中のテキストを編集可能な仕様に変更しているので、「変更したテキストが正しく反映されているか」を確認するためのテストを書いてみます。
test.describe( 'Block', () => {
// ...
test( 'should be updated the content', async ( { editor, page } ) => {
// ブロックを挿入する
await editor.insertBlock( { name: 'create-block/playwright-test' } );
// ブロックの中のテキストを更新する
await page.keyboard.type( 'Hello World!' );
// 投稿コンテンツがスナップショットと一致する事をテストする
expect( await editor.getEditedPostContent() ).toMatchSnapshot();
} );
} );
二つ目の新しいテストが失敗してスナップショット作成されますが、期待したスナップショットであるはずです。
<!-- wp:create-block/playwright-test -->
<p class="wp-block-create-block-playwright-test">Hello World!</p>
<!-- /wp:create-block/playwright-test -->
終わりに
@wordpres/scripts
が Playwright をサポートした事で、ブロック開発においてこれまでより簡単に e2e テストを行えるようになったと思います。また、 @wordpress/e2e-test-utils-playwright
は便利なユーティリティを多数持っています。具体的な使用例は、Gutenberg プロジェクトの e2e テストを見てみると良いと思います。
(補足) コンフィグファイルの準備
ハンドブックによると、「Playwright を起動するための最適な構成を自動的に検出する」とありますが、この issue で報告されている通り、@wordpress/scripts
のバージョンによっては明示的にコンフィグファイルを用意する必要があります。この問題を解決するプルリクエストは既にマージされていますが、このプルリクエストは @wordpress/scripts
のバージョン26.16.0の一部であるため、バージョンが26.13.0~26.15.0の場合は、以下のようなコンフィグファイルを定義する必要があります。
@wordpress/scripts
のデフォルトコンフィグを踏襲しつつ、動作させるために globalSetup
プロパティを上書きします。テストで参照するディレクトリも変更しています。
import { defineConfig } from '@playwright/test';
const baseConfig = require( '@wordpress/scripts/config/playwright.config.js' );
const config = defineConfig( {
...baseConfig,
globalSetup: require.resolve( './tests/e2e/global-setup.js' ),
testDir: './tests/e2e',
} );
export default config;
globalSetup
プロパティで指定しているファイルを用意し、以下のように記述します。このコードは、WordPress コアでも定義されている global-setup.js
を参考にしています。
const { request } = require( '@playwright/test' );
const { RequestUtils } = require( '@wordpress/e2e-test-utils-playwright' );
async function globalSetup( config ) {
const { storageState, baseURL } = config.projects[ 0 ].use;
const storageStatePath =
typeof storageState === 'string' ? storageState : undefined;
const requestContext = await request.newContext( {
baseURL,
} );
const requestUtils = new RequestUtils( requestContext, {
storageStatePath,
} );
// Authenticate and save the storageState to disk.
await requestUtils.setupRest();
// Reset the test environment before running the tests.
await Promise.all( [
requestUtils.activateTheme( 'twentytwentyone' ),
requestUtils.deleteAllPosts(),
requestUtils.deleteAllBlocks(),
requestUtils.resetPreferences(),
] );
await requestContext.dispose();
}
export default globalSetup;