1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【testing-library】TestingLibraryElementError: Unable to find an accessible element with the role

Posted at

はじめに

screen.getAllByRoleを使用してテーブル行を取得する際にエラーとなりました。

問題

screen.getAllByRole("row")を使用して、テーブルの行数を取得しようとしたところ表題のエラーになりました。

エラーとなった際のコード

delete.spec.js
import App from "../App";
import React from "react";
import '@testing-library/jest-dom'
import { render, screen, within, waitFor} from "@testing-library/react";
import userEvent from "@testing-library/user-event";

describe("RegistDelete Test", () => {
	it("削除ボタンを押すと記録数が1つ減っていること", async () => {
		
		render(<App />);

		const before = screen.getAllByRole("row").length;

		// テーブル最初の行の削除ボタン押下
		const rows = screen.getAllByRole("row");
		const firstRow = rows[0];
		const deleteButton = within(firstRow).getByTestId("delete");
		await userEvent.click(deleteButton);

		// テーブルの行が1行削除されていること
		expect(screen.getAllByRole("row").length).toBe(before - 1);
	});
});

解決方法

waitForを使う

※公式ドキュメント(翻訳)より引用

任意の期間待つ必要がある場合は、waitForを使用して、期待値が通過するのを待つことができます

waitForは、タイムアウトに達するまで何度でもコールバックを実行することができる。呼び出しの回数は、timeoutオプションとintervalオプションによって制限されることに注意してください。

await waitFor内にscreen.getAllByRole("row");を定義して、テーブル行を取得できるまで待つように修正

delete.spec.js
import App from "../App";
import React from "react";
import '@testing-library/jest-dom'
import { render, screen, within, waitFor} from "@testing-library/react";
import userEvent from "@testing-library/user-event";

describe("RegistDelete Test", () => {
	it("削除ボタンを押すと記録数が1つ減っていること", async () => {
		
		render(<App />);

+		// テーブルの行を取得できるまで待つ
+		await waitFor(() => {
+			screen.getAllByRole("row");
+		});

		const before = screen.getAllByRole("row").length;

		// テーブル最初の行の削除ボタン押下
		const rows = screen.getAllByRole("row");
		const firstRow = rows[0];
		const deleteButton = within(firstRow).getByTestId("delete");
		await userEvent.click(deleteButton);

		// テーブルの行が1行削除されていること
		expect(screen.getAllByRole("row").length).toBe(before - 1);
	});
});

実行したところ、テストが期待値通りの結果となりませんでした。
削除処理前後でconsole.logで出力すると、削除処理後も数が変わっていませんでした。

image.png

削除処理が完了する前に、
expect(screen.getAllByRole("row").length).toBe(before - 1);
を実行されていたことが原因でした。

削除されるまで、処理を待つようにwateForを追加することで解決しました。

delete.spec.js
import App from "../App";
import React from "react";
import '@testing-library/jest-dom'
import { render, screen, within, waitFor} from "@testing-library/react";
import userEvent from "@testing-library/user-event";

describe("RegistDelete Test", () => {
	it("削除ボタンを押すと記録数が1つ減っていること", async () => {
		
		render(<App />);

		// テーブルの行を取得できるまで待つ
		await waitFor(() => {
			screen.getAllByRole("row");
		});

		const before = screen.getAllByRole("row").length;

		// テーブル最初の行の削除ボタン押下
		const rows = screen.getAllByRole("row");
		const firstRow = rows[0];
		const deleteButton = within(firstRow).getByTestId("delete");
		await userEvent.click(deleteButton);

		// テーブルの行が1行削除されていること
+		await waitFor(() => {
			expect(screen.getAllByRole("row").length).toBe(before - 1);
+		});
	});
});

findByを使う

waitForでも実現可能ですが、非同期処理を待って要素を取得する場合、findByを使うほうが簡潔に実現できました。

※公式ドキュメント(翻訳)より引用

findByメソッドは、getByクエリとwaitForを組み合わせたものです。waitForオプションを最後の引数として受け取ります(例えば、await screen.findByText('text', queryOptions, waitForOptions))。

getByクエリとwaitForを組み合わせたものです。
最初にwaitForとgetByクエリで解決したことをfindByでできる…

delete.spec.js
import App from "../App";
import React from "react";
import '@testing-library/jest-dom'
import { render, screen, within, waitFor} from "@testing-library/react";
import userEvent from "@testing-library/user-event";

describe("RegistDelete Test", () => {
	it("削除ボタンを押すと記録数が1つ減っていること", async () => {
		
		render(<App />);

-		// テーブルの行を取得できるまで待つ
-		await waitFor(() => {
-			screen.getAllByRole("row");
-		});

-		const before = screen.getAllByRole("row").length;
+		const before = (await screen.findAllByRole("row")).length;

		// テーブル最初の行の削除ボタン押下
		const rows = screen.getAllByRole("row");
		const firstRow = rows[0];
		const deleteButton = within(firstRow).getByTestId("delete");
		await userEvent.click(deleteButton);

		// テーブルの行が1行削除されていること
		await waitFor(() => {
			expect(screen.getAllByRole("row").length).toBe(before - 1);
		});
	});
});

おわりに

最近エラーに遭遇すると、非同期処理の理解不足によるものなんじゃ…って思うことが増えてきました。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?