refactor: enforce frontend view model boundaries
This commit is contained in:
@@ -21,6 +21,7 @@ const snapshot: Portfolio = {
|
||||
structure: { currencies: [], unvaluedCategories: [] },
|
||||
totalsByCurrency: [{ currency: "RUB", value: "123.000000001" }],
|
||||
};
|
||||
|
||||
function auth() {
|
||||
configureAuthClient({
|
||||
accessToken: () => "synthetic",
|
||||
@@ -41,6 +42,7 @@ describe("persistent resource query lifecycle", () => {
|
||||
const mode = new URL(request.url).searchParams.get("sync");
|
||||
modes.push(mode);
|
||||
if (mode) observations += 1;
|
||||
|
||||
return HttpResponse.json(
|
||||
resource(snapshot, {
|
||||
stateVersion: observations > 1 ? "new" : "old",
|
||||
@@ -76,22 +78,26 @@ describe("persistent resource query lifecycle", () => {
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const { result } = renderHook(() => usePortfolio("a"), {
|
||||
wrapper: createQueryWrapper().wrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => expect(result.current.meta?.sync.state).toBe("failed"));
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isSuccess).toBe(false);
|
||||
expect(result.current.status).toBe("pending");
|
||||
expect(result.current.isPending).toBe(true);
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.transport).toEqual((/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
expect(result.current.transport).toEqual(
|
||||
{
|
||||
error: null,
|
||||
fetchStatus: "idle",
|
||||
status: "success",
|
||||
}
|
||||
/* eslint-enable unicorn/no-null */));
|
||||
},
|
||||
/* eslint-enable unicorn/no-null */
|
||||
);
|
||||
expect(result.current.meta?.availability).toBe("missing");
|
||||
});
|
||||
it("keeps the refetch envelope while exposing the refreshed resource payload", async () => {
|
||||
@@ -103,9 +109,11 @@ describe("persistent resource query lifecycle", () => {
|
||||
HttpResponse.json(isReady ? refreshed : resource(null)),
|
||||
),
|
||||
);
|
||||
|
||||
const { result } = renderHook(() => usePortfolio("a"), {
|
||||
wrapper: createQueryWrapper().wrapper,
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.transport.status).toBe("success"),
|
||||
);
|
||||
@@ -130,20 +138,25 @@ describe("persistent resource query lifecycle", () => {
|
||||
it("rejects a late ordinary response when an observe response for that resource arrived first", async () => {
|
||||
auth();
|
||||
|
||||
const { promise: blocked, resolve: release } = Promise.withResolvers<void>();
|
||||
const { promise: blocked, resolve: release }
|
||||
= Promise.withResolvers<void>();
|
||||
|
||||
server.use(
|
||||
http.get(
|
||||
"*/api/v1/brokerage-accounts/:accountId/portfolio",
|
||||
async ({ request }) => {
|
||||
if (!new URL(request.url).searchParams.has("sync")) await blocked;
|
||||
|
||||
return HttpResponse.json(resource(snapshot));
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const old = apiClient.GET(
|
||||
"/api/v1/brokerage-accounts/{accountId}/portfolio",
|
||||
{ params: { path: { accountId: "a" } } },
|
||||
);
|
||||
|
||||
// eslint-disable-next-line vitest/valid-expect -- Attach rejection handling before releasing the request; the assertion is awaited below.
|
||||
const rejected = expect(old).rejects.toMatchObject({ name: "AbortError" });
|
||||
await apiClient.GET("/api/v1/brokerage-accounts/{accountId}/portfolio", {
|
||||
@@ -156,21 +169,28 @@ describe("persistent resource query lifecycle", () => {
|
||||
auth();
|
||||
let isDenied = false;
|
||||
|
||||
const { promise: blocked, resolve: release } = Promise.withResolvers<void>();
|
||||
const { promise: blocked, resolve: release }
|
||||
= Promise.withResolvers<void>();
|
||||
|
||||
server.use(
|
||||
http.get(
|
||||
"*/api/v1/brokerage-accounts/:accountId/portfolio",
|
||||
async ({ params }) => {
|
||||
if (params.accountId === "b") await blocked;
|
||||
return isDenied && params.accountId === "a" ? HttpResponse.json({ code: "NOT_FOUND" }, { status: 404 }) : HttpResponse.json(resource(snapshot));
|
||||
|
||||
return isDenied && params.accountId === "a"
|
||||
? HttpResponse.json({ code: "NOT_FOUND" }, { status: 404 })
|
||||
: HttpResponse.json(resource(snapshot));
|
||||
},
|
||||
),
|
||||
);
|
||||
const { wrapper } = createQueryWrapper();
|
||||
|
||||
const { result } = renderHook(
|
||||
() => ({ a: usePortfolio("a"), b: usePortfolio("b") }),
|
||||
{ wrapper },
|
||||
);
|
||||
|
||||
await waitFor(() => expect(result.current.a.data).toEqual(snapshot));
|
||||
isDenied = true;
|
||||
await act(() => result.current.a.refetch());
|
||||
|
||||
Reference in New Issue
Block a user