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.
127 lines
3.9 KiB
TypeScript
127 lines
3.9 KiB
TypeScript
import { MantineProvider } from "@mantine/core";
|
|
import { render, screen, within } from "@testing-library/react";
|
|
import { MemoryRouter } from "react-router";
|
|
import { describe, expect, it } from "vitest";
|
|
import { resource } from "@/test/resource";
|
|
import { brokerageAccountCards } from "../../model/display";
|
|
import { BrokerageAccountList } from "./BrokerageAccountList";
|
|
|
|
describe("BrokerageAccountList", () => {
|
|
it("renders account details and an account link", () => {
|
|
render(
|
|
<MantineProvider>
|
|
<MemoryRouter>
|
|
<BrokerageAccountList
|
|
accounts={brokerageAccountCards([
|
|
{
|
|
id: "account-1",
|
|
name: "Основной",
|
|
type: "BROKERAGE",
|
|
openedOn: "2024-08-13",
|
|
portfolioSummary: {
|
|
stockPositionCount: 5,
|
|
bondPositionCount: 12,
|
|
totalsByCurrency: [
|
|
{ currency: "RUB", value: "1500" },
|
|
{ currency: "USD", value: "20" },
|
|
{ currency: "EUR", value: "5" },
|
|
],
|
|
},
|
|
},
|
|
{
|
|
id: "account-2",
|
|
name: "Недоступный",
|
|
type: "BROKERAGE",
|
|
openedOn: null,
|
|
portfolioSummary: null,
|
|
},
|
|
{
|
|
id: "account-3",
|
|
name: "Пустой",
|
|
type: "BROKERAGE",
|
|
openedOn: null,
|
|
portfolioSummary: {
|
|
totalsByCurrency: [],
|
|
stockPositionCount: 2,
|
|
bondPositionCount: 0,
|
|
},
|
|
},
|
|
])}
|
|
/>
|
|
</MemoryRouter>
|
|
</MantineProvider>,
|
|
);
|
|
|
|
expect(screen.getByRole("link", { name: /Основной/ })).toHaveAttribute(
|
|
"href",
|
|
"/accounts/account-1",
|
|
);
|
|
expect(screen.getAllByText("Брокерский счет")).toHaveLength(3);
|
|
expect(screen.getByText(/^Открыт /)).toBeInTheDocument();
|
|
expect(screen.getByText("1 500 ₽")).toBeInTheDocument();
|
|
expect(screen.getByText("20 USD")).toBeInTheDocument();
|
|
expect(screen.getByText("Еще 1 валюта")).toBeInTheDocument();
|
|
expect(screen.getByText("Сводка временно недоступна")).toBeInTheDocument();
|
|
expect(screen.getByText("Нет текущих сумм")).toBeInTheDocument();
|
|
expect(screen.getAllByText("Открыть счет")).toHaveLength(3);
|
|
const available = within(screen.getByRole("link", { name: /Основной/ }));
|
|
expect(available.getByText("Акции").nextElementSibling).toHaveTextContent(
|
|
"5",
|
|
);
|
|
expect(
|
|
available.getByText("Облигации").nextElementSibling,
|
|
).toHaveTextContent("12");
|
|
const unvalued = within(screen.getByRole("link", { name: /Пустой/ }));
|
|
expect(unvalued.getByText("Акции").nextElementSibling).toHaveTextContent(
|
|
"2",
|
|
);
|
|
expect(
|
|
unvalued.getByText("Облигации").nextElementSibling,
|
|
).toHaveTextContent("0");
|
|
expect(
|
|
within(screen.getByRole("link", { name: /Недоступный/ })).queryByText(
|
|
"Акции",
|
|
),
|
|
).not.toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
it("shows portfolio summary freshness independently for each account", () => {
|
|
const accounts = brokerageAccountCards(
|
|
["fresh", "stale"].map((id) => ({
|
|
id,
|
|
name: id,
|
|
type: "BROKERAGE" as const,
|
|
openedOn: null,
|
|
portfolioSummary: {
|
|
stockPositionCount: 1,
|
|
bondPositionCount: 0,
|
|
totalsByCurrency: [{ currency: "RUB", value: "10" }],
|
|
},
|
|
})),
|
|
[
|
|
resource(null, { resourceKey: "portfolio/fresh", freshness: "fresh" })
|
|
.meta,
|
|
resource(null, { resourceKey: "portfolio/stale", freshness: "stale" })
|
|
.meta,
|
|
],
|
|
);
|
|
render(
|
|
<MantineProvider>
|
|
<MemoryRouter>
|
|
<BrokerageAccountList accounts={accounts} />
|
|
</MemoryRouter>
|
|
</MantineProvider>,
|
|
);
|
|
expect(
|
|
within(screen.getByRole("link", { name: /stale/ })).getByText(
|
|
"Данные требуют обновления",
|
|
),
|
|
).toBeVisible();
|
|
expect(
|
|
within(screen.getByRole("link", { name: /fresh/ })).queryByText(
|
|
"Данные требуют обновления",
|
|
),
|
|
).not.toBeInTheDocument();
|
|
});
|