[メモ】Web自動化テストにSeleniumの代わりにChrome Extensionを使用する。
Seleniumの自動テストは不安定な点が多く、APIドキュメントをたくさん読んだり、使用する言語に対応したドライバパッケージをダウンロードしたりする必要があります。そこで、Chrome Extensionで直接置き換えたいと思いました。
Chrome Extensionを使ってWeb UIテストを推進する方法とは?まずは最初のExtensionから。
フォルダの中に入れたExtension。最初のExtensionは、icon.png、background.js、manifest.jsonの3つのファイルから構成されています。
特定のページを見たときに、アドレスバーの右側に拡張機能のアイコン icon.png を表示するウェブからのコードがたくさんあります。
// background.js
function match(url){
var host = "null";
if(typeof url == "undefined" || null == url)
url = window.location.href;
var regex = /. *\:\/\/([^\/]*). */;
var match = url.match(regex);
if(typeof match ! = "undefined" && null ! = match)
host = match[1];
return host;
}
function entry(tabId, changeInfo, tab) {
// Show extension icon when URL is localhost
if(match(tab.url).toLowerCase()=="localhost"){
chrome.pageAction.show(tabId);
}
};
chrome.tabs.onUpdated.addListener(entry);
// manifest.json
{
"manifest_version": 2,
"name": "Chrome Extension: Test",
"version": "0.0.1",
"background": { "scripts": ["background.js"] },
"permissions": ["tabs"],
"page_action": {
"default_icon": {
"19": "icon.png"
},
"default_title": "test extension"
}
}
次に、Chromeを開き、アドレスバーにchrome://extensions/と入力し、拡張機能のタイトルの右側にある"developer mode"をチェックすると、独自の拡張機能を追加するフォルダを選択するボタンが表示されるようになります。
拡張機能を読み込んだ後、新しいタブでテストページ(http://localhost/index.html など)を入力すると、アドレスバーの右側に icon.png が表示されます。
このアイコンは、テストしたいページが処理されていることを示す、今のところただの飾りです。
ここでは、現在訪問しているページの情報を取得する方法について説明します。ここで、エクステンションのコンテンツスクリプト機能の出番です。エクステンションの開発フォルダにjsファイルcontent.jsを追加してください。
// content.js
var links = document.getElementsByTagName('a');
var list = [];
var n,i,t;
n = links.length;
for(i=0;i<n;i++) {
t = links[i].href;
if (!t) continue;
if (t.toLowerCase().indexOf('javascript:') >= 0) continue;
list.push(t);
t = null;
}
console.log(list);
次に、コンテンツ スクリプトの設定を manifest.json に追加します。
// manifest.json
... ...
"background": { "scripts": ["background.js"] }
// Add support for content script
"content_scripts":[
{"matches":["http://localhost/*"],"js":["content.js"]}
],
"permissions": ["tabs"],
... ...
chrome://extensions/ で自分の拡張機能を再ロードし、テストページを更新します。それからコンソールに移動し、もしページ内にハイパーリンクがあれば、それらがリンクするすべてのアドレスをコンソールがプリントアウトします。もちろん、コンソール出力はファイルに出力する形なので、冒頭のアイコンを使い、それをクリックすれば結果を見ることができます。
アイコンをクリックして結果を見るという実装には、バックグラウンドスクリプトとコンテンツスクリプトがどのように通信しているかを知る必要があります。ここでは、コンテンツスクリプトからリストをバックグラウンドに取得し、アイコンをクリックしたときに表示する方法について説明します。
コンテンツスクリプトでリストをバックグラウンドに取得するためには、メッセージ機構による通信を実装する必要があります。content.jsとbackground.jsを以下のように修正します。
// content.js
... ...
console.log(list);
chrome.runtime.sendMessage({
type: 'localtest-links',
links: list
});
// background.js
... ...
chrome.tabs.onUpdated.addListener(entry);
var pageData = {};
chrome.runtime.onMessage.addListener(function(message, sender, response){
if (message.type ! == 'localtest-links') return;
pageData.links = message.links;
});
アイコンをクリックしてコンテンツを表示するのは、実際にはポップアップページの設定なので、popup.html と popup.js の2つのファイルを追加し、manifest.json を修正する必要があります。
<! -- popup.html -->
<html>
<body>
<div id="result">(No Result)</div>
<script type="text/javascript" src="popup.js"></script>
</body>
</html>
// popup.js
document.addEventListener('DOMContentLoaded', function () {
var data = chrome.extension.getBackgroundPage().pageData;
var dom = document.getElementById('result');
var html = '';
var n, i;
n = data.links.length;
for(i=0;i<n;i++) {
html += '<div>' + data.links[i] + '</div>';
}
dom.innerHTML = html;
html = null;
dom = null;
data = null;
});
// manifest.json
... ...
"default_title": "test extension",
"default_popup": "popup.html"
}
... ...
function trigger(element, eventType) {
var event = document.createEvent('HTMLEvents');
event.initEvent(eventType, true, true);
element.dispatchEvent(event);
event = null;
}
こうすることで、localhostのページにアクセスしたときに、すべてのハイパーリンクの情報が収集され、拡張機能アイコンがクリックされたときに小さなポップアップウィンドウに表示されるようになります。
上記のプロセス全体は、基本的にいくつかの簡単なテストを実行するのに十分です。テスト者はスクリプトを使ってクロームを開き、拡張機能にテストを自動的に実行させることができ、最後に拡張機能のアイコンでテスト結果を見ることができます。
拡張機能でテストするときに、コントロールパネルをpopup.htmlに入れることを考えてみましょう。ここでは、クリックされるとテストされるページの最初のボタンのクリックイベントをトリガーするボタンを追加しています。
まずは、イベントのトリガーをブレインストーミングで考えてみましょう。
<! -- popup.html -->
... ...
<div id="result">(None)</div>
<button id="fire">Fire</button>
<script src="popup.js"></script>
... ...
// popup.js
... ...
dom.innerHTML = html;
dom = document.getElementById('fire');
dom.addEventListener('click', function () {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
chrome.tabs.sendMessage(
tabs[0].id,
{type: 'localtest-fire'},
function(response) {});
});
});
html = null;
... ...
// content.js
... ...
chrome.extension.onMessage.addListener(function(message, sender, response) {
if(message.type!=='localtest-fire') return;
var buttons = document.getElementsByTagName('buttons');
if(buttons.length > 0) {
// trigger is the part I just made up :P
trigger(buttons[0], 'click');
}
buttons = null;
});
コントロールボタンは popup.html に追加され、その後、ボタンのクリックイベントを発生させたいことをコンテンツスクリプトに通知するポップアップからのメッセージの処理が行われます。
<html>
<body>
<a href="http://www.baidu.com"">Hello</a><br/>
<a href="javascript:alert('hi');">World</a><br/>
<a href="test.html">self</a><br/>
<button οnclick="javascript:alert('trigger')">From Popup</button>
</body>
</html>
// content.js
... ...
var script = document.createElement('script');
script.type = 'text/javascript';
// Replace the alert and output the msg directly to the console
script.textContent = 'window.nativeAlert=window.alert;window.alert=function(msg){console.log(msg);};';
// inject the code into the current page
(document.head || document.documentElement).appendChild(script);
// You can have the script removed from the page after the code has run, but that's not important
script = null;
効果を試すために、ローカルサーバーにtest.htmlファイルを置いてみます。
<html>
<body>
<a href="http://www.baidu.com"">Hello</a><br/>
<a href="javascript:alert('hi');">World</a><br/>
<a href="test.html">self</a><br/>
<button οnclick="javascript:alert('trigger')">From Popup</button>
</body>
</html>
拡張機能を再読み込みした後、http://localhost/test.html时、アドレスバーの右側にある拡張機能のアイコンをクリックし、Fireボタンをクリックすると、"trigger"というアラートがポップアップされます
以下は、アラートを殺すことを目的として、現在のページにコードを注入するコンテンツスクリプトの説明です。
window.alertはalertであり、これを実行するとメッセージボックスがポップアップすることが分かっています。この関数をオーバーライドして、コンソールにメッセージを出力させることができればいいのですが。content.jsを次のように修正する必要があります。
// content.js
... ...
var script = document.createElement('script');
script.type = 'text/javascript';
// Replace the alert and output the msg directly to the console
script.textContent = 'window.nativeAlert=window.alert;window.alert=function(msg){console.log(msg);};';
// inject the code into the current page
(document.head || document.documentElement).appendChild(script);
// You can have the script removed from the page after the code has run, but that's not important
script = null;
拡張機能をオーバーロードすると、test.html にアクセスしたときに "ポップアップから" ボタンを直接クリックして、コンソールにメッセージが出力されたことを確認し、ポップアップの "fire" ボタンをクリックできるようになるのです。同じ効果です。
もちろん、このインジェクションを使ってテストスクリプトを読み込んで実行し、その結果を返すこともできるので、素敵なWeb UI自動テストツールを作ることができます。
HTTPSの場合、入力認証のダイアログでポップアップが出ることがあるので、エクステンションのwebRequest機能を有効にして、HeaderにAuthentication情報を追加すると、このダイアログを回避することができます。
これで、基本的にWeb UI自動テストのために独自の拡張機能を実行し、結果をテキストとして出力するコードを書くことができます。
J.Y.リュー
2014.09.15
関連
-
[解決済み】Babel NodeJS ES6: SyntaxError: 予期しないトークンのエクスポート
-
[解決済み】改行が「LF」であることを期待したが、「CRLF」改行スタイルが見つかった
-
[解決済み】Reactルーターでブラウザの履歴が表示されない件
-
[解決済み] クラス名ですべての子孫を検索するDojoクエリ
-
[解決済み] エラー修正方法; 'Error: Bootstrap tooltips には Tether (http://github.hubspot.com/tether/) が必要です'。
-
[解決済み] Angularマテリアルのmat-expansion-panelのコンテンツを中央に配置する。
-
[解決済み] AngularJSのng-modelでArrayを作成する方法
-
[解決済み] 要素外でのクリックを検出するにはどうすればよいですか?
-
[解決済み] vuejsでクッキーを設定する方法は?
-
[解決済み] GoにおけるDate.now()の等価性
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】ES6マップオブジェクトをソートすることは可能ですか?
-
[解決済み] null のプロパティ 'addEventListener' を読み取ることができません。
-
[解決済み] AngularのngDefaultControlとは何ですか?
-
[解決済み] TypeError: 未定義のプロパティ 'then' を読み取ることができません。
-
[解決済み] アロー関数「式が期待される」シンタックスエラー
-
[解決済み] キーボード入力でThree JSのキューブを動かすにはどうしたらいいですか?
-
[解決済み] "メディアを再生できません。No decoders for requested formats" on popular Big Buck Bunny mp4 video
-
[解決済み] HTMLアンカータグとJavascriptのonclickイベント
-
[解決済み] open 'fancybox' 内の関数から fancybox を閉じる
-
[解決済み] 警告 スクロールブロックの「touchstart」イベントに非受動的なイベントリスナーを追加しました [重複] 。