6. WebDriver APIを直接使用するテストシナリオ
このサンプルは、デモアプリケーションをテストする完全なテストシナリオ例です。
テストシナリオの動作は以下のようになります。
初期画面
アプリケーションの最初のページです。
このページで、「トップメニュー」をクリックして表示されるalertで、alertの操作例としています。
「問い合わせ」をクリックして次のアコーディオンメニューの展開へ進みます。
アコーディオンメニューの展開
アコーディオンメニューのような動的にページ内の状態が変化するケースで、表示の完了を待つ例としています。
また、スクリーンキャプチャを使用する例も含まれています。
「ユーザ登録」をクリックして次のページへ遷移します。
ユーザ登録画面
このページは、キー入力とボタン操作を中心とした例です。
特に、GHOST Operatorの特徴でもあるIMEを使用した日本語入力を行っています。
各項目の入力後「送信する」ボタンのクリックで次のページへ遷移します。
ユーザ登録結果画面
このページの表示でテストシナリオは終了します。
このテストシナリオは一連の操作を実行し、最後のユーザ登録結果画面まで到達できるかを確認しています。
仮に、途中で意図しない動作・挙動があれば要所に挿入されているチェックコードにより検出されるか、WebDriverAPIの呼び出しが失敗して例外がスローされるかで、テストの失敗を検出する仕組みです。
全体の処理方法を明確にするために、Seleniumプロジェクトで提供されるWebDriverライブラリを直接使用しているため、比較的簡易なページのテストですが記述量は多くなっています。
const crypto = require('crypto');
const { Builder, Capabilities, Key, until, By } = require("selenium-webdriver");
const fs = require('fs');
const path = require('path');
(async function doTest() {
let driver = null;
try {
console.log("capabilitiesの設定");
const capabilities = new Capabilities()
.set("scriptFilter",["\\.html"])
.setBrowserName("safari+G.O");
console.log("WebDriverへ接続");
driver = new Builder()
.usingServer("http://192.168.1.147:7000/wd/hub")
.withCapabilities(capabilities)
.build();
console.log("テスト対象アプリのindex.htmlをロード");
await driver.get("http://dev01.nexaweb.co.jp/GHOST_Operator/demo/index.html");
// 「トップメニュー」のクリックによるalert表示
console.log("「トップメニュー」の表示を待つ");
const titleElm = await driver.wait(until.elementLocated(By.xpath("/html/body/div[1]/header/div/h1")), 3000);
console.log("「トップメニュー」をクリックする");
await titleElm.click();
console.log("Alertを待機");
await driver.wait(until.alertIsPresent(), 1000);
const alert = await driver.switchTo().alert();
console.log("Alertを閉じる");
await alert.dismiss();
// JavaScriptによる値の取得
console.log("appData変数の値を取得");
const appData = await driver.executeScript('return appData;');
if(appData !== "hello") {
throw new Error("appData is not true. appData=" + appData);
}
// アコーディオンメニューの選択
console.log("「問合せボタン」を検索");
const contactElm = await driver.findElement(By.xpath("/html/body/ul/li[4]/div"));
console.log("「問合せボタン」の表示をクリック");
await contactElm.click();
console.log("「ユーザ登録」の表示を待つ");
const userregElm = await driver.wait(until.elementLocated(By.id("userreg", 3000)));
await driver.wait(until.elementIsVisible(userregElm),3000);
console.log("「ユーザ登録」の表示OK");
// スクリーンキャプチャによるメニュー表示テスト
console.log("スクリーンキャプチャのために「ユーザ登録」の安定を待つ");
await driver.sleep(700);
console.log("スクリーンキャプチャによるメニュー表示テスト");
const img_b64 = await driver.takeScreenshot();
const hashHex = crypto.createHash('sha256').update(img_b64, 'utf8').digest('hex');
if(hashHex !== "a4cc7834d3f1df879ee9361eb73943735a05792b6a1ed72671692e83ad074bd8") {
try {
const img_bin = Buffer.from(img_b64, "base64"); // base64エンコードをデコードしてバイナリに変換
const dirName = "images";
const fileName = "snapshot";
const fn = path.normalize(path.format({
dir: dirName,
name: fileName,
ext: ".png"
}));
const fnDir = path.dirname(fn);
if (!fs.existsSync(fnDir))
fs.mkdirSync(fnDir, {recursive: true});
fs.writeFileSync(fn, img_bin); // 画像をファイルに保存
console.log("キャプチャイメージを保存しました");
}
catch(ex) {
console.log(ex);
}
throw new Error("screenshot compare error hash=" + hashHex);
}
console.log("「ユーザ登録」をクリック");
await userregElm.click();
console.log("ページ遷移を待つ");
await driver.wait(until.urlMatches(/^http.*\/demo\/reg\.html$/),1000);
console.log("「お名前」入力欄の表示を待つ");
const nameElm = await driver.wait(until.elementLocated(By.id("name1", 3000)));
console.log("「お名前」入力欄をクリック");
await nameElm.click();
await driver.sleep(100);
console.log("「お名前」の入力");
await nameElm.sendKeys("[HanjaMode On]yamada",Key.SPACE,Key.RETURN," ");
await nameElm.sendKeys("tarou",Key.SPACE,Key.RETURN,"[HanjaMode Off]");
await nameElm.sendKeys(Key.TAB);
console.log("「メールアドレス」の入力");
await nameElm.sendKeys("Tarou.Yamada@nexaweb.com",Key.COMMAND,"ac");
await nameElm.sendKeys(Key.TAB);
console.log("「メールアドレス(確認用)」の入力");
await nameElm.sendKeys(Key.COMMAND, "v");
await nameElm.sendKeys(Key.TAB);
console.log("「電話番号」の入力");
await nameElm.sendKeys("080-4321-8765");
console.log("「性別」を検索");
const genderElms = await driver.findElements(By.name("gender"));
console.log("「男性」を選択");
await genderElms[0].click();
console.log("「職業」を検索");
const jobElm = await driver.findElement(By.id("job"));
console.log("「職業」をクリック");
await jobElm.click();
console.log("「職業」のセレクタ表示を待つ");
await driver.sleep(500);
console.log("「Webデザイナ」を選択");
await driver.actions({bridge: true})
.move({origin: jobElm, x:0, y:-270})
.click()
.perform();
console.log("「あなたが学びたいこと」を検索");
const qElms = await driver.findElements(By.name("q1"));
console.log("「デザインについて」を選択");
await qElms[0].click();
console.log("「マーケティングについて」を選択");
await qElms[2].click();
console.log("「送信する」を検索");
const buttonElm = await driver.findElement(By.xpath("/html/body/div[2]/form/div/button"));
console.log("「送信する」をクリック");
await buttonElm.click();
console.log("ページ遷移を待つ");
await driver.wait(until.urlMatches(/^http.*\/demo\/result\.html\?.*$/),3000);
console.log("ページ遷移完了");
console.log("テスト正常終了");
} catch (e) {
console.log(e);
} finally {
if(driver !== null)
await driver.quit();
}
})();
※ このサンプルの関連ファイルはSeleniumSamples.zipのsec6_webDriverAPIに収められています。