- 印刷
- ダークライト
Webアプリケーションのテストにおいては、CSSセレクターを使用して要素を選択する場面が多くあります。
Autifyにおいては、Autifyレコーダーで「シナリオ」をレコーディングする範囲では特段CSSセレクターを意識する必要はありませんが、ロケータやJSステップをご利用いただく際にCSSセレクターを書く場面が発生します。
ロケータでご紹介しているように、Google Chromeのデベロッパーツールを使用すると要素のCSSセレクターが簡単に取得出来ますが、デベロッパーツールで取得したCSSセレクターをそのままロケータやJSステップで指定すると上手くいかないケースがあります(詳細は後でご説明します)。
当記事では、より良いCSSセレクターの指定の仕方を解説します。
1. 基本的なCSSセレクター
CSSセレクターの基本的な要素の指定をする際によく使うセレクターをご紹介します。
1.1. 基本のセレクター
指定方法 | 指定例 |
---|---|
タグ名で指定 | div, a |
class名で指定 | .main, .sub |
id名で指定 | #a123, #b456 |
タグ名・class名・id名を組み合わせて指定 | div#a123.main, a.sub |
1.2. よく使うセレクター
指定方法 | 指定例 |
---|---|
子孫要素 | .main .sub, div a |
直下の子要素 | .main > .sub, div > a |
最初の子要素 | div:first-child |
最後の子要素 | div:last-child |
〇〇番目の子要素 | li:nth-child(n) |
1.3. 知っていると便利なセレクター
指定方法 | 指定例 |
---|---|
属性で指定 | a[href="https://example.com/index.html"], p[class="main"] |
属性内容の“一部”が一致する要素 | a[href*="example.com"], p[class*="ai"] |
属性内容の“始め”が一致する要素 | a[href^="https://"], p[class^="ma"] |
属性内容の“最後”が一致する要素 | a[href$="index.html"], p[class$="in"] |
非活性状態 | input:disabled, textarea:disabled |
1.4. フォーム関連のセレクター
指定方法 | 指定例 |
---|---|
テキスト入力フィールド | input[type="text"] |
テキストエリア | textarea |
プルダウン(セレクトボックス) | select |
プルダウンのn番目の選択肢 | option:nth-child(n) |
チェックボックス | input[type="checkbox"] |
ラジオボタン | input[type="radio"] |
チェックボックス・ラジオボタンにチェックが入っている状態 | input[type="checkbox"]:checked, input[type="radio"]:checked |
送信ボタン | input[type="submit"] |
非活性状態 | input[type="text"]:disabled |
2. CSSセレクターを使いこなそう
CSSセレクターは、同じ要素を選ぶ場合であっても複数の指定方法があります。自動テストにおいては、複数の指定方法がある中でも
- 自分の意図を反映している
- 対象を一意に識別出来る
- 簡潔で壊れにくい(ページ構造の変化に強い)
ものを指定することが肝要です。
ここからは、下記の様なHTML構造のページで <li>Hello! C2</li> を指定するCSSセレクターを例に記述方法をご紹介します。
<html>
<body>
...
<div class="aaaaa ccccc">
...
<div id="#bbbbb">
...
<section class="ccccc">
...
<ul>
<li>Hello! A1</li>
<li>Hello! A2</li>
<li>Hello! A3</li>
</ul>
<ul>
<li>Hello! B1</li>
<li>Hello! B2</li>
<li>Hello! B3</li>
</ul>
<ul>
<li>Hello! C1</li>
<li>Hello! C2</li>
<li>Hello! C3</li>
</ul>
...
</section>
...
</div>
...
</div>
...
</body>
</html>
このHTMLの階層構成を図にするとこの様になります。
2.1. HTML階層構造に沿って直上の親要素を順に全て指定する
対象要素のHTML階層構造に沿って、指定したい要素の直上の親要素をタグまで順に指定すると下記の様になります。
body > div.aaaaa.ccccc > div#bbbbb > section.ccccc > ul:last-child > li:nth-child(2)
この指定方法は、先祖要素やclass・idを厳密に指定し過ぎているため汎用性が低く、例えばサイト運用の経過で、
- <div class="aaaaa ccccc"> が デザイン変更でスタイルが変わり <div class="aaaaa bbbbb"> に変わった。
- <li>Hello! C2</li> の前に <li>Hello! C0</li> が追加され、リストの2番目から3番目に変わった。
などといった、ページ更新によるHTMLの構成の変更や、デザイン変更によるclassやidの変更が生じると、それまで指定出来ていたCSSセレクターでは対象要素が指定出来なくなる、という問題が発生する可能性が高くなります。
2.2. タグだけで指定する
「HTML階層構造に沿って直上の親要素を順に全て指定する」CSSセレクターを、<div>タグ・<section>タグのclass・idを省いて要素のみで指定すると下記の様になります。
body > div > div > section > ul:last-child > li:nth-child(2)
この場合、「div > div > section」は「このHTML階層構造に合致する<div>タグ・<section>タグ」という条件になります。
class・idに変更が生じやすいサイトの場合は、<div>タグ・<section>タグのclass・idを省いて要素のみで指定すると良いでしょう。
2.3. class・idだけで指定する
class・idを持つ要素はclass・idのみを記述することも出来ます。
「HTML階層構造に沿って直上の親要素を順に全て指定する」CSSセレクターで、class・idを持つ<div>タグと<section>タグをclass・idだけで指定すると、下記の様になります。
body > .aaaaa.ccccc > #bbbbb >.ccccc > ul:last-child > li:nth-child(2)
この場合、「.aaaaa.ccccc > #bbbbb >.ccccc」は「このHTML階層構造に合致する、該当のclass・idが設定された全ての要素」という条件になります。
2.4. 直下の子要素を指定する
div.aaaaa > section > ul:last-child > li:nth-child(2)
上記のCSSセレクターは、<div class="aaaaa">の直下に子要素となる<section>タグが存在しないため、このCSSセレクターの指定対象となる要素は存在しません。
2.5. 子孫要素を指定する
「直下の子要素指定」では<div class="aaaaa">の直下に<section>タグが存在しないので、指定対象の要素が存在しませんでしたが、このCSSセレクターの**「div.aaaaa > section」の直下子要素指定を「div.aaaaa section」**と子孫要素指定に変えると、<div class="aaaaa">の子孫要素である<section>タグは存在します。
div.aaaaa section > ul:last-child > li:nth-child(2)
上記のCSSセレクターは、クラス名「aaaaa」が設定された<div>タグの子孫要素<ul>の中で最後の<ul>直下の<li>の2番目 が対象要素となり、指定対象は <li>Hello! C2</li> です。
2.6. CSSセレクターをより短くする
先に述べた通り、「HTML階層構造に沿って直上の親要素を順に全て指定する」CSSセレクターは、ページ更新によるHTMLの構成の変更や、デザイン変更によるclassやidの変更が生じると、それまで指定出来ていたCSSセレクターでは対象要素が指定出来なくなる、という問題が発生するリスクが高くなります。
CSSセレクターを短くシンプルにすることで、このリスクを減らすことが出来ます。
「HTML階層構造に沿って直上の親要素を順に全て指定する」でも取り上げた下記のCSSセレクターを指定条件で分解すると、
body > div.aaaaa.ccccc > div#bbbbb > section.ccccc > ul:last-child > li:nth-child(2)
- body > div.aaaaa.ccccc > div#bbbbb > section.ccccc > ul > li
- このHTML階層構造に合致する要素が対象
- ul:last-child
- 1の条件に合致する<ul>タグの中で一番最後の<ul>タグが対象
- li:nth-child(2)
- 1の条件に合致する<li>タグの中で2番目の<li>タグが対象
となります。
1 のHTML階層構造は、対象要素が特定可能な範囲であれば短くする事が出来ます。
例えば、<section>タグがページ内でこの部分にしか存在しない場合、<section>はこのページでは一意の要素となるので、下記の様に<section>タグまでの親要素を指定するCSSセレクターでも対象を特定出来ます。
section > ul:last-child > li:nth-child(2)
上記のセレクタの場合、<section>直下の子要素<ul>の中で最後の<ul>直下の<li>の2番目 が対象要素となり、指定対象は <li>Hello! C2</li> です。
なお、W3C の勧告では「id属性の値は一つの文書内で一意でなければならない」とされているため、idが設定されている要素はページ内で一意な要素である確率が高いです。
2.6.1. CSSセレクターを短縮しすぎると…
CSSセレクターを短縮しすぎると、指定対象が一意なものでなくなったり、対象要素が指定出来なくなることがあるので、注意が必要です。
2.6.2. 指定対象が複数存在する (1)
section > ul > li:nth-child(2)
上記のセレクタの場合、<section>直下の子要素<ul>直下の<li>の2番目 が対象要素になるため、指定対象は <li>Hello! A2</li>・<li>Hello! B2</li>・<li>Hello! C2</li> です。
2.6.3. 指定対象が複数存在する (2)
section li
上記のセレクタの場合、<section>の子孫要素<li>が対象要素 になるため、指定対象は <li>Hello! A1</li>・<li>Hello! A2</li>・<li>Hello! A3</li>・<li>Hello! B1</li>・<li>Hello! B2</li>・<li>Hello! B3</li>・<li>Hello! C1</li>・<li>Hello! C2</li>・<li>Hello! C3</li> です。
2.6.4. 指定対象が存在しない
section > li:nth-child(2)
上記のセレクタの場合、<section>直下の子要素<li>の2番目が対象要素になるため、対象となる要素はありません。
2.6.5. 指定したい要素ではない要素が指定対象になる
section li:nth-child(2)
上記のセレクタの場合、<section>の子孫要素<li>の2番目 が対象要素になるため、指定対象は <li>Hello! A2</li> です。