import { act, fireEvent, render, screen } from "@testing-library/react" import { Effect, Layer } from "effect" import * as React from "react" import { describe, expect, it, vi } from "vitest" import * as Async from "./Async.js" import * as Component from "./Component.js" import * as Memoized from "./Memoized.js" import * as ReactRuntime from "./ReactRuntime.js" describe("Async", () => { it("does not rerun for an unrelated parent state update", async () => { const load = vi.fn((_id: number) => Effect.never) const renderPost = vi.fn() const runtime = ReactRuntime.make(Layer.empty) const context = await runtime.runtime.context() const Post = Component.make("Post")(function*(props: { readonly id: number }) { renderPost() const value = yield* Component.useOnChange(() => load(props.id), [props.id]) return
{value}
}).pipe( Async.async, Memoized.memoized, ) const Parent = Component.make("Parent")(function*() { const [text, setText] = React.useState("") const AsyncPost = yield* Post.use return <> setText(event.currentTarget.value)} /> loading} /> }).pipe(Component.withContext(runtime.context)) let view!: ReturnType await act(async () => { view = render( , ) }) expect(screen.getByText("loading")).toBeTruthy() expect(load).toHaveBeenCalledTimes(2) const callsAfterLoad = load.mock.calls.length const rendersAfterLoad = renderPost.mock.calls.length await act(async () => { fireEvent.change(screen.getByLabelText("text"), { target: { value: "a" } }) }) expect(load).toHaveBeenCalledTimes(callsAfterLoad) expect(renderPost).toHaveBeenCalledTimes(rendersAfterLoad) view.unmount() await runtime.runtime.dispose() }) })