Cypress テストコードを劇的に改善! "within" の使い方をマスターしよう

2024-04-02

Cypress "Commands" における "within" の詳細解説

"within" の基本構文

cy.within(selector, () => {
  // このブロック内のコマンドは、`selector` で指定された要素内でのみ実行されます。
  cy.get('[data-test="button"]').click();
  cy.get('[data-test="input"]').type('Cypress');
});

上記の例では、selector で指定された要素内でのみ clicktype コマンドが実行されます。

"within" の利点

  • 要素間の切り替えを簡略化: テスト対象の要素階層が深い場合、within を使用することで、各要素へのアクセスを簡潔に記述できます。
  • コードの読みやすさ向上: テストコードを要素ごとに分割することで、コードの理解とメンテナンスが容易になります。
  • テストの安定性向上: 特定の要素内でのみコマンドを実行することで、誤操作によるテストの失敗を防ぎ、安定性を向上させます。

"within" の詳細な使い方

1 ネストされた要素へのアクセス

cy.within('.container', () => {
  cy.get('.header').should('be.visible');
  cy.within('.content', () => {
    cy.get('.paragraph').should('contain', 'Cypress');
  });
});

上記の例では、.container 要素内にある .header 要素と、.content 要素内にある .paragraph 要素をそれぞれ検証しています。

2 複数要素への適用

cy.get('.buttons').within(() => {
  cy.get('button').each(($button) => {
    // 各ボタンに対して処理を実行
    cy.wrap($button).click();
  });
});

上記の例では、.buttons 要素内のすべての button 要素に対して .click() コマンドを実行しています。

3 "within" のオプション

within には、以下のオプションが利用できます。

  • log: false - コマンドの実行ログを出力しない
  • timeout: 10000 - コマンドの実行タイムアウトを設定
cy.within('.modal', { log: false, timeout: 10000 }, () => {
  // ...
});

"within" の注意点

  • within は要素が存在することを前提としているため、事前に存在確認を行う必要があります。
  • 複雑なネスト構造の場合、コードの読みやすさが損なわれる可能性があります。
  • 要素の切り替えが多すぎると、テストの理解とメンテナンスが難しくなる可能性があります。

"within" の代替方法

  • cy.get().find() - 特定の要素内の子要素を取得
  • cy.root() - 最上位要素を取得
  • cy.focused() - フォーカスされている要素を取得

これらの方法を状況に応じて使い分けることで、テストコードをより効率的に記述できます。

まとめ

"within" は、Cypress の "Commands" における強力な機能です。適切なタイミングで使用することで、テストコードの読みやすさ、安定性、効率を向上させることができます。

その他



Cypress "within" のサンプルコード

テキスト入力

cy.within('.form', () => {
  cy.get('[data-test="username"]').type('user');
  cy.get('[data-test="password"]').type('password');
  cy.get('[data-test="submit"]').click();
});

要素の表示確認

cy.within('.modal', () => {
  cy.get('.title').should('be.visible');
  cy.get('.content').should('contain', 'Cypress');
});

複数要素への処理

cy.within('.list', () => {
  cy.get('li').each(($item) => {
    // 各リスト項目に対して処理を実行
    cy.wrap($item).click();
  });
});

ネストされた要素へのアクセス

cy.within('.container', () => {
  cy.get('.header').should('be.visible');
  cy.within('.content', () => {
    cy.get('.paragraph').should('contain', 'Cypress');
  });
});

オプションの利用

cy.within('.modal', { log: false, timeout: 10000 }, () => {
  // ...
});


Cypress "within" の代替方法

cy.get().find()

特定の要素内の子要素を取得して、その要素内でのみコマンドを実行できます。

cy.get('.container').find('.content').find('.button').click();

cy.root()

最上位要素を取得して、その要素内でのみコマンドを実行できます。

cy.get('.container').root().find('.button').click();

cy.focused()

フォーカスされている要素を取得して、その要素内でのみコマンドを実行できます。

cy.get('.input').focus().type('Cypress');

その他の方法

  • cy.contains()
  • cy.eq()
  • cy.filter()

これらの方法を状況に応じて使い分けることで、テストコードをより効率的に記述できます。

それぞれの方法の比較

方法メリットデメリット
within簡潔に記述できるネスト構造が複雑になると読みづらい
cy.get().find()柔軟性が高い記述が長くなる
cy.root()最上位要素を取得できるすべての要素に対して実行される
cy.focused()フォーカスされている要素を取得できるフォーカスされていない要素には使用できない

"within" は強力な機能ですが、状況に応じて他の方法を使い分けることで、より効率的で読みやすいテストコードを記述できます。