動かなくなったらWebDriverのバージョンを疑え
以下のようなエラーで動かなくなった場合、Chromeをバージョンアップした影響でChromeDriverのサポートバージョンとズレてしまっているためにエラーとなっている。
$ node hoge.js /home/grgrjnjn/Documents/hoge/node_modules/selenium-webdriver/lib/error.js:524 let err = new ctor(data.message) ^ SessionNotCreatedError: session not created: This version of ChromeDriver only supports Chrome version 107 Current browser version is 110.0.5481.177 with binary path /usr/bin/google-chrome at Object.throwDecodedError (/home/grgrjnjn/Documents/hoge/node_modules/selenium-webdriver/lib/error.js:524:15) at parseHttpResponse (/home/grgrjnjn/Documents/hoge/node_modules/selenium-webdriver/lib/http.js:587:13) at Executor.execute (/home/grgrjnjn/Documents/hoge/node_modules/selenium-webdriver/lib/http.js:515:28) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { remoteStacktrace: '#0 0x563b89a30463 <unknown>\n' + '#1 0x563b897f48d8 <unknown>\n' + '#2 0x563b898213c6 <unknown>\n' + '#3 0x563b8981c580 <unknown>\n' + '#4 0x563b89817c05 <unknown>\n' + '#5 0x563b8985b802 <unknown>\n' + '#6 0x563b8985b2af <unknown>\n' + '#7 0x563b89853443 <unknown>\n' + '#8 0x563b898243c5 <unknown>\n' + '#9 0x563b89825531 <unknown>\n' + '#10 0x563b89a82dce <unknown>\n' + '#11 0x563b89a86192 <unknown>\n' + '#12 0x563b89a6793e <unknown>\n' + '#13 0x563b89a87103 <unknown>\n' + '#14 0x563b89a5ad85 <unknown>\n' + '#15 0x563b89aa80a8 <unknown>\n' + '#16 0x563b89aa8239 <unknown>\n' + '#17 0x563b89ac3492 <unknown>\n' + '#18 0x7fc4cce94b43 <unknown>\n' } Node.js v18.12.0
Seleniumサイトの次のページ下部のクイックリファレンスからダウンロードページに飛び、使っているChromeバージョンにあったドライバをダウンロードする。
ブラウザーのドライバーをインストールする | Selenium
ドライバーはPATHが通ったところにおく。僕は簡単に以下の通りした。
$ sudo cp ~/Downloads/chromedriver_linux64/chromedriver /usr/local/bin/
Node.jsでSeleniumを使用してWebページの読み込み時間を計測する
driver.executeScript( "return (window.performance.timing.loadEventEnd - window.performance.timing.requestStart) / 1000") .then(function(sec_loading_time){ console.log(sec_loading_time); });
上記コードをChatGPTにawaitを使った記述に変更してもらった。
(async () => { const sec_loading_time = await driver.executeScript( "return (window.performance.timing.loadEventEnd - window.performance.timing.requestStart) / 1000" ); console.log(sec_loading_time); })();
以下は、ChatGPTにコードを説明してもらったものからの抜粋。
このコードは、Node.jsでSeleniumを使用して、特定のWebページの読み込み時間を計測するためにJavaScriptを実行しています。
executeScriptの説明部分
executeScript()は、ブラウザ内でJavaScriptコードを実行するためのSeleniumのメソッドです。引数として渡されたJavaScriptコードがブラウザ内で実行され、その結果を返します。
ここはキモとなる部分
"return (window.performance.timing.loadEventEnd - window.performance.timing.requestStart) / 1000"は、ページの読み込み時間を計算するJavaScriptコードです。performance.timingオブジェクトには、ブラウザのページ読み込みに関する情報が含まれています。ここでは、ページの読み込みが完了するまでにかかった時間を計算しています。この時間を秒単位で返すように指定しています。
ここの内容が重要
ここで測定される時間は、HTMLファイルを含めたページのすべてのリソースが読み込み完了するまでの時間です。
window.performance.timingオブジェクトは、ページの読み込みに関する様々なタイミング情報を提供します。その中には、HTMLファイルの読み込みが完了するresponseEnd、JavaScriptやCSSファイルなどのすべてのリソースの読み込みが完了するloadEventEndなどが含まれます。このコードでは、loadEventEndとrequestStartの差を計算することで、すべてのリソースの読み込みが完了するまでの時間を計測しています。
つまり、このコードによって計測される時間は、HTMLファイルを含めたすべてのリソースが読み込み完了するまでの時間です。
selenium.devドキュメントを読む
(一部)日本語版が提供されているのがすばらしい。
- 冒頭
- 概要
- WebDriver
- 入門
- ドライバー
- ブラウザ
- 待機
- Web待機
- Interactions
- Actions API
- BiDirectional
- Support features
- テストの実践
冒頭
- Seleniumは
基本
const {Builder} = require('selenium-webdriver'); require("chromedriver"); (async function helloSelenium() { let driver = await new Builder().forBrowser('chrome').build(); await driver.get('https://selenium.dev'); await driver.quit(); })();
概要
- Seleniumはたくさんのツールから構成されている
- ウェブサイトのテスト自動化にはWebDriver API
- WebDriver APIはブラウザベンダーによって提供されている
- IDEはSeleniumのテストケースを開発するためのツール
- IDEはChromeとFirefoxの拡張機能
- IDEはユーザーの動作を記録する
- IDEはSeleniumスクリプトのシンタックスを学ぶための優れた方法
- Gridは複数のブラウザーとOSの組み合わせでテストを実行できる
- Gridはテストケースの起動の制御はローカル端末で行われ、リモート端末によって自動的に実行される
- ドライバーは、実際のブラウザを制御します。 ドライバーはブラウザベンダー自身が作成します。一部の人々はドライバーをプロキシと呼んでいます。
ドライバーは、ChromeDriver、GeckoDriverなどブラウザー固有のものです。 最低限、WebDriverはドライバーを経由してブラウザーと通信します。 コミュニケーションは双方向です。 ドライバーはブラウザと同じシステムで動きます。簡単な例は直接通信です。
[WebDriver]<--->[Driver]<--->[Browser]
RemoteWebDriverを経由したリモート通信もできます。 RemoteWebDriverは、ドライバーおよびブラウザと同じシステムで実行されます。
[WebDriver]<--(-->[Remote WebDriver]<--->[Driver]<--->[Browser] )
Selenium ServerまたはSelenium Gridを使用してリモート通信を行うこともできます。
[WebDriver]<--->[Selenium Server or Grid]<--(-->[Driver]<--->[Browser] )
WebDriverのジョブは1つです。テストに関することは知りません。
そこでフレームワーク登場です。例えば NUnit for .NET, JUnitfor Java, RSpec for Ruby, Cucumber など。 テストフレームワークは、WebDriverおよびテストの関連手順の実行を担当します。
(TEST FRAMEWORK [WebDriver]<--)-->[Selenium Server or Grid]<--(-->[Driver]<--->[Browser] HOST SYSTEM)
WebDriver
- WebDriverはブラウザをネイティブに操作します
- WebDriverは言語バインディングと個々のブラウザ制御コードの実装の両方を参照します
入門
インストール、セットアップは、別記事に譲る。
8つの基本コンポーネント
- ドライバーインスタンスでセッションを開始
- ブラウザ上で操作
- ブラウザに関する情報をリクエスト
- 待ち時間の設定
- 要素を検索するためのコマンドを送信
- 要素に対してアクションを実行
- 要素に関する情報をリクエスト
- セッションを終了
ドライバーインスタンスでセッションを開始
詳細は ドライバーセッション | Selenium 参照
driver = await new Builder().forBrowser('chrome').build();
ブラウザ上で操作
ブラウザー ナビゲーション | Selenium (get / back / forward / refresh)
await driver.get('https://www.selenium.dev/selenium/web/web-form.html');
ブラウザに関する情報をリクエスト
Browser interactions | Selenium
ウィンドウハンドル、ブラウザのサイズ/位置、クッキー、アラートなど、要求できるブラウザに関する情報の種類はたくさんあります。
let title = await driver.getTitle();
待ち時間の設定
ブラウザの現在の状態とコードを同期させることはSeleniumの最大の課題の1つであり、それをうまく行うことは高度なトピックです。
基本的には、要素を見つけようとする前にその要素がページ上にあることを確認し、それと対話しようとする前に要素が対話可能な状態にあることを確認したいのです。
暗黙の待機が最善の解決策であることはほとんどありませんが、ここで示すのが最も簡単なので、プレースホルダとして使用することにします。
詳細は 待機 | Selenium 参照
await driver.manage().setTimeouts({ implicit: 500 });
要素を検索するためのコマンドを送信
ほとんどのSeleniumセッションのコマンドの大部分は要素に関連しており、最初に要素を見つけることなく、コマンド操作することはできません。
詳細は Web要素 | Selenium 参照
let textBox = await driver.findElement(By.name('my-text')); let submitButton = await driver.findElement(By.css('button'));
要素に対してアクションを実行
要素に対して行うアクションはほんの一握りですが、頻繁に使用することになります。
await textBox.sendKeys('Selenium');
await submitButton.click();
要素に関する情報をリクエスト
要素には、要求できる多くの情報が格納されています。
詳細は Web要素に関する情報 | Selenium 参照
let value = await message.getText();
セッションを終了
ドライバプロセスが終了し、デフォルトでブラウザも終了します。
after(async () => await driver.quit());
// firstScript.spec.js const { By, Builder } = require('selenium-webdriver'); const { suite } = require('selenium-webdriver/testing'); const assert = require("assert"); suite(function(env) { describe('First script', function() { let driver; before(async function() { driver = await new Builder().forBrowser('chrome').build(); }); after(async () => await driver.quit()); it('First Selenium script', async function() { await driver.get('https://www.selenium.dev/selenium/web/web-form.html'); let title = await driver.getTitle(); assert.equal("Web form", title); await driver.manage().setTimeouts({ implicit: 500 }); let textBox = await driver.findElement(By.name('my-text')); let submitButton = await driver.findElement(By.css('button')); await textBox.sendKeys('Selenium'); await submitButton.click(); let message = await driver.findElement(By.id('message')); let value = await message.getText(); assert.equal("Received!", value); }); }); });
テストフレームワークmochaをインストールして実行。
$ npm install mocha $ node firstScript.spec.js $ npx mocha --no-timeouts firstScript.spec.js
npxの説明は npxコマンドとは? 何ができるのか? を参照。
ドライバー
セッションの開始と停止は、ブラウザーを開いたり閉じたりするためのものです。
セッションの作成
- W3C コマンド New session に対応している
- セッションは新しいDriverクラスのオブジェクトを初期化することで自動的に作成される
- クラスの引数
- ブラウザーオプション | Selenium
- ブラウザーオプションは、ローカルではデフォルト値を使用できるが、リモートでは必須
- Command executors | Selenium
- Command Listeners | Selenium
セッションの終了
ブラウザーオプション
Command executors Command Listeners Browser Service Remote WebDriver
ブラウザ
待機
Web待機
Interactions
Actions API
BiDirectional
Support features
IDE
Grid
コンポーネントを理解する
Selenium 詳細
Selenium+Node.js
参照すべき公式情報
- Selenium (上部メニューから日本語が選択できる!)
- selenium-webdriver
- selenium-webdriver - npm
ライブラリのインストール
Seleniumライブラリのインストール | Selenium
$ npm init $ npm install selenium-webdriver
ドライバーのインストール
ブラウザーのドライバーをインストールする | Selenium
クイックリファレンスの表からChromeのドライバーのダウンロードサイトへ遷移する。 使用しているChromeのバージョンが「バージョン: 107.0.5304.87(Official Build) (64 ビット)」なので、「If you are using Chrome version 107, please download ChromeDriver 107.0.5304.62」のリンクからchromedriver_linux64.zipをダウンロード、展開して、chromedriverファイルを得る。
PATHに設定する必要があるのだけど、どこに置くのがいいのだろう? .bashrcの設定しなくても使えるように /usr/local/binにでも置いておこうか。 chromedriverが起動すればOK。
$ sudo cp ~/Downloads/chromedriver_linux64/chromedriver /usr/local/bin/ $ ls -l /usr/local/bin/chromedriver -rwxr-xr-x 1 root root 14454968 11月 3 17:59 /usr/local/bin/chromedriver $ chromedriver Starting ChromeDriver 107.0.5304.62 (1eec40d3a5764881c92085aaee66d25075c159aa-refs/branch-heads/5304@{#942}) on port 9515 Only local connections are allowed. Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe. ChromeDriver was started successfully. (Ctrl+C)
ブラウザの起動
browser_launch.js
を作成。
const {Builder} = require('selenium-webdriver'); const driver = new Builder().forBrowser('chrome').build();
$ node browser_launch.js
非推奨ながら、chromedriverのパスを指定して起動する方法。browser_launch2.js
を作成。4行目のパスはchromedriverを置いた場所を指定。
const {Builder} = require('selenium-webdriver'); const chrome = require('selenium-webdriver/chrome'); const service = new chrome.ServiceBuilder('/usr/local/bin/chromedriver'); const driver = new Builder().forBrowser('chrome').setChromeService(service).build();
$ node browser_launch2.js
※ここ修正する
冒頭は以下のように修正可能
(async () => {
最初のSeleniumスクリプトfirstScript.spec.js
を書く
最初のSeleniumスクリプトを書く | Selenium
const { By, Builder } = require('selenium-webdriver'); const { suite } = require('selenium-webdriver/testing'); const assert = require("assert"); suite(function(env) { describe('First script', function() { let driver; before(async function() { driver = await new Builder().forBrowser('chrome').build(); }); after(async () => await driver.quit()); it('First Selenium script', async function() { await driver.get('https://www.selenium.dev/selenium/web/web-form.html'); let title = await driver.getTitle(); assert.equal("Web form", title); await driver.manage().setTimeouts({ implicit: 500 }); let textBox = await driver.findElement(By.name('my-text')); let submitButton = await driver.findElement(By.css('button')); await textBox.sendKeys('Selenium'); await submitButton.click(); let message = await driver.findElement(By.id('message')); let value = await message.getText(); assert.equal("Received!", value); }); }); });
テストフレームワークmochaをインストールして実行。
$ npm install mocha $ node firstScript.spec.js
実行はエラーになる。 下記を参考に実行。
javascript - after function on selenium test is not defined - Stack Overflow
$ npx mocha --no-timeouts firstScript.spec.js [INFO] Searching for WebDriver executables installed on the current system... [INFO] ... located chrome [INFO] ... located firefox [INFO] Running tests against [chrome, firefox] [chrome] First script ✔ First Selenium script (1317ms) [firefox] First script ✔ First Selenium script (1025ms) 2 passing (4s)
これはどこから辿ったのだっけ?こちらも参考になりそう。
この記事では、Selenium/WebDriver や selenium-webdriver for Node のようなテストライブラリーを使って、自動化環境のインストールとテストを実行する方法を教えます。
google_test.js
const webdriver = require('selenium-webdriver'); const By = webdriver.By; const until = webdriver.until; const driver = new webdriver.Builder() .forBrowser('chrome') .build(); driver.get('http://www.google.com'); driver.findElement(By.name('q')).sendKeys('webdriver'); driver.sleep(1000).then(() => { driver.findElement(By.name('q')).sendKeys(webdriver.Key.TAB); }); driver.findElement(By.name('btnK')).click(); driver.sleep(2000).then(() => { driver.getTitle().then((title) => { if (title === 'webdriver - Google Search') { console.log('Test passed'); } else { console.log('Test failed'); } driver.quit(); }); });
ローカルファイルを開くとき
driver.get('file:///Users/chrismills/git/learning-area/tools-testing/cross-browser-testing/accessibility/fake-div-buttons.html');
ロギング
selenium-webdriver/lib/logging.Logger
selenium/logging_test.js at trunk · SeleniumHQ/selenium · GitHub
Logging - ChromeDriver - WebDriver for Chrome
selenium-webdriver/lib/logging
パフォーマンステストに使いたいというのが1つの目的だったが、お勧めしません?
通常、SeleniumとWebDriverを使用したパフォーマンステストはお勧めしません。
Selenium Webdriver ページの読み込み時間の計測 - Qiita
SeleniumのexecuteScriptを利用して、ページのwindowオブジェクトに直接アクセスして読み込み時間を取得した。windowオグジェクトは、Performanceに関するAPIを持っていて詳しくは以下を参照。
BiDirectional APIには、Performanceに関するドキュメントがなかったので、Chrome DevTools Protocolを使って
Chrome DevTools Protocol | Selenium
こんなサイトも
これは大注目(あとで読む)
ChromeDriver - WebDriver for Chrome - Performance Log
検証用にログを出力。キーワード「webdriver.logging」?
Ubuntu22にNode.jsをインストール
サイドバー?の[Ubuntu Software]から、[探す]-[Development]-[node]-[インストール]でインストール完了。
$ node --version v18.12.0
nvmは公式サイトのインストール手順を参照。
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash (略) => Appending nvm source string to /home/tokushima/.bashrc => Appending bash_completion source string to /home/tokushima/.bashrc => Close and reopen your terminal to start using nvm or run the following to use it now: export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
$ source ~/.bashrc
$ nvm --version 0.39.2
現在使用のバージョンを調べる
$ nvm current system
利用可能なバージョンを一覧表示
$ nvm ls-remote (略) v18.11.0 v18.12.0 (Latest LTS: Hydrogen) v19.0.0
特定のバージョンのノードをインストール
$ nvm install 18.12.0 Downloading and installing node v18.12.0... Downloading https://nodejs.org/dist/v18.12.0/node-v18.12.0-linux-x64.tar.xz... ######################################################################### 100.0% Computing checksum with sha256sum Checksums matched! Now using node v18.12.0 (npm v8.19.2) Creating default alias: default -> 18.12.0 (-> v18.12.0) $ nvm current v18.12.0
インストール済みバージョンを表示
$ nvm list -> v18.12.0 system default -> 18.12.0 (-> v18.12.0) iojs -> N/A (default) unstable -> N/A (default) node -> stable (-> v18.12.0) (default) stable -> 18.12 (-> v18.12.0) (default) lts/* -> lts/hydrogen (-> v18.12.0) lts/argon -> v4.9.1 (-> N/A) lts/boron -> v6.17.1 (-> N/A) lts/carbon -> v8.17.0 (-> N/A) lts/dubnium -> v10.24.1 (-> N/A) lts/erbium -> v12.22.12 (-> N/A) lts/fermium -> v14.21.0 (-> N/A) lts/gallium -> v16.18.0 (-> N/A) lts/hydrogen -> v18.12.0
使用するバージョンを切り替える
$ nvm use system system $ nvm use 18.12.0 Now using node v18.12.0 (npm v8.19.2)
VSCode リモートコンテナ機能
リモートSSH機能
拡張機能ビューから「Remote Development」をインストール。
Ctrl+Shift+Pから「Dev Containers: Add Dev Container Configuration File...」を入力するか、左下のリモート開発機能アイコンから「Add Dev Container Configuration File...」を選択。 一覧から適合した環境を選択する。
.devcontainerディレクトリが作成され、Dev Containerの設定ファイルdevcontainer.jsonと、Dockerfileが生成される。
フォルダを開くと、Dev Container内でワークスペースを開き直すかを確認するダイアログが表示される。「Reopen in Container」を選択すると、リモートコンテナ機能が有効になったVSCodeが再起動する。手動で行う場合は「Remote-Containers: Reopen Folder in Container」。