TestCafe で E2E テストを始めよう #2 - ベーシック認証とユーザーロール(アカウント認証)
wakamsha
前回は TestCafe の大まかな概要と Getting Started をご紹介しました。
今回は ベーシック認証 と ユーザーロール という二つの認証についてご紹介します。
シリーズ一覧
- 概要説明 と Hello World
- ベーシック認証とユーザーロール(アカウント認証) 👈 この記事
- よりプログラマブルな作りにする
- 関心の分離・メンテナブルなテストを書くためのベストプラクティス
ベーシック認証が効いている環境にアクセスする
通常、ベーシック認証(HTTP Authentication)が効いているサイトへ( curl
といった)プログラムからアクセスする際は、下記の様に認証情報を URL に直接埋め込むことが多いかと思います。
# https://www.example.com
# ユーザー名: username
# パスワード: password
https://userame:password@www.example.com # @といった記号は URL エンコードすること
しかし E2E テストでは実際に web ブラウザからアクセスするためこの手法は使えません。そこで TestCafe ではベーシック認証情報を下記のように宣言的に記述します。
fixture('My Fixture')
.page('https://www.example.com')
.httpAuth({
username: 'username',
password: 'password',
});
test('Test 1', async t => {...});
page
で対象 URL を指定してからメソッドチェーンでベーシック認証情報を指定します。まるで自然言語のようで可読性が高いですね。
User Role 機能を使って認証処理を共通化する
アカウント認証が必要なプロダクトのテストをする時に役立ちます。通常であれば各テストケースの中にこういった認証フローまで含めてしまいがちですが、全てのシナリオに全く同じコードを書くのは避けたいところです。TestCafe の User Role 機能は認証処理に特化したもので、そこを綺麗に分離して管理できるというものです。
使い方
Role
コンストラクタを使ってロール(アカウント)を定義します。
import { Role, TestController } from 'testcafe';
const regularUser = Role(
'http://example.com/login',
async (t: TestController) => {
await t
.typeText('#login', 'TestUser')
.typeText('#password', 'user-password')
.click('#sign-in');
}
);
const adminUser = Role(
'http://example.com/login',
async (t: TestController) => {
await t
.typeText('#login', 'AdminUser')
.typeText('#password', 'admin-password')
.click('#sign-in');
}
);
第一引数に認証を行う URL を渡し、第二引数にユーザを認証するロジックを含む内容を関数として定義します。構文自体はテストケースと殆ど同じですね。
ではこれらのロールをテストケースから読み込んでみます。
import 'testcafe';
import { Selector } from 'testcafe';
const entry = Selector('#entry');
const removeButton = Selector('#remove-entry');
fixture('My Fixture').page('https://www.example.com');
test('test that involves two users', async (t: TestController) => {
await t
.useRole(regularUser)
.expect(entry.exists)
.ok()
.expect(removeButton.visible)
.notOk();
});
TestController
オブジェクトの useRole
というメソッドに Role
オブジェクトを渡します。すると regularUser
内に定義したアクションが実際に行われ、そのロール(アカウント情報)が元いたページ( page
メソッドに渡した URL )に読み込まれた状態で後続のステップが続行されます。
上記の例ではテストケースの最初のステップでロールを読み込んでいますが、ステップの途中で読み込むことも可能です。
test('test that involves two users', async (t: TestController) => {
await t
.useRole(regularUser)
.expect(entry.exists)
.ok()
.expect(removeButton.visible)
.notOk()
.useRole(adminUser)
.expect(removeButton.visible)
.ok()
.click(removeButton)
.expect(entry.exists)
.notOk();
});
最初に regularUser
ロールを読み込んだ後に adminUser
を読み込んでいます。つまりこれ以降のステップは adminUser として行われるということです。
このように複数のロールを定義しておくことで管理が一元化され、またテストケースからの利用もシームレスに行えるようになります。
preserveUrl
Role メソッド内で実施する認証処理によっては、最後にセッション情報が URL ハッシュとして追記されたページへリダイレクトされることがあります。通常 Role メソッドはそのページに進んだところですぐに元いたページに戻ってしまいますが、 preserveUrl
というオプションを true
にしておくと、認証後にリダイレクトしたページの URL 情報を記憶でき、次回以降ロールを切り替える際はこの記憶された URL を開くようになります。
const regularUser = Role(
'http://example.com/login',
async (t: TestController) => {
await t
.typeText('#login', 'TestUser')
.typeText('#password', 'user-password')
.click('#sign-in');
},
{
preserveUrl: true
}
);
例えば Firebase Authentication や Auth0 のような IDaaS を採用しているプロダクトの E2E テストをする際に役立つと思われます。
今回はここまで。次回は TestCafe をよりプログラマブルに実行する方法についてご紹介します。