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
@@ -195,7 +195,6 @@ describe("AccountIncomePage", () => {
it("keeps income calendar dates in GET and source sync requests", async () => {
const requested: string[] = [];
const syncRequests: unknown[] = [];
server.use(
http.get(
"*/api/v1/brokerage-accounts/:accountId/income-analytics",
@@ -216,30 +215,11 @@ describe("AccountIncomePage", () => {
);
},
),
http.post("*/api/v1/tbank-sync", async ({ request }) => {
syncRequests.push(await request.json());
return HttpResponse.json(
{ code: "TBANK_UNAVAILABLE" },
{ status: 503 },
);
}),
);
renderPage("from=2024-02-29&to=2024-03-01");
const retry = await screen.findByRole("button", { name: "Повторить" });
await screen.findByText("Не удалось рассчитать пассивный доход");
expect(requested).toEqual(["?from=2024-02-29&to=2024-03-01"]);
expect(syncRequests).toEqual([]);
fireEvent.click(retry);
await waitFor(() =>
expect(syncRequests).toEqual([
{
accountId: "account-1",
from: "2024-02-29",
screen: "income",
to: "2024-03-01",
},
]),
);
expect(screen.queryByRole("button", { name: "Повторить" })).not.toBeInTheDocument();
});
it("requests a multi-year period from the URL without resetting it", async () => {
@@ -486,7 +466,7 @@ describe("AccountIncomePage", () => {
).toBeVisible();
});
it("shows a recoverable realized error", async () => {
it("shows a quiet realized error", async () => {
server.use(
http.get(
"*/api/v1/brokerage-accounts/account-1/income-analytics",
@@ -495,8 +475,11 @@ describe("AccountIncomePage", () => {
);
renderPage();
expect(
await screen.findByRole("button", { name: "Повторить" }),
await screen.findByText("Не удалось рассчитать пассивный доход", undefined, {
timeout: 4000,
}),
).toBeInTheDocument();
expect(screen.queryByRole("button", { name: "Повторить" })).not.toBeInTheDocument();
});
});
@@ -631,7 +614,7 @@ describe("income period and snapshot boundary", () => {
expect(requests).toEqual(["?from=2026-09-01&to=2026-09-01"]);
});
it("keeps valid data and draft during refetch, warns on failure and retries", async () => {
it("keeps valid data and draft during refetch failure", async () => {
respondWithRequestedPeriod([]);
const { queryClient } = renderPage();
await screen.findByLabelText("Период");
@@ -653,51 +636,13 @@ describe("income period and snapshot boundary", () => {
act(() => {
void queryClient.invalidateQueries();
});
expect(
await screen.findByRole("status", { name: "Обновляем пассивный доход" }),
).toBeInTheDocument();
expect(screen.getByRole("region", { name: "Выплаты" })).toBeVisible();
expect(screen.getByLabelText("Период")).toHaveTextContent(
"02.08.2026 – 27.08.2026",
);
release();
expect(
await screen.findByText(/Показан последний загруженный результат/),
).toBeInTheDocument();
expect(screen.getByRole("region", { name: "Выплаты" })).toBeVisible();
server.use(
http.post("*/api/v1/tbank-sync", () =>
HttpResponse.json(
{
id: "income",
now: "2026-09-25T00:00:00Z",
scope: { accountId: "account-1", screen: "income" },
},
{ status: 202 },
),
),
http.get("*/api/v1/tbank-sync/:id", () =>
HttpResponse.json(
{
errorCode: null,
id: "income",
now: "2026-09-25T00:00:00Z",
scope: null,
state: "succeeded",
},
),
),
http.get("*/api/v1/brokerage-accounts/account-1/income-analytics", () =>
HttpResponse.json(resource(analytics, { dataRevision: "2" })),
),
);
fireEvent.click(screen.getByRole("button", { name: "Повторить" }));
await waitFor(() =>
expect(
screen.queryByText(/Показан последний загруженный результат/),
).not.toBeInTheDocument(),
);
expect(screen.queryByText(/Показан последний загруженный результат/)).not.toBeInTheDocument();
expect(screen.getByLabelText("Период")).toHaveTextContent(
"02.08.2026 – 27.08.2026",
);