North Detail / ノースディテール

BLOG ブログ

ブログ
CATEGORY
TECH

Cypressでの属性に依存しないテーブルの検証

※本記事は、NorthDetail Advent Calendar 2020の一環として投稿しています

こんにちは、d_ice_kです。
今月から品質テストに関わることとなり、Cypressによるテスト環境を整えております。
今回は、一覧画面などテーブルやリストに関する項目の検証について考えます。

はじめに

Cypressでは、どの要素を検証するかを選択するために、ロケータとしてCSSセレクタやXPathを利用することになりますが、公式ではロケータの一意性を保持するために推奨される書き方があります。以下公式より抜粋、

Submitボタン

<button id="main" class="btn btn-large" name="submission"
    role="button" data-cy="submit">Submit</button>

Submitボタンを押すテストコード

//データ属性でロケーティング
cy.get('[data-cy=submit]').click()

//テキストでロケーティング
cy.contains('Submit').click()

//name属性でロケーティング
cy.get('[name=submission]').click()

//id属性でロケーティング
cy.get('#main').click()

//class属性でロケーティング
cy.get('.btn.btn-large').click()

//要素名(タグ)でロケーティング
cy.get('button').click()

データ属性 > テキスト > name属性 > id属性 > class属性 > 要素名(タグ)

変更される可能性や、変更された時の修正のし易さに伴い、この順でのロケーティングが推奨されています。詳しくはこちら、Cypress.io Best Practices

テーブル構造の検証

上記の属性を保持していれば、属性でロケーティングするのが最短ですが、必ずしも推奨するロケーティング通りにいくとは限りません。順を追って考えてみます。

2行目にテスト2があるかを検証をする

まず初めに、属性でロケーティングができる場合

検証するテーブル

<table>
    <tr data-test="test1">
        <td>1</td>
        <td>テスト1</td>
    </tr>
    <tr data-test="test2">                   
        <td>2</td>
        <td>テスト2</td>
    </tr>
    <tr data-test="test3">             
        <td>3</td>
        <td>テスト3</td>
    </tr>
</table>

テストコード

cy.get('[data-test=test2]').contains('テスト2')

データ属性のdata-test=test2でロケーティングし、テーブル2行目にテスト2があることを検証できます。

では、属性が乏しい、または属性が不定なテーブルを検証する場合はどうするのか?

2行目にテスト2があるかを構造から検証する

検証するテーブル

<table>
    <tr>                  <!-- eq(0) -->                    
        <td>1</td>
        <td>テスト1</td>
    </tr>
    <tr>                  <!-- eq(1) -->                   
        <td>2</td>
        <td>テスト2</td> 
    </tr>
    <tr>                  <!-- eq(2) -->                    
        <td>3</td>
        <td>テスト3</td>
    </tr>
</table>

テストコード

CSSセレクタでロケーティングすると、

cy.get('table>tr:nth-child(2)').contains('テスト2')

これを、もっとテーブルの階層構造を直接的に指定する書き方にすると、

cy.get('tr').eq(1).contains('テスト2')

テーブルの2行目('tr').eq(1)を指定して、テスト2があることを検証できます。

上の2つは、画面内にテーブルが1つの場合は成り立ちますが、同じ画面内に複数のテーブルが存在する場合には、最初のテーブルの2行目だけをロケーティングしてしまいます。

複数テーブル構造の検証

では、複数のテーブルがある場合の属性に依存しない検証はどうすればいいのか?

2つ目のテーブルの2行目に結果2-2があるかを構造から検証する

検証する複数テーブル

<table>
    <tr>                   
        <td>1</td>
        <td>テスト1-1</td>
        <td>結果1-1</td>
        <td><button>編集</button></td> 
    </tr>
    <tr>                    
        <td>2</td>
        <td>テスト1-2</td> 
        <td>結果1-2</td>
        <td><button>編集</button></td>
    </tr>
    <tr>
        <td>3</td>
        <td>テスト1-3</td>
        <td>結果1-3</td>
        <td><button>編集</button></td> 
    </tr>
</table>
<table>
    <tr>                   
        <td>1</td>
        <td>テスト2-1</td>
        <td>結果2-1</td>
        <td><button>編集</button></td> 
    </tr>
    <tr>                    
        <td>2</td>
        <td>テスト2-2</td> 
        <td>結果2-2</td>
        <td><button>編集</button></td>
    </tr>
    <tr>
        <td>3</td>
        <td>テスト2-3</td>
        <td>結果2-3</td>
        <td><button>編集</button></td> 
    </tr>
</table>

テストコード

cy.contains('テスト2-2').parents('tr').within(() => {
    cy.get('td').eq(2).contains('結果2-2')
    cy.get('td').eq(3).contains('編集').click()
})
  • contains('テスト2-2')でテーブル内の特定の値(テスト2-2)をキャッチして、テスト2-2を持つ行trを指定する。
  • parents('tr').within()で親要素tr内の子要素tdに対する指定をする。
  • within()内で、3列目('td').eq(2)に結果2-2があることを検証する。
  • 4列目('td').eq(3)の編集ボタンを押すこともできる。

まとめ

構造そのものが変わらない限り、登録一覧画面のようなid属性などが不定なテーブルや、同じ構造が並ぶ画面の検証をする際は、属性に依存しない書き方が有効です。

d_ice_k
WRITER:d_ice_k
元建築系3Dモデラー
主な記事 一覧へ

一覧へ

IS 501383 / ISO 27001