Open11
React Server Components のテストの仕方を調べながら、手を動かす
最近、React Server Components (これ以降RSC)のテストをしたいと思い、調べます。
以下のようなコンポーネントを用意
Sleep.tsx
import React, { Suspense } from "react";
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const Sleep = async () => {
await sleep(2000);
return (
<>
<div>おはよう!</div>
</>
);
};
export default Sleep;
例えばコンポーネントをテストする場合、
testing-libraryのrenderを使うと思います。
以下でテストを行うと
/**
* @jest-environment jsdom
*/
import { render, screen } from "@testing-library/react";
import Sleep from "app/components/Sleep";
describe("sleepのテスト", () => {
it("期待する文字が表示されるか", async () => {
render(<Sleep />);
expect(screen.getByText("おはよう!")).toBeInTheDocument();
});
});
Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
上記エラーが出てきてしまう。
解決策として
や
rfcを関数として実行、そして実行結果をrenderしてテストを行うテクニックがあるよう。
試してみる。
以下でpassできた。
/**
* @jest-environment jsdom
*/
import { render, screen } from "@testing-library/react";
import Sleep from "app/components/Sleep";
describe("sleepのテスト", () => {
it("期待する文字が表示されるか", async () => {
const result = await Sleep();
render(result);
expect(screen.getByText("おはよう!")).toBeInTheDocument();
});
});
しかしこのテクニック注意点があるようで、
async componentsの中でasync componentsを使用するとエラーが起こってしまう。
Sleep.tsx
import React, { Suspense } from "react";
import DeepSleep from "./DeepSleep";
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const Sleep = async () => {
await sleep(2000);
return (
<>
<div>おはよう!</div>
<Suspense fallback={<div>DeepSleepしてます</div>}>
<DeepSleep />
</Suspense>
</>
);
};
export default Sleep;
DeepSleep.tsx
import React from "react";
const deepSleep = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));
const DeepSleep = async () => {
await deepSleep(4000);
return <div>超おはよう!</div>;
};
export default DeepSleep;
nextjsのドキュメントに以下の文が。
Since async Server Components are new to the React ecosystem, some tools do not fully support them. In the meantime, we recommend using End-to-End Testing over Unit Testing for async components.
E2Eテストを薦めている
Nextjsで紹介されているPlaywright を使ってみます。
またquickstartも用意されているので、すぐ試せそう
e2e/sample.spec.ts
import { test, expect } from "@playwright/test";
test("期待する文字が表示されるか", async ({ page }) => {
await page.goto("/");
await expect(page.getByText(/^おはよう!$/)).toBeVisible();
await expect(page.getByText(/^超おはよう!$/)).toBeVisible();
});
実行
npx playwright test
実行結果
✓ 1 [Mobile Chrome] › sample.spec.ts:3:5 › 期待する文字が表示されるか (7.7s)
✓ 2 [Desktop Chrome] › sample.spec.ts:3:5 › 期待する文字が表示されるか (7.7s)
✓ 3 [Mobile Safari] › sample.spec.ts:3:5 › 期待する文字が表示されるか (7.8s)
3 passed (19.8s)
3環境でテストを行なってくれました。
--headedオプションを追加して実行すると、実際のブラウザが立ち上がってテストが行われます。
テスト時間がかかりそうな印象を受けた。
コンポーネント単位というよりは、ページ単位のテストになっている。
Container/Presentational Components パターンを利用するテスト手法もあるそう。