セレクター
WebDriver プロトコルは、要素を照会するためのいくつかのセレクターストラテジーを提供します。WebdriverIO は、要素の選択を簡単にするためにそれらを簡略化しています。要素を照会するコマンドは $
および $$
と呼ばれていますが、jQuery や Sizzle セレクターエンジンとは関係がないことに注意してください。
多くの異なるセレクターが利用可能ですが、適切な要素を見つけるための弾力性のある方法を提供するのはごくわずかです。たとえば、次のボタンの場合
<button
id="main"
class="btn btn-large"
name="submission"
role="button"
data-testid="submit"
>
Submit
</button>
次のセレクターを推奨するものと推奨しないものがあります。
セレクター | 推奨 | 備考 |
---|---|---|
$('button') | 🚨 絶対に推奨しない | 最悪 - 汎用的すぎて、コンテキストがない。 |
$('.btn.btn-large') | 🚨 絶対に推奨しない | 良くない。スタイリングに依存している。変更の影響を非常に受けやすい。 |
$('#main') | ⚠️ 控えめに | まだ良い。しかし、スタイリングや JS イベントリスナーに依存している。 |
$(() => document.queryElement('button')) | ⚠️ 控えめに | 効果的なクエリ、記述が複雑。 |
$('button[name="submission"]') | ⚠️ 控えめに | HTML セマンティクスを持つ name 属性に依存している。 |
$('button[data-testid="submit"]') | ✅ 良い | 追加の属性が必要で、a11y に接続されていない。 |
$('aria/Submit') または $('button=Submit') | ✅ 常に | 最良。ユーザーがページと対話する方法に似ています。翻訳が更新されたときにテストが失敗しないように、フロントエンドの翻訳ファイルを使用することをお勧めします。 |
CSS クエリセレクター
特に指定がない場合、WebdriverIO はCSS セレクターパターンを使用して要素を照会します。例:
loading...
リンクテキスト
特定のテキストを含むアンカー要素を取得するには、等号 (=
) で始まるテキストを照会します。
例:
loading...
この要素は、次のように呼び出すことで照会できます
loading...
部分リンクテキスト
表示テキストが検索値と部分的に一致するアンカー要素を見つけるには、クエリ文字列の前に *=
を使用して照会します(例:*=driver
)。
上記の例の要素は、次のように呼び出すことでも照会できます
loading...
注: 1 つのセレクターに複数のセレクターストラテジーを混在させることはできません。複数の連結された要素クエリを使用して同じ目標を達成してください。例:
const elem = await $('header h1*=Welcome') // doesn't work!!!
// use instead
const elem = await $('header').$('*=driver')
特定のテキストを持つ要素
同じ手法を要素にも適用できます。さらに、クエリ内で .=
または .*=
を使用して、大文字と小文字を区別しないマッチングを行うことも可能です。
たとえば、「Welcome to my Page」というテキストを持つレベル 1 の見出しのクエリは次のようになります。
loading...
この要素は、次のように呼び出すことで照会できます
loading...
または、部分テキストのクエリを使用します。
loading...
id
と class
の名前にも同じように機能します。
loading...
この要素は、次のように呼び出すことで照会できます
loading...
注: 1 つのセレクターに複数のセレクターストラテジーを混在させることはできません。複数の連結された要素クエリを使用して同じ目標を達成してください。例:
const elem = await $('header h1*=Welcome') // doesn't work!!!
// use instead
const elem = await $('header').$('h1*=Welcome')
タグ名
特定のタグ名を持つ要素を照会するには、<tag>
または <tag />
を使用します。
loading...
この要素は、次のように呼び出すことで照会できます
loading...
名前属性
特定の名前属性を持つ要素を照会するには、通常の CSS3 セレクターを使用するか、セレクターパラメーターとして [name="some-name"] のようなものを渡すことで、JSONWireProtocol から提供される名前ストラテジーを使用できます。
loading...
loading...
注: このセレクターストラテジーは非推奨であり、JSONWireProtocol プロトコルまたは Appium を使用して実行される古いブラウザーでのみ機能します。
xPath
特定のxPathを介して要素を照会することも可能です。
xPath セレクターの形式は //body/div[6]/div[1]/span[1]
のようになります。
loading...
2 番目の段落は、次のように呼び出すことで照会できます。
loading...
xPath を使用して、DOM ツリーを上下にトラバースすることもできます。
loading...
アクセシビリティ名セレクター
アクセス可能な名前で要素を照会します。アクセス可能な名前とは、要素にフォーカスが当たったときにスクリーンリーダーによってアナウンスされるものです。アクセス可能な名前の値は、視覚的なコンテンツと非表示のテキスト代替の両方になる可能性があります。
このセレクターの詳細については、リリースブログ記事をご覧ください
aria-label
で取得
loading...
loading...
aria-labelledby
で取得
loading...
loading...
コンテンツで取得
loading...
loading...
タイトルで取得
loading...
loading...
alt
プロパティで取得
loading...
loading...
ARIA - ロール属性
ARIA ロールに基づいて要素を照会するには、セレクターパラメーターとして [role=button]
のように要素のロールを直接指定できます。
loading...
loading...
ID 属性
ロケーターストラテジー「id」は WebDriver プロトコルではサポートされていません。ID を使用して要素を見つけるには、代わりに CSS または xPath セレクターストラテジーを使用する必要があります。
ただし、一部のドライバー(例:Appium You.i Engine Driver)は、このセレクターを依然としてサポートする場合があります。
現在サポートされている ID のセレクター構文は次のとおりです。
//css locator
const button = await $('#someid')
//xpath locator
const button = await $('//*[@id="someid"]')
//id strategy
// Note: works only in Appium or similar frameworks which supports locator strategy "ID"
const button = await $('id=resource-id/iosname')
JS 関数
JavaScript 関数を使用して、Web ネイティブ API を使用して要素を取得することもできます。もちろん、これは Web コンテキスト(例:browser
、またはモバイルの Web コンテキスト)内でのみ可能です。
次の HTML 構造の場合
loading...
次のように、#elem
の兄弟要素を照会できます
loading...
ディープセレクター
WebdriverIO の v9
以降では、この特別なセレクターは必要ありません。WebdriverIO は、シャドウ DOM を自動的に貫通するためです。先頭の >>>
を削除して、このセレクターからの移行をお勧めします。
多くのフロントエンドアプリケーションは、シャドウ DOM を持つ要素に大きく依存しています。回避策なしにシャドウ DOM 内の要素を照会することは、技術的には不可能です。shadow$
および shadow$$
は、制限があった回避策でした。ディープセレクターを使用すると、一般的なクエリコマンドを使用して、シャドウ DOM 内のすべての要素を照会できるようになりました。
次の構造を持つアプリケーションがあるとします
このセレクターを使用すると、別のシャドウ DOM 内にネストされている <button />
要素を照会できます。例:
loading...
モバイルセレクター
ハイブリッドモバイルテストでは、コマンドを実行する前に、自動化サーバーが適切なコンテキストにあることが重要です。ジェスチャーを自動化するには、ドライバーをネイティブコンテキストに設定するのが理想的です。ただし、DOM から要素を選択するには、ドライバーをプラットフォームの Webview コンテキストに設定する必要があります。その場合のみ、上記のメソッドを使用できます。
ネイティブモバイルテストの場合、コンテキスト間の切り替えは必要ありません。モバイル戦略を使用し、基盤となるデバイス自動化技術を直接使用する必要があるためです。これは、テストが要素の検索においてきめ細かい制御を必要とする場合に特に役立ちます。
Android UiAutomator
AndroidのUI Automatorフレームワークは、要素を見つけるための多くの方法を提供します。特にUI Automator API、UiSelectorクラスを使用して要素を特定できます。Appiumでは、Javaコードを文字列としてサーバーに送信し、サーバーがアプリケーションの環境で実行し、要素または要素の集合を返します。
const selector = 'new UiSelector().text("Cancel").className("android.widget.Button")'
const button = await $(`android=${selector}`)
await button.click()
Android DataMatcherとViewMatcher (Espressoのみ)
AndroidのDataMatcher戦略は、Data Matcherによって要素を見つける方法を提供します。
const menuItem = await $({
"name": "hasEntry",
"args": ["title", "ViewTitle"]
})
await menuItem.click()
同様にView Matcherも利用できます。
const menuItem = await $({
"name": "hasEntry",
"args": ["title", "ViewTitle"],
"class": "androidx.test.espresso.matcher.ViewMatchers"
})
await menuItem.click()
Android View Tag (Espressoのみ)
view tag戦略は、要素をtagで検索する便利な方法を提供します。
const elem = await $('-android viewtag:tag_identifier')
await elem.click()
iOS UIAutomation
iOSアプリケーションを自動化する場合、AppleのUI Automationフレームワークを使用して要素を見つけることができます。
このJavaScript APIには、ビューとその上のすべての要素にアクセスするためのメソッドがあります。
const selector = 'UIATarget.localTarget().frontMostApp().mainWindow().buttons()[0]'
const button = await $(`ios=${selector}`)
await button.click()
また、Appium内のiOS UI Automation内で述語検索を使用して、要素の選択をさらに絞り込むこともできます。詳細については、こちらを参照してください。
iOS XCUITest述語文字列とクラスチェーン
iOS 10以上(XCUITest
ドライバーを使用)では、述語文字列を使用できます。
const selector = `type == 'XCUIElementTypeSwitch' && name CONTAINS 'Allow'`
const switch = await $(`-ios predicate string:${selector}`)
await switch.click()
そして、クラスチェーンも使用できます。
const selector = '**/XCUIElementTypeCell[`name BEGINSWITH "D"`]/**/XCUIElementTypeButton'
const button = await $(`-ios class chain:${selector}`)
await button.click()
アクセシビリティID
accessibility id
ロケータ戦略は、UI要素の一意の識別子を読み取るように設計されています。これにより、ローカライゼーションやテキストを変更する可能性のあるその他のプロセス中に変更されないという利点があります。さらに、機能的に同じ要素が同じアクセシビリティIDを持つ場合、クロスプラットフォームテストの作成に役立ちます。
- iOSの場合、これはAppleによってこちらで説明されている
accessibility identifier
です。 - Androidの場合、
accessibility id
は、こちらで説明されているように、要素のcontent-description
にマッピングされます。
両方のプラットフォームで、要素(または複数の要素)をaccessibility id
で取得する方法は通常、最良の方法です。また、非推奨のname
戦略よりも推奨される方法です。
const elem = await $('~my_accessibility_identifier')
await elem.click()
クラス名
class name
戦略は、現在のビュー上のUI要素を表すstring
です。
- iOSの場合、UIAutomationクラスの完全な名前であり、テキストフィールドの場合は
UIATextField
のようにUIA-
で始まります。完全なリファレンスは、こちらにあります。 - Androidの場合、これはUI Automator クラスの完全修飾名であり、テキストフィールドの場合は
android.widget.EditText
のようになります。完全なリファレンスは、こちらにあります。 - Youi.tvの場合、これはYoui.tvクラスの完全な名前であり、プッシュボタン要素の場合は
CYIPushButtonView
のようにCYI-
で始まります。完全なリファレンスは、You.i Engine DriverのGitHubページにあります。
// iOS example
await $('UIATextField').click()
// Android example
await $('android.widget.DatePicker').click()
// Youi.tv example
await $('CYIPushButtonView').click()
チェーンセレクター
クエリでより具体的に指定したい場合は、適切な要素が見つかるまでセレクターをチェーンできます。実際のコマンドの前にelement
を呼び出すと、WebdriverIOはその要素からクエリを開始します。
たとえば、次のようなDOM構造がある場合
<div class="row">
<div class="entry">
<label>Product A</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product B</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product C</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
</div>
製品Bをカートに追加したい場合、CSSセレクターを使用するだけでは困難です。
セレクターチェーンを使用すると、はるかに簡単になります。目的の要素を段階的に絞り込むだけです。
await $('.row .entry:nth-child(2)').$('button*=Add').click()
Appium Image Selector
-image
ロケータ戦略を使用すると、アクセスしたい要素を表す画像ファイルをAppiumに送信できます。
サポートされているファイル形式:jpg,png,gif,bmp,svg
完全なリファレンスはこちらにあります。
const elem = await $('./file/path/of/image/test.jpg')
await elem.click()
注意:Appiumがこのセレクターを使用する方法は、内部的に(アプリ)スクリーンショットを作成し、その(アプリ)スクリーンショット内で要素が見つかるかどうかを検証するために、提供された画像セレクターを使用することです。
Appiumが、取得した(アプリ)スクリーンショットのサイズを、(アプリ)画面のCSSサイズに合わせて変更する可能性があることに注意してください(これは、iPhoneだけでなく、DPRが1より大きいRetinaディスプレイを備えたMacマシンでも発生します)。これにより、提供された画像セレクターが元のスクリーンショットから取得されたものである可能性があるため、一致するものが見つからない結果になることがあります。これは、Appium Serverの設定を更新することで修正できます。設定についてはAppiumドキュメントを、詳細な説明についてはこのコメントを参照してください。
Reactセレクター
WebdriverIOは、コンポーネント名に基づいてReactコンポーネントを選択する方法を提供します。これを行うには、react$
とreact$$
の2つのコマンドから選択できます。
これらのコマンドを使用すると、React VirtualDOMからコンポーネントを選択し、単一のWebdriverIO要素または要素の配列(使用する関数に応じて)を返すことができます。
注意:コマンドreact$
とreact$$
は機能が似ていますが、react$$
は一致するすべてのインスタンスをWebdriverIO要素の配列として返し、react$
は最初に見つかったインスタンスを返します。
基本的な例
// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
function MyComponent() {
return (
<div>
MyComponent
</div>
)
}
function App() {
return (<MyComponent />)
}
ReactDOM.render(<App />, document.querySelector('#root'))
上記のコードでは、アプリケーション内に単純なMyComponent
インスタンスがあり、Reactはそれをid="root"
を持つHTML要素内でレンダリングしています。
browser.react$
コマンドを使用すると、MyComponent
のインスタンスを選択できます。
const myCmp = await browser.react$('MyComponent')
これで、WebdriverIO要素がmyCmp
変数に格納されたため、要素コマンドを実行できます。
コンポーネントのフィルタリング
WebdriverIOが内部で使用するライブラリでは、コンポーネントのpropsおよび/またはstateで選択をフィルタリングできます。これを行うには、ブラウザコマンドに2番目の引数としてprops、3番目の引数としてstateを渡す必要があります。
// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
function MyComponent(props) {
return (
<div>
Hello { props.name || 'World' }!
</div>
)
}
function App() {
return (
<div>
<MyComponent name="WebdriverIO" />
<MyComponent />
</div>
)
}
ReactDOM.render(<App />, document.querySelector('#root'))
name
というpropがWebdriverIO
であるMyComponent
のインスタンスを選択する場合は、次のようにコマンドを実行できます。
const myCmp = await browser.react$('MyComponent', {
props: { name: 'WebdriverIO' }
})
stateで選択をフィルタリングする場合は、browser
コマンドは次のようになります。
const myCmp = await browser.react$('MyComponent', {
state: { myState: 'some value' }
})
React.Fragment
の処理
react$
コマンドを使用してReact フラグメントを選択すると、WebdriverIOはそのコンポーネントの最初の子供をコンポーネントのノードとして返します。react$$
を使用すると、セレクターに一致するフラグメント内のすべてのHTMLノードを含む配列が返されます。
// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
function MyComponent() {
return (
<React.Fragment>
<div>
MyComponent
</div>
<div>
MyComponent
</div>
</React.Fragment>
)
}
function App() {
return (<MyComponent />)
}
ReactDOM.render(<App />, document.querySelector('#root'))
上記の例の場合、コマンドは次のように動作します。
await browser.react$('MyComponent') // returns the WebdriverIO Element for the first <div />
await browser.react$$('MyComponent') // returns the WebdriverIO Elements for the array [<div />, <div />]
注意:MyComponent
の複数のインスタンスがあり、react$$
を使用してこれらのフラグメントコンポーネントを選択すると、すべてのノードの1次元配列が返されます。つまり、3つの<MyComponent />
インスタンスがある場合、6つのWebdriverIO要素の配列が返されます。
カスタムセレクターストラテジー
アプリが要素を取得するための特定の方法を必要とする場合は、custom$
およびcustom$$
で使用できるカスタムセレクターストラテジーを自分で定義できます。そのためには、テストの開始時、たとえばbefore
フックで、ストラテジーを一度登録します。
loading...
次のHTMLスニペットが与えられた場合
loading...
次のように呼び出して使用します。
loading...
注意:これは、execute
コマンドを実行できるWeb環境でのみ機能します。