要素の定義方法
要素の定義方法
Page Objectで要素を定義するいくつかの方法を紹介します。
方法1: readonlyプロパティ
最も基本的な方法です。
export class LoginPage {
readonly usernameInput: Locator;
readonly passwordInput: Locator;
constructor(page: Page) {
this.usernameInput = page.locator('#username');
this.passwordInput = page.locator('#password');
}
}
メリット: TypeScriptの型チェックが効く デメリット: 要素が多いとコードが長くなる
方法2: getterを使う
getterを使うと、プロパティ宣言が不要になります。
export class LoginPage {
constructor(private page: Page) {}
get usernameInput() {
return this.page.locator('#username');
}
get passwordInput() {
return this.page.locator('#password');
}
}
メリット: コードがスッキリする デメリット: アクセスのたびにlocatorが生成される
方法3: アロー関数を使う
関数として要素を取得する方法です。
export const loginPage = {
usernameInput: () => page().locator('#username'),
passwordInput: () => page().locator('#password'),
async login(username: string, password: string) {
await this.usernameInput().fill(username);
await this.passwordInput().fill(password);
}
};
メリット: オブジェクトリテラルで書ける デメリット: pageの取得方法を工夫する必要がある
おすすめのパターン
小規模プロジェクト
readonlyプロパティがシンプルでおすすめ:
export class LoginPage {
readonly usernameInput: Locator;
constructor(page: Page) {
this.usernameInput = page.locator('#username');
}
}
中〜大規模プロジェクト
getterを使うとコードが整理しやすい:
export class LoginPage {
constructor(private page: Page) {}
// 要素
get usernameInput() { return this.page.locator('#username'); }
get passwordInput() { return this.page.locator('#password'); }
get loginButton() { return this.page.getByRole('button', { name: 'Login' }); }
// アクション
async login(username: string, password: string) {
await this.usernameInput.fill(username);
await this.passwordInput.fill(password);
await this.loginButton.click();
}
}
🎯 ベストプラクティス
- ロケーターは
getByRoleやgetByTestIdを優先 - IDやclassは変更されやすいので避ける
- 要素名は分かりやすい名前をつける