refactor: enforce frontend view model boundaries
Frontend verify / commits (pull_request) Successful in 28s
Frontend verify / security (pull_request) Successful in 10s
Frontend verify / verify (pull_request) Successful in 8m19s

This commit is contained in:
2026-09-28 18:48:23 +03:00
parent 5b69003516
commit ca0ad4f824
287 changed files with 8558 additions and 4538 deletions
+38 -22
View File
@@ -18,6 +18,7 @@ import { server } from "@/test/server";
import { CardsPage } from "./CardsPage";
const money = (value: string) => ({ currency: "RUB", value });
function renderCards(isFail = false, hasCategoryFailure = false) {
configureAuthClient({
accessToken: () => "test",
@@ -32,7 +33,8 @@ function renderCards(isFail = false, hasCategoryFailure = false) {
isFail ? HttpResponse.error() : HttpResponse.json([]),
),
http.get("*/api/v1/bank-cards/summary", () =>
HttpResponse.json((/* 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. */
HttpResponse.json(
{
cardId: null,
categories: [],
@@ -40,10 +42,12 @@ function renderCards(isFail = false, hasCategoryFailure = false) {
month: "2026-09",
net: money("0"),
refunds: money("0"),
}
/* eslint-enable unicorn/no-null */)),
},
/* eslint-enable unicorn/no-null */
),
),
);
return render(
<QueryClientProvider client={createTestQueryClient()}>
<MantineProvider env="test">
@@ -54,6 +58,7 @@ function renderCards(isFail = false, hasCategoryFailure = false) {
</QueryClientProvider>,
);
}
describe("CardsPage", () => {
it("preserves exact negative opening amount and the creation intent through unknown failure", async () => {
renderCards();
@@ -67,12 +72,15 @@ describe("CardsPage", () => {
server.use(
http.post("*/api/v1/bank-cards", async ({ request }) => {
submitted.push((await request.json()) as Record<string, unknown>);
if (submitted.length === 1) {
const deferred = Promise.withResolvers<void>();
resolve = deferred.resolve;
await deferred.promise;
return HttpResponse.error();
}
return HttpResponse.json({ id: submitted[0].id }, { status: 201 });
}),
);
@@ -111,14 +119,16 @@ describe("CardsPage", () => {
expect(screen.queryByRole("dialog")).not.toBeInTheDocument(),
);
expect(submitted[0]).toEqual(submitted[1]);
expect(submitted[0]).toMatchObject((/* 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(submitted[0]).toMatchObject(
{
bankName: null,
lastFour: null,
name: "Повседневная",
openingBalance: money("-92233720368547758.08"),
}
/* eslint-enable unicorn/no-null */));
},
/* eslint-enable unicorn/no-null */
);
});
it("uses archive only for card list and keeps all-card summary including negative net", async () => {
renderCards();
@@ -126,20 +136,22 @@ describe("CardsPage", () => {
server.use(
http.get("*/api/v1/bank-cards", ({ request }) => {
requests.push(new URL(request.url).search);
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
return HttpResponse.json([
(/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
{
archivedAt: "2026-09-01",
balance: money("0"),
bankName: null,
id: "demo",
lastFour: null,
name: "Запасная",
openingBalance: money("0"),
openingDate: "2026-01-01",
version: 1,
}
/* eslint-enable unicorn/no-null */),
{
archivedAt: "2026-09-01",
balance: money("0"),
bankName: null,
id: "demo",
lastFour: null,
name: "Запасная",
openingBalance: money("0"),
openingDate: "2026-01-01",
version: 1,
},
/* eslint-enable unicorn/no-null */
]);
}),
);
@@ -162,15 +174,19 @@ describe("CardsPage", () => {
server.use(
http.get("*/api/v1/bank-cards/summary", ({ request }) => {
requests.push(new URL(request.url).search);
return HttpResponse.json((/* 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. */
return HttpResponse.json(
{
cardId: null,
categories: [],
expenses: money("0"),
net: money("0"),
refunds: money("0"),
}
/* eslint-enable unicorn/no-null */));
},
/* eslint-enable unicorn/no-null */
);
}),
);
fireEvent.click(screen.getByLabelText("Период"));