Playwright JavaScript 実行
この章では、Playwright で JavaScript コードを実行する方法を紹介します。ページコンテキストでの実行、引数の受け渡し、初期化スクリプトの注入を含みます。
page.evaluate() ページコンテキストでの実行
page.evaluate()ページの JavaScript 環境でコードを実行し、DOM やページのグローバル変数にアクセスできます。
例
test('ページデータを取得', async ({ page }) => {
await page.goto('https://www.example.com/');
// ページタイトルを取得(ページコンテキストで実行)
const title = await page.evaluate(() => {
return document.title;
});
console.log('ページタイトル:', title);
// ページ内のすべてのリンク数を取得
const linkCount = await page.evaluate(() => {
return document.querySelectorAll('a').length;
});
console.log('リンク数:', linkCount);
// ページのスクロール位置を取得
const scrollY = await page.evaluate(() => {
return window.scrollY;
});
});
await page.goto('https://www.example.com/');
// ページタイトルを取得(ページコンテキストで実行)
const title = await page.evaluate(() => {
return document.title;
});
console.log('ページタイトル:', title);
// ページ内のすべてのリンク数を取得
const linkCount = await page.evaluate(() => {
return document.querySelectorAll('a').length;
});
console.log('リンク数:', linkCount);
// ページのスクロール位置を取得
const scrollY = await page.evaluate(() => {
return window.scrollY;
});
});
evaluate に引数を渡す
page.evaluate()の2番目の引数はページ内の関数に渡されます。
例
test('ページに引数を渡す', async ({ page }) => {
await page.goto('https://www.example.com/');
// 単一の引数を渡す
const result1 = await page.evaluate((name) => {
return `Hello, ${name}!`;
}, 'サンプル');
// オブジェクトの引数を渡す
const userInfo = { name: 'サンプル', role: 'admin' };
const result2 = await page.evaluate((user) => {
return `${user.name}の役割は $ です。{user.role}`;
}, userInfo);
// 複数の引数を渡す(分割代入を使用)
const result3 = await page.evaluate(
({ x, y }) => {
return x + y;
},
{ x: 10, y: 20 }
);
console.log('10 + 20 =', result3); // 30
});
await page.goto('https://www.example.com/');
// 単一の引数を渡す
const result1 = await page.evaluate((name) => {
return `Hello, ${name}!`;
}, 'サンプル');
// オブジェクトの引数を渡す
const userInfo = { name: 'サンプル', role: 'admin' };
const result2 = await page.evaluate((user) => {
return `${user.name}の役割は $ です。{user.role}`;
}, userInfo);
// 複数の引数を渡す(分割代入を使用)
const result3 = await page.evaluate(
({ x, y }) => {
return x + y;
},
{ x: 10, y: 20 }
);
console.log('10 + 20 =', result3); // 30
});
渡された引数は JSON にシリアライズされてページコンテキストに送信されるため、関数や DOM 要素などシリアライズできないオブジェクトは渡せません。
戻り値も同様にシリアライズされます。
locator.evaluate() 要素コンテキストでの実行
locator.evaluate()一致した要素のコンテキストでコードを実行します。引数にはその要素の DOM ノードへの参照が含まれます。
例
test('要素の DOM 属性を取得', async ({ page }) => {
await page.goto('https://www.example.com/');
// 特定の要素の textContent を取得
const text = await page
.getByRole('heading', { name: 'サンプル' })
.evaluate(node => node.textContent);
// 要素のスタイル属性を取得
const color = await page
.getByRole('button', { name: '検索' })
.evaluate(node => getComputedStyle(node).backgroundColor);
});
await page.goto('https://www.example.com/');
// 特定の要素の textContent を取得
const text = await page
.getByRole('heading', { name: 'サンプル' })
.evaluate(node => node.textContent);
// 要素のスタイル属性を取得
const color = await page
.getByRole('button', { name: '検索' })
.evaluate(node => getComputedStyle(node).backgroundColor);
});
locator.evaluateAll() 一致するすべての要素を走査
evaluateAll()一致するすべての要素に対して同じコードを実行し、配列を返します。
例
test('すべてのリスト項目のテキストを取得', async ({ page }) => {
await page.goto('https://www.example.com/');
// すべてのメニュー項目のテキストを取得
const menuItems = await page
.getByRole('navigation')
.locator('a')
.evaluateAll(links => links.map(link => link.textContent));
console.log('メニュー項目:', menuItems);
// ['ホーム', 'チュートリアル', 'ツール', ...]
});
await page.goto('https://www.example.com/');
// すべてのメニュー項目のテキストを取得
const menuItems = await page
.getByRole('navigation')
.locator('a')
.evaluateAll(links => links.map(link => link.textContent));
console.log('メニュー項目:', menuItems);
// ['ホーム', 'チュートリアル', 'ツール', ...]
});
page.addInitScript() 初期化スクリプトの注入
addInitScript()ページが読み込まれる前に JavaScript コードを注入でき、ページスクリプトの実行前にブラウザ環境を変更できます。
例
test('初期化スクリプトを注入', async ({ page }) => {
// ページ読み込み前に navigator プロパティを変更
await page.addInitScript(() => {
// WebDriver 検出を上書き
Object.defineProperty(navigator, 'webdriver', {
get: () => false,
});
// window 上のグローバル変数をモック
window.サンプル_CONFIG = {
env: 'test',
version: '1.0.0',
};
});
await page.goto('https://www.example.com/');
// 注入した変数が有効であることを確認
const config = await page.evaluate(() => window.サンプル_CONFIG);
console.log(config); // { env: 'test', version: '1.0.0' }
});
// ページ読み込み前に navigator プロパティを変更
await page.addInitScript(() => {
// WebDriver 検出を上書き
Object.defineProperty(navigator, 'webdriver', {
get: () => false,
});
// window 上のグローバル変数をモック
window.サンプル_CONFIG = {
env: 'test',
version: '1.0.0',
};
});
await page.goto('https://www.example.com/');
// 注入した変数が有効であることを確認
const config = await page.evaluate(() => window.サンプル_CONFIG);
console.log(config); // { env: 'test', version: '1.0.0' }
});
addInitScript()一般的な用途:
| 用途 | 説明 |
|---|---|
| ブラウザ API のモック | 上書きnavigator.webdriver、navigator.language 等 |
| カスタム設定の注入 | テスト環境変数の設定、データソースのモックなど |
| 機能の無効化 | Service Worker の停止、ログの無効化など |
| Polyfill | ページが依存しているがテスト環境にない機能を追加する |
ElementHandle の用途と制限
ElementHandle は DOM 要素への直接参照であり、Playwright の初期バージョンで広く使用されていました。
現在、ほとんどのシナリオでは、LocatorLocator を ElementHandle の代わりに使用します。
例
// ElementHandle 方式(旧式、非推奨)
const handle = await page.$('.my-element');
await handle.click();
// Locator 方式(新式、推奨)
await page.locator('.my-element').click();
const handle = await page.$('.my-element');
await handle.click();
// Locator 方式(新式、推奨)
await page.locator('.my-element').click();
ElementHandle は、取得が必要な場合にのみboundingBox()または複雑な DOM 操作を行う場合に使用します。