feat: add quiet reading with rare confirmations

Part of the quiet-user-feedback change; docs and specs land in their own repositories.
This commit is contained in:
2026-10-06 07:01:58 +03:00
parent c096fc70ef
commit 5b30bb802a
77 changed files with 1352 additions and 1259 deletions
@@ -1,7 +1,7 @@
import type { FC, PropsWithChildren } from "react";
import { MantineProvider } from "@mantine/core";
import { act, renderHook, waitFor } from "@testing-library/react";
import { renderHook, waitFor } from "@testing-library/react";
import { http, HttpResponse } from "msw";
import { MemoryRouter, Route, Routes } from "react-router";
import { describe, expect, it, vi } from "vitest";
@@ -147,10 +147,10 @@ describe("useAccountPageViewModel", () => {
HttpResponse.json(resource(portfolio)),
),
http.get("*/api/v1/brokerage-accounts/:accountId/operations", () =>
HttpResponse.json({ code: "TBANK_UNAVAILABLE" }, { status: 503 }),
HttpResponse.json({ code: "DEMO_FAILURE" }, { status: 400 }),
),
http.get("*/api/v1/brokerage-accounts/:accountId/events", () =>
HttpResponse.json({ code: "MOEX_UNAVAILABLE" }, { status: 503 }),
HttpResponse.json({ code: "DEMO_FAILURE" }, { status: 400 }),
),
);
@@ -208,7 +208,7 @@ it("keeps overview sections independent when their source data is incomplete", a
);
});
it("refreshes every overview section through one account descriptor and observational reads", async () => {
it("keeps overview sections loaded without exposing technical retry", async () => {
configureTestAuth();
const sections: Record<string, unknown>
@@ -219,48 +219,17 @@ it("refreshes every overview section through one account descriptor and observat
portfolio,
};
const observed: string[] = [];
const scopes: unknown[] = [];
let version = "1";
server.use(
...Object.entries(sections).map(([path, data]) =>
http.get(
`*/api/v1/brokerage-accounts/:accountId/${path}`,
({ request }) => {
if (new URL(request.url).searchParams.get("sync") === "observe")
observed.push(path);
() => {
return HttpResponse.json(
resource(data, { dataRevision: version, resourceKey: path }),
resource(data, { dataRevision: "1", resourceKey: path }),
);
},
),
),
http.post("*/api/v1/tbank-sync", async ({ request }) => {
scopes.push(await request.json());
version = "2";
return HttpResponse.json(
{
id: "overview",
now: "2026-09-25T00:00:00Z",
scope: { accountId: "account-1", screen: "account" },
},
{ status: 202 },
);
}),
http.get("*/api/v1/tbank-sync/:id", () =>
HttpResponse.json(
{
errorCode: null,
id: "overview",
now: "2026-09-25T00:00:00Z",
scope: null,
state: "succeeded",
},
),
),
);
const { result } = renderHook(() => useAccountPageViewModel(), {
@@ -275,11 +244,5 @@ it("refreshes every overview section through one account descriptor and observat
state: "loaded",
}),
);
await act(async () => {
if (result.current.state === "loaded") await result.current.retry();
});
await waitFor(() =>
expect(new Set(observed)).toEqual(new Set(Object.keys(sections))),
);
expect(scopes).toEqual([{ accountId: "account-1", screen: "account" }]);
expect(result.current).not.toHaveProperty("retry");
});