はじめに
改修中の学習記録アプリを、Vitestを使用してテストしたところ、エラーに遭遇しました。
問題
学習内容と、学習時間を入力後に登録ボタンを押下して一覧に記録されるかテストコードを書いてテストをすると、タイトルのエラーが発生した。
・問題のテストコード
test("学習内容と時間を入力して登録ボタンを押すと新たに記録が追加することが出来る", async () => {
render(<LearnLog />);
await waitForElementToBeRemoved(() => screen.getByText("ロード中..."));
const inputTitle = await screen.getByText("");
const inputTime = await screen.getByText("0");
const addButton = await screen.getByRole("button", {name: "登録"});
fireEvent.change(inputTitle, { target: { value: "テスト"}});
fireEvent.change(inputTime, { target: { value: "10"}});
fireEvent.click(addButton);
const list = screen.getByRole("list");
expect(within(list).getByText("テスト")).toBeInTheDocument();
expect(within(list).getByText("10")).toBeInTheDocument();
});
・エラー内容(長いので中略します)
FAIL src/tests/LearnLog.test.jsx > 学習記録アプリのテスト > 学習内容と時間を入力して登録ボタンを押すと新たに記録が追加することが出来る
TestingLibraryElementError: Found multiple elements with the text:
Here are the matching elements:
Ignored nodes: comments, script, style
<body>
<div>
<h1>
学習記録一覧
</h1>
<ul>
<div>
学習内容
<input
type="text"
value=""
/>
</div>
<div>
学習時間
<input
type="number"
value="0"
/>
時間
</div>
<div>
入力されている学習内容:
<label />
</div>
<div>
入力されている学習時間:
<label>
0
</label>
時間
</div>
<li>
<label>
英語
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
数学
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
React
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<button>
登録
</button>
<div />
<div>
合計時間:
110
/1000(h)
</div>
</ul>
</div>
</body>
Ignored nodes: comments, script, style
<div>
<h1>
学習記録一覧
</h1>
<ul>
<div>
学習内容
<input
type="text"
value=""
/>
</div>
<div>
学習時間
<input
type="number"
value="0"
/>
時間
</div>
<div>
入力されている学習内容:
<label />
</div>
<div>
入力されている学習時間:
<label>
0
</label>
時間
</div>
<li>
<label>
英語
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
数学
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
React
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
10
時間
</label>
<button>
削除
</button>
</li>
<li>
<label>
テスト
(中略)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
❯ Object.getElementError node_modules/@testing-library/dom/dist/config.js:37:19
❯ getElementError node_modules/@testing-library/dom/dist/query-helpers.js:20:35
❯ getMultipleElementsFoundError node_modules/@testing-library/dom/dist/query-helpers.js:23:10
❯ node_modules/@testing-library/dom/dist/query-helpers.js:55:13
❯ node_modules/@testing-library/dom/dist/query-helpers.js:95:19
❯ src/tests/LearnLog.test.jsx:35:37
33| await waitForElementToBeRemoved(() => screen.getByText("ロード中..."));
34|
35| const inputTitle = await screen.getByText("");
| ^
36| const inputTime = await screen.getByText("0");
37| const addButton = await screen.getByRole("button", {name: "登録"});
学習内容テキストボックス内の要素を取得したかった為、以下のgetByTextを使用しました。初期値は空文字の為、引数も空文字にしました。
しかし、input要素が発見されないようで、うまくいきませんでした。
const inputTitle = await screen.getByText("");
解決方法
getByText→getByDisplayValueに修正すると、テストがPassされました。こうすると、input要素を的確に拾ってきてくれるようです。
test("学習内容と時間を入力して登録ボタンを押すと新たに記録が追加することが出来る", async () => {
render(<LearnLog />);
await waitForElementToBeRemoved(() => screen.getByText("ロード中..."));
const inputTitle = screen.getByDisplayValue("");
const inputTime = screen.getByDisplayValue("0");
const addButton = screen.getByRole("button", {name: "登録"});
fireEvent.change(inputTitle, { target: { value: "テスト"}});
fireEvent.change(inputTime, { target: { value: "10"}});
fireEvent.click(addButton);
const list = screen.getByRole("list");
expect(await within(list).findByText("テスト")).toBeInTheDocument();
expect(await within(list).findByText("10")).toBeInTheDocument();
});
✓ src/tests/LearnLog.test.jsx (2 tests) 1100ms
✓ 学習記録アプリのテスト (2)
✓ タイトルが表示されている 832ms
✓ 学習内容と時間を入力して登録ボタンを押すと新たに記録が追加することが出来る 264ms
Test Files 1 passed (1)
Tests 2 passed (2)
Start at 16:42:10
Duration 1.45s
PASS Waiting for file changes...
press h to show help, press q to quit
おわりに
テストコードは中々難しく感じますが、徐々に慣れていきたいと思います。
参考