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?

JestにおけるTestingLibraryElementError: Unable to find an accessible element with the role "listitem"

Posted at

1 はじめに

supabaseと連携したReactアプリにおいて、
Jestとreact-testing-libraryを用いた自動テストで躓いたことが複数個あったため、
それぞれ別記事としてまとめていく
今回は第2弾、TestingLibraryElementErrorについて

2 事象

今回、supabaseと連携したReactアプリとして
学習記録アプリを開発した。このアプリは画面を立ち上げた際、
supabaseに登録しているレコードを全件取得したのち、
一覧を表示するといったものである。

image.png

学習内容と学習時間を入力後、登録ボタンを押したらレコードが1つ増えることを
確認するため下記のようなプログラムを用意したが次のようなエラーが起きた

TestingLibraryElementError: Unable to find an accessible element with the role "listitem" There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the hidden option to true. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
InputTest.spec.jsx
jest.mock("../supabaseClients.jsx", () => {
    let data = [ {id: 1, title: "dummy", time: 1}, {id: 2, title: "dummy2", time: 2} ];
    
    return {
        supabase: {
            from: jest.fn(() => ({
                select: jest.fn(() => {
                    return Promise.resolve({
                        data: data,
                        error: null,
                    })
                }),
                insert: jest.fn((newItem) => {
                    newItem.id = 2;
                    data = [...data, newItem];
                    return Promise.resolve({
                        data: newItem,
                        error: null,
                    });
                }),
                delete: jest.fn(() => {
                    return {                    
                        eq: jest.fn((key, value) => {
                        data = data.filter(item => item[key] !== value);
                        return Promise.resolve({
                            data: data,
                            error: null,
                        });
                    }),}
                }),
            })),
        },
    };
});

import { LearningRecord } from "../LearningRecord"; 
import React from "react"; 
import "@testing-library/jest-dom" 
import { render, screen } from "@testing-library/react"; 
import userEvent from "@testing-library/user-event"; 

describe("Input Test", () => { 
    it("登録ができること", async () => { 
        const { getByLabelText } = render(<LearningRecord />); 
        const before = (await screen.getAllByRole("listitem")).length; 
        
        const user = userEvent.setup(); 
        const input_title = await getByLabelText("学習内容"); 
        const input_time = await getByLabelText("学習時間"); 
        const button = await screen.getByRole("button", {name: "登録"}); 
        
        await user.type(input_title, "自動テスト1"); 
        await user.type(input_time, "10"); 
        await user.click(button); 
        
        const after = (await screen.findAllByRole("listitem")).length; 
        
        expect(after).toBe(before + 1); 
    }); 
});

3 原因と解決方法

調査したところ、getAllByRoleが同期処理でawaitが意味をなさず、fetchの結果を待たずにli要素を探しに行っていたことが原因であった。
fetchの結果を待つ必要があるので、今回は非同期処理のメソッドを探す必要がある。

調査したところ、findAllByRoleが非同期処理でfetchの結果を待った後にli要素を探しに行けることが判明。
よって下記のように修正したところ、無事に動作し、テストも成功した。

InputTest.spec.jsx
jest.mock("../supabaseClients.jsx", () => {
    let data = [ {id: 1, title: "dummy", time: 1}, {id: 2, title: "dummy2", time: 2} ];
    
    return {
        supabase: {
            from: jest.fn(() => ({
                select: jest.fn(() => {
                    return Promise.resolve({
                        data: data,
                        error: null,
                    })
                }),
                insert: jest.fn((newItem) => {
                    newItem.id = 2;
                    data = [...data, newItem];
                    return Promise.resolve({
                        data: newItem,
                        error: null,
                    });
                }),
                delete: jest.fn(() => {
                    return {                    
                        eq: jest.fn((key, value) => {
                        data = data.filter(item => item[key] !== value);
                        return Promise.resolve({
                            data: data,
                            error: null,
                        });
                    }),}
                }),
            })),
        },
    };
});


import { LearningRecord } from "../LearningRecord";
import React from "react";
import "@testing-library/jest-dom"
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

describe("Input Test", () => {
    it("登録ができること", async () => {
        render(<LearningRecord />);
        
        const before = (await screen.findAllByRole("listitem")).length;

        const user = userEvent.setup();
        const input_title = await screen.findByLabelText("学習内容");
        const input_time = await screen.findByLabelText("学習時間");
        const button = screen.getByRole("button", {name: "登録"});

        await user.type(input_title, "入力テスト");
        await user.type(input_time, "10");
        await user.click(button);

        const after = (await screen.findAllByRole("listitem")).length;

        expect(after).toBe(before + 1);


    });
});

ちなみに、get系は同期処理、find系は非同期処理と覚えておくとよい。

4 まとめ

役割だけでなく、同期処理なのか非同期処理なのかという点にも着目して
調べて使い分ける必要がある。

JISOUのメンバー募集中!

プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてくださ!
▼▼▼

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?