Consume the provided resource-envelope API snapshot. Preserve financial snapshots during refresh, observe synchronization without importing, and fence late responses across account and connection changes.
113 lines
3.4 KiB
TypeScript
113 lines
3.4 KiB
TypeScript
import { QueryClientProvider } from "@tanstack/react-query";
|
|
import {
|
|
act,
|
|
fireEvent,
|
|
render,
|
|
screen,
|
|
waitFor,
|
|
} from "@testing-library/react";
|
|
import { HttpResponse, http } from "msw";
|
|
import type { FC } from "react";
|
|
import { MemoryRouter, useNavigate } from "react-router";
|
|
import { beforeEach, describe, expect, it } from "vitest";
|
|
import { AuthProvider } from "@/features/auth";
|
|
import { createTestQueryClient } from "@/test/query";
|
|
import { resource } from "@/test/resource";
|
|
import { server } from "@/test/server";
|
|
import { ProtectedDocumentTitle } from "./DocumentTitle";
|
|
|
|
const Navigation: FC = () => {
|
|
const navigate = useNavigate();
|
|
return (
|
|
<>
|
|
<button type="button" onClick={() => navigate("/accounts/all/income")}>
|
|
Все счета
|
|
</button>
|
|
<button type="button" onClick={() => navigate(-1)}>
|
|
Назад
|
|
</button>
|
|
</>
|
|
);
|
|
};
|
|
|
|
const renderTitle = (path: string) =>
|
|
render(
|
|
<QueryClientProvider client={createTestQueryClient()}>
|
|
<MemoryRouter initialEntries={[path]}>
|
|
<AuthProvider>
|
|
<ProtectedDocumentTitle />
|
|
<Navigation />
|
|
</AuthProvider>
|
|
</MemoryRouter>
|
|
</QueryClientProvider>,
|
|
);
|
|
|
|
beforeEach(() => {
|
|
document.title = "Previous page";
|
|
server.use(
|
|
http.post("*/api/v1/auth/refresh", () =>
|
|
HttpResponse.json({
|
|
accessToken: "test-token",
|
|
user: { id: "user-1", email: "user@example.com" },
|
|
}),
|
|
),
|
|
);
|
|
});
|
|
|
|
describe("document titles", () => {
|
|
it("updates a loading account name and follows account scope and history", async () => {
|
|
let resolveAccounts!: () => void;
|
|
const accountsReady = new Promise<void>((resolve) => {
|
|
resolveAccounts = resolve;
|
|
});
|
|
server.use(
|
|
http.get("*/api/v1/brokerage-accounts", async () => {
|
|
await accountsReady;
|
|
return HttpResponse.json(resource([{ id: "a", name: "ИИС" }]));
|
|
}),
|
|
);
|
|
renderTitle("/accounts/a/income?from=2026-01-01&to=2026-08-31");
|
|
expect(document.title).toBe("Пассивный доход — Счет — WealthLedger");
|
|
await act(async () => resolveAccounts());
|
|
await waitFor(() =>
|
|
expect(document.title).toBe("Пассивный доход — ИИС — WealthLedger"),
|
|
);
|
|
fireEvent.click(screen.getByRole("button", { name: "Все счета" }));
|
|
expect(document.title).toBe("Пассивный доход — Все счета — WealthLedger");
|
|
fireEvent.click(screen.getByRole("button", { name: "Назад" }));
|
|
expect(document.title).toBe("Пассивный доход — ИИС — WealthLedger");
|
|
});
|
|
|
|
it.each([
|
|
["bonds", "SU26238RMFS4", "Облигация", "ОФЗ 26238"],
|
|
["stocks", "SBER", "Акция", "Сбербанк"],
|
|
])(
|
|
"updates the %s title when instrument data arrives",
|
|
async (kind, id, fallback, name) => {
|
|
server.use(
|
|
http.get(`*/api/v1/${kind}/by-ticker/:ticker`, () =>
|
|
HttpResponse.json(resource({ name })),
|
|
),
|
|
);
|
|
renderTitle(`/${kind}/${id}`);
|
|
expect(document.title).toBe(`${fallback} — WealthLedger`);
|
|
await waitFor(() =>
|
|
expect(document.title).toBe(`${name} — WealthLedger`),
|
|
);
|
|
},
|
|
);
|
|
|
|
it("keeps a useful title when the instrument is unavailable", async () => {
|
|
let requested = false;
|
|
server.use(
|
|
http.get("*/api/v1/stocks/by-ticker/:ticker", () => {
|
|
requested = true;
|
|
return HttpResponse.json({ code: "NOT_FOUND" }, { status: 404 });
|
|
}),
|
|
);
|
|
renderTitle("/stocks/missing");
|
|
await waitFor(() => expect(requested).toBe(true));
|
|
expect(document.title).toBe("Акция — WealthLedger");
|
|
});
|
|
});
|