1. ホーム
  2. ジャバスクリプト

[メモ】Web自動化テストにSeleniumの代わりにChrome Extensionを使用する。

2022-02-25 12:32:53

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