Angularコンポーネントの見た目が崩れていないことを確認する画像回帰テストを、できるだけ最小ステップで既存のAngular CLIプロジェクトに導入する手順を紹介する。
いくつか検討したが、この方法が現状では比較的追加要素が少なく、導入上の困難が少ないと思われる。もっといい方法を知っている人がいたらぜひ Twitter @laco2net などで教えてほしい。
サンプルレポジトリ
今回の記事の内容が実際に動作するデモレポジトリはこちら
CLIワークスペースにCypressを導入する
この手順は基本的にCypressの公式ドキュメントに従う。
まずは、Angular CLIで作成したワークスペースに、Cypress パッケージをインストールする。
# npm
npm i -D cypress
# yarn
yarn add -D cypress
パッケージをインストールしたら、 cypress
CLIで各種設定の初期化を行う。CypressのGUI操作をしていくと必要なファイルが自動で生成される。
npx cypress open
- テスト形式は “Component Testing” を選択する
- フレームワークは “Angular” を選択する(通常は自動検出されている)
- コンフィグファイルはデフォルトのまま生成する
画像回帰テスト用のプラグインを追加する
Cypress単体では画像回帰テストをサポートしていないため、サードパーティのプラグインを導入する必要がある。
いくつかプラグインはあるが、比較的新しく作られメンテナンスが活発なものの中で、コンポーネントテストに適合したものとして @frsource/cypress-plugin-visual-regression-diff
を紹介する。
こちらも導入方法は README.mdに書かれていることに従うだけでよい。まずはnpmパッケージをインストールする。
# npm
npm i -D @frsource/cypress-plugin-visual-regression-diff
# yarn
yarn add -D @frsource/cypress-plugin-visual-regression-diff
次に、Cypressにプラグインを導入する。2つの作業が必要で、まずはCypressのテストコードで cy.matchImage()
コマンドを使用可能にするために、 cypress/support/component.ts
ファイルに次のインポート文を追加する。
// cypress/support/component.ts
import '@frsource/cypress-plugin-visual-regression-diff';
次に、ルートディレクトリに追加されている cypress.config.ts
にもプラグインを導入する。ただし、 v2.3.1
の時点では initPlugin
のインポート文でTypeScriptの型定義ファイルが見つからないというエラーがエディターに表示されるが、そのままで動作する。気になる場合は require
に切り替えても動作するし、 cypress.config.js
に拡張子を切り替えてもよい。
import { defineConfig } from 'cypress';
// プラグインの初期化関数をインポートする
import { initPlugin } from '@frsource/cypress-plugin-visual-regression-diff/plugins';
export default defineConfig({
component: {
devServer: {
framework: 'angular',
bundler: 'webpack',
},
specPattern: '**/*.cy.ts',
setupNodeEvents(on, config) {
// プラグインを初期化する
initPlugin(on, config);
},
},
});
これでプラグインを導入できた。あとはコンポーネントのテストを記述するだけである。
コンポーネントテストを記述する
今回の例ではライブラリプロジェクト projects/ui
の中に作成した MessageComponent
を対象に画像回帰テストを記述する。
// message.component.ts
import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core';
@Component({
standalone: true,
imports: [CommonModule],
selector: 'ui-message',
template: ` <p *ngIf="message">{{ message }}</p> `,
styles: [
`
p {
color: red;
}
`,
],
})
export class MessageComponent {
@Input() message: string = '';
}
このコンポーネント実装に対して、同じディレクトリに message.component.cy.ts
を作成する。 cy.mount
コマンドを使ってAngularコンポーネントをドキュメント上に表示(マウント)できる。第一引数にはコンポーネントクラスか、テンプレートHTMLを指定できる。この関数の使い方についてはCypressの公式ドキュメントを参考にするとよい。
次の例では MessageComponent
の Inputである message
プロパティに文字列を与えた状態でマウントし、 その後に cy.matchImage()
コマンドによってスクリーンショットを撮っている。
// message.component.cy.ts
import { MessageComponent } from './message.component';
describe('MessageComponent', () => {
it('mounts', () => {
cy.mount(MessageComponent, {
componentProperties: {
message: 'Hello World',
},
});
cy.matchImage();
});
});
MessageComponent
はスタンドアロンコンポーネントとして作成しているため特別な記述をしていなが、スタンドアロンコンポーネントではない場合には declarations
や imports
といったようなNgModule関連のセットアップが必要になるが、今回は割愛する( cy.mount
のAPIと TestBed
の経験を合わせればおそらく察しが付くはずだ)。
画像回帰テストを実行する
それでは実際に画像回帰テストを実行してみよう。 cypress
CLI の open
コマンドでインタラクティブなCypressのGUIを起動する。
npx cypress open --component
テストを実行するブラウザを選択するよう求められるため、任意のものを選ぶ。その後、テスト一覧から実行したい message.component.cy.ts
を選択する
初回は比較する対象の画像がないため、スクリーンショットを保存しただけでテストが通ることになる。実行後に message.component.ts
と同じディレクトリに __image_snapshots__
ディレクトリが追加され、撮影されたスクリーンショットを確認できるだろう。
では、Cypressを実行したまま、テストを書き換えてみよう。コンポーネントに渡している message
インプットを違う文字列に変えてみよう。そうするとテストが再実行されるが、画像の差分が出たことでテストが失敗するはずだ。
describe('MessageComponent', () => {
it('mounts', () => {
cy.mount(MessageComponent, {
componentProperties: {
message: 'Hello Angular', // 文字列を変更する
},
});
cy.matchImage();
});
});
画像比較の失敗メッセージの中にある “See comparison” リンクをクリックすると、保存されている画像と現在の画像の差分をGUIで確認することができる。うまくエラーにならない場合は、差分のエラースレッショルド設定を厳しくしてみるといいだろう。
cy.matchImage({
maxDiffThreshold: 0.001, // 0.1%の差でエラーになる
});
比較画面で “Update screenshot” ボタンをクリックすると、新しいスクリーンショットを今後のテスト基準にするようアップデートしてくれる。アップデートしたあとテストを再実行すれば、画像の差分がなくなりテストが成功するようになる。
コマンドラインでの実行
cypress run
コマンドを使うと、GUIではなくコンソール上でコンポーネントテストを実行することができる。CIなどでテストを自動実行する場合に使うことになる。
npx cypress run --component
cypress run
コマンドではデフォルトでヘッドレスブラウザを使ってテストされる。デフォルトの振る舞いはほとんどがカスタマイズ可能なので、コマンドライン引数の詳細なリファレンスは公式ドキュメントを参照してほしい。
まとめ
この記事ではAngularのコンポーネントをできるだけ少ない手順で画像回帰テストできるようにする方法を紹介した。冒頭にも書いたように、この方法が現状では追加要素が少なく、導入上の困難が少ないと思っているが、もっといい方法を知っている人がいたらぜひ Twitter @laco2net などで教えてほしい。