Repository navigation
Rendering emails in tests fails if sync in v5 #2809
|
Hi 👋, After updating to React Email v5 the tests with Vitest + Happy DOM fail. If I make the first test in each test file async with Is this an expected behavior and what's the correct way to handle this? Should we make all tests async or is there a way to "prepare" react-email (I assume the first test loads some additional code or something like that?) upfront so that the tests can by synchronous? Repro: https://github.com/rothsandro/repro.react-email-test/tree/main/emails |
Replies: 1 comment 1 reply
|
This is expected in v5, and it's the In v5 The reason the rest of the file then passes synchronously: that hook caches the resolved result in a module-level map keyed by config. Once the first render has awaited it, every later render in the same worker gets the compiled result back instantly, no suspend. So the whole thing hinges on "has anything awaited the Tailwind compile yet in this worker," which is exactly the cross-test dependency you're seeing. So don't make the tests sync. Await the render in each one: test("test 1", async () => {
render(<Email />);
expect(await screen.findByText("Join the team")).toBeTruthy();
});
beforeAll(async () => {
render(<Email />);
await screen.findByText("Join the team");
cleanup();
});Either works. I'd go with |
This is expected in v5, and it's the
<Tailwind>component doing it, not your test setup.In v5
<Tailwind>compiles the CSS through an async step and suspends on the first render (it throws a promise via an internaluseSuspensedPromisehook). Testing Library'srender()returns synchronously, so on that very first render the tree is still suspended and nothing has committed yet, which is whygetByTextfinds nothing.findByTextworks because it polls until React re-renders after the promise resolves.The reason the rest of the file then passes synchronously: that hook caches the resolved result in a module-level map keyed by config. Once the first render has awaited it, every later render in…