ブラウザー・スクリプト
Node.js ベースのスクリプトや Selenium ベースの API を使用することで、 Instana のブラウザテストを実行できます。 あらかじめ定義されたグローバル変数と Instana のブラウザテストAPIを使用すれば、Webブラウザでのユーザーの操作をシミュレートするブラウザスクリプトテストを作成し、実行することができます。
Instana ブラウザスクリプトの参照
ブラウザー・テストを使用可能にするためにブラウザー・スクリプト・テストを作成するには、グローバル変数およびモジュールが必要です。
グローバル変数
表に概説されている事前定義グローバル変数は、スクリプト開発を加速します。
| 名前 | タイプ | 詳細 |
|---|---|---|
$driver |
@types/selenium-webdriver |
Selenium WebDriverJS の型定義です。 |
$browser |
ThenableWebDriver |
WebDriver クライアントのラッパーを使用可能にします。これにより、ブラウザーを制御し、 thenを呼び出さずに Promise<WebDriver> 上で WebDriver メソッドを直接呼び出すことができます。 |
$secure |
Dict<string> |
ユーザー資格情報にアクセスするための変数。 |
$util |
UserUtil |
$util.secretsなどのユーティリティー関数。 |
$network |
Network |
プロキシーをセットアップするためのネットワーク・ユーティリティー。 |
$synthetic |
Dict<string> |
環境変数。 |
$attributes |
UserInsight |
カスタマイズされた属性を追加および操作するための変数。 |
事前定義グローバル変数の使用法と宣言は、以下のとおりです。
$synthetic
$synthetic.var_name を使用して、スクリプト内の環境変数およびランタイム変数にアクセスできます。 いくつかの事前定義変数を以下に示します。
$synthetic.LOCATIONまたは$synthetic.pop: 変数controller.locationの先頭部分である位置ラベルにアクセスするために使用されます。$synthetic.TEST_IDまたは$synthetic.id: 実行された合成テストの識別子にアクセスするために使用されます。$synthetic.TEST_NAMEまたは$synthetic.testName: 実行された合成テストのテストラベルにアクセスするために使用されます。$synthetic.TIME_ZONEまたは$synthetic.timeZone: 合成テストを実行している PoP のタイムゾーンを取得するために使用します。$synthetic.JOB_IDまたは$synthetic.taskId: 再生ジョブまたはタスクの識別子にアクセスするために使用され、結果IDでもあります。$synthetic.testType: テストタイプにアクセスするために使用します。$synthetic.description: テストの説明にアクセスするために使用します。$synthetic.labels.xxx: テスト定義の セクションcustomPropertiesで定義されたカスタムプロパティにアクセスするために使用します。
また、 helm チャートの`environment.yml` values.yaml ファイルで、カスタム環境変数を定義することもできます。 以下の例を参照してください。
controller:
customProperties: "tag1=value1;tag2=value2"
これらのカスタム変数にアクセスするには、スクリプトで $synthetic.tag1 および $synthetic.tag2 を使用します。
テスト定義の customProperties セクションで定義されているカスタム・プロパティーと、スクリプト内のプロパティー値にアクセスするには、 $synthetic.labels.xxxを使用します。 以下の例を参照してください。
// to print test custom property defined in customProperties of test definition
console.info('Test custom property -> Team: ' + $synthetic.labels.Team);
console.info('Test custom property -> Purpose: ' + $synthetic.labels.Purpose);
$secure
Instana のブラウザスクリプトは、ログインユーザー名やパスワードなどの機密情報を安全に保存するために、ユーザー認証情報をサポートしています。 $secure.MY_SECURE_CREDENTIAL を使用して、スクリプト内の事前定義されたセキュア資格情報を参照できます。
Synthetic Open API を使用して認証情報を作成するには、以下の手順を実行してください:
- 適切な権限設定になっていることを確認してください。
- OpenAPI または synctl コマンドを使用し、および
credentialValuecredentialName変数を指定して認証情報を作成します。
次に、ブラウザー・スクリプトで、 $secure.credentialName を使用して、作成した資格情報 ( $secure.password や $secure.usernameなど) を参照します。
$secure.credentialName 形式のみです。 この $secure[credentialName] 形式はサポートされていません。$secure.credentialName)は、スクリプトの実行前に解決されます。 資格情報の名前を直接指定する必要があります。 eval()変数や文字列連結、または を使用して参照を動的に構築しないでください。これらの方法はサポートされておらず、評価されません。$attributes
$attributes 変数を使用して、モニター・データにカスタム属性を追加または取得できます。 これらのカスタム属性は、他のデフォルトのモニター結果属性とともにモニター結果にも保管されます。
Instana Synthetic Monitoringでは、カスタム属性を設定するために以下のAPIをサポートしています:
$attributes.set(key, value): キーまたは値を設定します。$attributes.get(key): 指定されたキーの値を返します。$attributes.getKeys(): すべてのキーの配列を返します。$attributes.has(key): キーが存在する場合はtrueを返します。$attributes.unset(key): 指定されたキーまたは値を削除します。$attributes.unsetAll(): すべてのカスタム・データを削除します。
次の例は、 API $attributes を示しています:
$attributes.set(xxx, yyy) // sets tag xxx to value yyy
let v = $attributes.get(xxx) // sets variable v to the value of tag xxx
$attributesAPI ` で設定されたカスタム属性や、テスト定義の ` customProperties section` で定義されたカスタムプロパティは、テスト結果内で ` synthetic.tags metric` を使用して参照できます。また、`metric synthetic.tags ` を使用してテスト結果をフィルタリングしたり、Smart Alert のカスタムペイロードにカスタム値を渡したりすることも可能です。$network
Instana のSyntheticモニタリングでは、プロキシサーバーの設定に関して以下のAPIがサポートされています:
$network.setProxy(string proxy): すべてのリクエスト( HTTP、 HTTPS )で使用するプロキシサーバーを設定します。$network.setProxyForHttp(string proxy): HTTP へのリクエストにのみ使用するプロキシサーバーを設定します。$network.setProxyForHttps(string proxy): HTTPs 要求にのみ使用するプロキシー・サーバーを設定します。$network.setProxyPAC(string pac, object auth): プロキシー自動構成 (PAC) スクリプトを使用してプロキシー・サーバーを設定します。$network.setProxyAdvanced(object proxy): プロキシ設定を、Chrome/ Firefox 拡張機能( API )でサポートされている形式を使用して設定します。$network.clearProxy(): プロキシー構成を削除します。$network.getProxy(): プロキシー構成を返します。
$util.secrets
機密情報を伏せるには、セキュリティ $util.secretsAPI を使用できます。
URL からシークレットを編集するには、スクリプトで $util.secrets.setURLSecretsRegExps コマンドを使用します。 以下の例を参照してください。
// to redact 'key', 'password' and 'secret' query parameters in URL
$util.secrets.setURLSecretsRegExps([/key/i, /password/i, /secret/i]);
この API を呼び出すと、 URLhttps://example.com/accounts/status?key=mykey123&secret=mysecret が収集され、 Instanahttps://example.com/accounts/status?key=*&secret=* のUIに表示されます。
Instana Syntheticは、 Instana の現在の設計と整合性を保つため、すべてのリクエストおよびレスポンスヘッダーを削除します。
デフォルトでは、 Instana は機密データの送信を防ぐため、 HTTP への呼び出しを追跡する際に HTTP ヘッダーを収集しません。
ブラウザテストに関する API の参考資料
ブラウザー・テストでは、 Seleniumベースの API と、その他の 30 を超える拡張ブラウザー・テスト API がサポートされます。 詳細については、 『 API リファレンス』 を参照してください。
ブラウザスクリプトのテストを作成する
以下のアクションのブラウザー・スクリプト・テストを作成して、ブラウザー・テストを有効にすることができます。 サンプル・コードは、一般的に使用される API を使用してブラウザー・スクリプト・テストを作成する方法を示しています。 完全なサンプル・コードについて詳しくは、「 スクリプトの例 」セクションを参照してください。
基本的なアクションの実装
以下のサンプル・コードは、以下の基本アクションを実装するためのブラウザー・スクリプト・テストの作成方法を示しています。
ヘッダーの準備: Web サイトにアクセスする前に要求ヘッダーをカスタマイズするには、以下のコマンドを使用します。
await $browser.addHeader("test", "test"); await $browser.addHeaders({ "test1": "test1", "test2": "test2" }); await $browser.deleteHeaders(["test1", "test2"]); $browser.getHeaders().forEach((value, key) => console.log(">>>>>>>>>>>>>>>>>>>", "User customized headers: ", key + "=" + value));アクセスの制御: 拒否リストと許可リストを使用してアクセスを制御するには、以下のコマンドを使用します。
await $browser.addHostnamesToDenylist(["*google*", "*timeanddate*"]); await $browser.deleteHostnameFromDenylist("*timeanddate*"); await $browser.get("https://www.google.com");これらのコマンドを実行した後、Googleで検索すると、そのメッセージが表示されます
wwww.google.com is blocked。URL を開く:ブラウザで URL を開いてウェブサイトにアクセスするには、次のコマンドを使用します:
await $browser.get("http://www.bing.com");スリープ時間の設定: ブラウザーでスリープ・オプションを設定するには、以下のコマンドを使用します。 パラメーターは、スリープする時間 (ミリ秒) です。 次の例では、ブラウザーは 2 秒間スリープします。
await $browser.sleep(2000);ページ・タイトル「Assertion is critical in your tests to determine the test results」でアサーションを使用してください。 ページ・タイトルまたはページ・ソースでアサーションを使用するには、以下のコードを使用します。 ライブラリー
const assert = require("assert").strict;またはCハイ・アサーション・ライブラリーconst { assert } = require("chai");を使用できます。console.logを使用して、コンソール出力およびコンソール・ログ・ファイルにログインします。const { assert } = require("chai"); await $browser.get("http://www.timeanddate.com"); let page = await $browser.getPageSource(); assert.isTrue(page.includes("<title>timeanddate.com</title>")); console.log(">>>>>>>>>>>>>>>>>>>", "Page title: ", await $browser.getTitle());セッションの取得: セッションに関する情報を取得するには、以下のコマンドを使用します。
let session = await $browser.getSession(); console.log(">>>>>>>>>>>>>>>>>>>", "Session id: ", session.getId());ウィンドウ・サイズの最大化: ブラウザー・ウィンドウ・サイズを最大化するには、次のコマンドを使用します。
$browser.manage().window().maximize();スクリーン・ショットの取得: ブラウザーのスクリーン・ショットを取得するには、以下のコマンドを使用します。
await $browser.takeScreenshot();
ページ要素の検索と操作
待機してページでエレメントを見つけます。以下の表のコマンドを使用して、特定の検索を行うことができます。
名前 使用 $browser.waitForAndFindElement($driver.By.id("boxyear"), 1000)エレメントが可視になるまで、またはタイムアウト値に達するまで、ID によってエレメントを検索します。 $browser.findElements($driver.By.css('select'))CSS セレクターを使用してページ上の複数のエレメントを検索します。 $browser.findElement($driver.By.linkText("About"))linkTextで要素を検索します。 $browser.findElement($driver.By.xpath('//input[@value='f']'))XPath でエレメントを検索します。 $browser.$('#boxyear')ID によってエレメントを検索します。 $browser.$$(".rd-box")クラスごとにエレメントを検索します。 elem.$('h2').$('a').getText()エレメント名でエレメントを検索します。 以下のサンプル・コードは、ページ上で待機してエレメントを見つける方法を示しています。
// Find element by XPath and wait for the element until specified timeout value reached await $browser.waitForAndFindElement($driver.By.xpath(`//textarea[@inputmode='search']`), 10000); // Find element by id let elem = await $browser.waitForAndFindElement($driver.By.id("boxyear"), 1000); assert.equal("2022", await elem.getAttribute("value")); assert.equal("2022", await $browser.$('#boxyear').getAttribute("value")); // Find elements by CSS selector let selects = await $browser.findElements($driver.By.css('select')); assert.equal(2, selects.length); // Find elements by class let elems = await $browser.$$(".rd-box"); console.log(await elems[0].$('h2').$('a').getText());要素の検索とアクションの実行:以下の例は、 CSSセレクタで要素を検索し、 ActionSequence を使用してキー入力を送信する方法を示しています:
<input id="sb_form_q" name="q" type="search">let textarea = await $browser.waitForAndFindElement($driver.By.css('#sb_form_q'), 10000); // Actions to send keys await $browser .actions() .move({ origin: textarea }) .sendKeys("synthetic") .pause(5000) .sendKeys($driver.Key.ENTER) .perform();
条件の適用
Wait until タイトルが condition: タイトルが条件になるまで待機を適用するには、次のコマンドを使用します。
await $browser.wait($driver.until.titleContains('Year 2022 Calendar'), 10000);タイムアウト条件まで待機およびポーリング: タイムアウト条件まで待機およびポーリングを適用するには、以下のコマンドを使用します。
注: 以下のサンプルは、以前のバージョンと互換性のあるプロミスチェーンの呼び出しです。 最新の JavaScript では、このコードを使用しないでください。 その代わりに、AsyncとAwaitを使った最新の非同期 JavaScript を使用してください。$browser.get("https://www.google.com"); $browser.wait(function () { return $browser.getTitle().then(function (title) {return title.includes("Google");}); }, 10000).then(function () { return $browser.findElement($driver.By.linkText("About")).click(); }).then(function () { return $browser.navigate().back(); });
ブラウザの閲覧履歴を閲覧する
戻る: ブラウザーで前にアクセスしたページに戻るには、以下のコマンドを使用します。
await $browser.navigate().back();新規タブへの切り替え: 現行ウィンドウ・ハンドルを取得し、新規ウィンドウに切り替えて新規タブで新規ページを開き、元のウィンドウに戻るには、以下のコードを使用します。
console.log("Windows handle: ", await $browser.getWindowHandle(), "Current url: ", await $browser.getCurrentUrl()); let originalWindow = await $browser.getWindowHandle(); await $browser.switchTo().newWindow(); await $browser.get("http://www.timeanddate.com"); await $browser.switchTo().window(originalWindow); await $browser.takeScreenshot();
マウスの移動とキーの送信
マウス・クリック: マウスを移動するには、次のコマンドを使用します。
const element = await $browser.waitForAndFindElement(by, timeout); const out = $browser.actions().move({origin: element}).press().release().perform();マウス・ポインター移動: ブラウザー要素の上にマウスを移動するには、次のコマンドを使用します。
const element = await $browser.waitForAndFindElement(by, timeout); const out = $browser.actions().move({origin: element, duration: 2000}).perform();鍵の送信: 鍵を送信するには、以下のコマンドを使用します。
await $browser.actions().sendKeys("synthetic").perform();
Shadow DOM 要素の処理
シャドー DOM エレメントにアクセスするには、 getShadowRoot() 関数を使用できます。 新しいメソッドは、シンセティック PoP Helm チャート 1.1.1 以降でサポートされます。 シャドー DOM 対話のサポートを有効にするには、Synthetic PoP バージョンを 1.1.1 以降に アップグレード する必要があります。
let shadowHost = await $browser.waitForAndFindElement(shadowHostSelector, timeout);
let shadowRoot = await shadowHost.getShadowRoot();
let element = await shadowRoot.findElement(elementSelector);
console.log("element text is:", await element.getText(), ", id is:", await element.getId());
Webサイトにアクセスするためのプロキシの設定
HTTP および HTTPS へのリクエストに対して、`proxy` または `
$network$browserproxy-name` 変数を使用してプロキシを設定するには、次のコマンドを実行します。 プロキシーは、stringまたはurl.URLを使用して設定できます。await $network.clearProxy(); await $network.setProxyForHttp(proxyServer); website = await accessWebSite(); checkHostname("www.google.com.hk", website) await $network.clearProxy(); let testURL = new URL("http://" + sslProxyServer); await $network.setProxyForHttps(testURL); website = await accessWebSite(); checkHostname("www.google.com", website);バイパス・リストを使用してフィルターに掛けるすべての要求に対してプロキシーを設定するには、以下のコマンドを使用します。 以下の例でこのコマンドを実行した後、 www.google.comで使用可能なプロキシーはありません。
await $network.clearProxy(); await $network.setProxy(proxyServer, "www.google.com"); console.log(">>>>>>>>>>>>>>>>>>>", "Bypass list: ", $network.getProxy().rules.bypassList); website = await accessWebSite(); checkHostname("www.google.com.hk", website);
機密情報の黒塗り
URL で機密データをマスキングするには、次のコマンドを使用します。 次の例では、 URL は.に置き換えられています "url": "https://www.bing.com/?mkt=zh-CN&toHttps=1&redig=*"。
$util.secrets.setURLSecretsRegExps([/redig/i]);
console.log(">>>>>>>>>>>>>>>>>>>", "Access bing");
await $browser.get("http://cn.bing.com");
await $browser.wait($driver.until.titleContains('Bing'), 10000);
モジュールの管理
サード・パーティー・モジュール、コア・モジュール、またはオプション・モジュールをブラウザー・テスト・スクリプトにインポートできます。
オプションモジュールのインポート
以下の例は、アサーション・モジュール chaiをインポートするコマンドを示しています。
var assert = require('chai').assert;
対応コアモジュール
Instana ブラウザテストは、 Node.js v18 以降で、 Node.js のコアモジュールをサポートしています。
child_processおよび、ならびに fs `write`や`rm`操作を含む process、いくつかの組み込みモジュールやAPIがサポートされていません。 これらの API をテスト・スクリプトまたはバンドル・スクリプトで使用すると、テスト結果が以下のエラー・メッセージで失敗する可能性があります。 そのため、これらの API をテスト・スクリプトで使用しないでください。[SyntheticPoP] [ERROR] process.exit is not allowed. This API is blocked by playback engine.
対応しているサードパーティ製モジュール
Instana Synthetic Monitoringは、以下のサードパーティ製モジュールに対応しています:
- @aws-sdk/client-s3 3.626.0
- VOB 2.1.2
- オーセンティケーター 1.1.5
- basic-ftp 4.6.6
- btoa 1.2.1
- chai 4.3.10
- 色 1.4.0
- consoleplusplus 1.4.4
- 暗号 js 4.2.0
- Faker 5.5.3
- 11.8.6 を取得しました
- Ji 17.7.1
- js-yaml 4.1.0
- ldapauth-fork 5.0.2
- 宿泊施設 4.17.21
- モーメント 2.29.4
- net-snmp 3.6.3
- protocol-buffers 4.2.0
- 1.5.1
- re2 1.18.3
- ssh2-sftp-client 7.2.3
- ssl チェッカー 2.0.7
- テキスト・エンコード 0.7.0
- スリフト 0.14.2
- totp-generator 0.0.14
- タフクッキー 4.1.3
- 下線 1.13.3
- url-parse 1.5.10
- urllib 2.41.0
- uuid 3.4.0
- バリデーター 13.7.0
- ws 7.5.10
- xml2js 0.5.0
スクリプトの例
以下の例には、ほとんどのブラウザー・テスト API と完全なサンプル・コードが含まれています。
これらのサンプルは、デモンストレーションのみを目的としています。 最新のサンプルは、公開リポジトリ GitHub でご覧いただけます。
アクションの完全なサンプルコード
let click = async (message, by, timeout = 60000) => {
console.log(`Click on ${message} >> ${by} << `);
try {
const element = await $browser.waitForAndFindElement(by, timeout);
return $browser.actions().move({ origin: element }).click().perform();
} catch (err) {
console.error(`\ncatch(click): ${err.message}`);
throw err;
}
};
let hover = async (message, by, timeout = 60000) => {
console.log(`Hover on ${message} >> ${by} << `);
try {
const element = await $browser.waitForAndFindElement(by, timeout);
return $browser.actions().move({ origin: element, duration: 3000 }).perform();
} catch (err) {
console.error(`\ncatch(hover): ${err.message}`);
throw err;
}
};
(async function () {
console.log(">>>>>>>>>>>>>>>>>>>", "Access bing page");
await $browser.get("http://www.bing.com");
console.log(">>>>>>>>>>>>>>>>>>>", "Actions of search");
await hover("search button", $driver.By.xpath("//label[@id='search_icon']"), 10000);
await $browser.takeScreenshot();
await $browser.actions().sendKeys("synthetic").perform();
await click("search button", $driver.By.xpath("//label[@id='search_icon']"), 10000);
})();
APIの完全なサンプルコード
const { assert } = require("chai");
(async function () {
/**
* manipulate headers and retrieve all the customized headers
*/
await $browser.addHeader("test", "test");
await $browser.addHeaders({ "test1": "test1", "test2": "test2" });
await $browser.deleteHeaders(["test1", "test2"]);
$browser.getHeaders().forEach((value, key) => console.log(">>>>>>>>>>>>>>>>>>>", "User customized headers: ", key + "=" + value));
/**
* manipulate deny and allow list
*/
await $browser.addHostnamesToDenylist(["*google*", "*timeanddate*"]);
await $browser.deleteHostnameFromDenylist("*timeanddate*");
/**
* open url www.bing.com
* find element by class selector
* send keys to search Synthetic in the page
*/
console.log(">>>>>>>>>>>>>>>>>>>", "Access bing page");
await $browser.get("http://www.bing.com");
console.log(">>>>>>>>>>>>>>>>>>>", "Actions of search");
// Find element by XPath and wait for the element until specified timeout value reached
await $browser.waitForAndFindElement($driver.By.xpath(`//textarea[@inputmode='search']`), 10000);
// Sleep or pause to wait for specified milliseconds
await $browser.sleep(5000);
// Take a screenshot
await $browser.takeScreenshot();
// Actions to send keys
await $browser.actions().sendKeys("synthetic").sendKeys($driver.Key.ENTER).perform();
/* Find element by CSS selector and perform actions
let textarea = await $browser.waitForAndFindElement($driver.By.css('#sb_form_q'), 10000);
// Actions to send keys
await $browser
.actions()
.move({ origin: textarea })
.sendKeys("synthetic")
.pause(5000)
.sendKeys($driver.Key.ENTER)
.perform();
*/
/**
* samples of promise chain invocation, which is not recommended but backwards compatible
* samples of waiting and polling function with timeout value
*/
await $browser.deleteHostnameFromDenylist("*google*");
await $browser.get("https://www.google.com");
// Call the wait function.
await $browser.wait(function () {
return $browser.getTitle().then(function (title) {
return title.includes("Google");
});
//If the condition isn't satisfied within 10000 milliseconds (10 seconds), proceed anyway.
}, 10000).then(function () {
return $browser.findElement($driver.By.linkText("About")).click();
}).then(function () {
return $browser.navigate().back();
});
})();
プロキシの完全なサンプルコード
const url = require("url");
const URL = url.URL;
const { assert } = require("chai");
let website;
let proxyServer = "proxyHost:proxyPort";
let sslProxyServer = "username:password@proxyHost:proxyPort";
async function accessWebSite(url) {
console.log(">>>>>>>>>>>>>>>>>>>", "Proxy configuration is: ", JSON.stringify($network.getProxy()));
console.log(">>>>>>>>>>>>>>>>>>>", `Access website ${url}`);
await $browser.get(url);
await $browser.findElement($driver.By.name('q')).click();
await $browser.actions().sendKeys('synthetic').sendKeys($driver.Key.ENTER).perform();
await $browser.takeScreenshot();
return $browser.getCurrentUrl();
}
function checkHostname(hostname, website) {
let actualURL = new URL(website);
console.log(">>>>>>>>>>>>>>>>>>>", "Hostname is: ", actualURL.hostname);
assert.equal(actualURL.hostname, hostname);
}
(async function () {
/**
* samples of proxy configuration settings with await asynchronous
* using $network tools
*/
console.log(">>>>>>>>>>>>>>>>>>>", "Clear proxy configuration");
await $network.clearProxy();
console.log(">>>>>>>>>>>>>>>>>>>", "Set proxy configuration for HTTPS request with string");
await $network.setProxyForHttps(proxyServer);
website = await accessWebSite("https://www.bing.com");
checkHostname("www.bing.com", website)
console.log(">>>>>>>>>>>>>>>>>>>", "Clear proxy configuration");
await $network.clearProxy();
console.log(">>>>>>>>>>>>>>>>>>>", "Set proxy configuration for HTTPS request with URL object");
let testURL = new URL("http://" + sslProxyServer);
await $network.setProxyForHttps(testURL);
website = await accessWebSite("https://www.google.com");
checkHostname("www.google.com", website);
/**
* samples of proxy configuration settings with bypass list
*/
await $network.clearProxy();
await $network.setProxy(proxyServer, "www.google.com");
console.log(">>>>>>>>>>>>>>>>>>>", "Proxy config: ", $network.getProxy());
website = await accessWebSite("https://www.bing.com");
checkHostname("www.bing.com", website);
})();