chore: finish frontend ESLint migration #18

Enable every plugin recommended preset and replace Biome with ESLint formatting.

Preserve API contracts and JSX whitespace; verify source, tests, builds and tooling.
This commit is contained in:
2026-09-28 16:36:40 +03:00
committed by ksv741
parent 57630102e4
commit 72d7835227
253 changed files with 10059 additions and 8864 deletions
@@ -7,11 +7,13 @@ import {
waitFor,
within,
} from "@testing-library/react";
import { HttpResponse, http } from "msw";
import { http, HttpResponse } from "msw";
import { describe, expect, it, vi } from "vitest";
import { apiQueryClient, configureAuthClient } from "@/shared/api";
import { createTestQueryClient } from "@/test/query";
import { server } from "@/test/server";
import { tbankConnectionQueryOptions } from "../../model/connection-boundary";
import { TbankConnectionSection } from "./TbankConnectionSection";
@@ -54,8 +56,8 @@ const unrelatedQueryKey = apiQueryClient.queryOptions(
function renderSection(client: QueryClient) {
configureAuthClient({
accessToken: () => "test-token",
refresh: async () => true,
clear: vi.fn(),
refresh: () => Promise.resolve(true),
});
return render(
<MantineProvider>
@@ -69,12 +71,14 @@ function renderSection(client: QueryClient) {
function seededClient() {
const client = createTestQueryClient();
client.setQueryData(brokerageAccountsQueryKey, [
{
id: "account-1",
name: "Основной счет",
type: "BROKERAGE",
openedOn: null,
},
(/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
{
id: "account-1",
name: "Основной счет",
openedOn: null,
type: "BROKERAGE",
}
/* eslint-enable unicorn/no-null */),
]);
client.setQueryData(portfolioQueryKey, { source: "previous-connection" });
client.setQueryData(stockQueryKey, { source: "previous-connection" });
@@ -87,10 +91,8 @@ function seededClient() {
describe("TbankConnectionSection", () => {
it("preserves cached status and a draft entered during a delayed failed refetch", async () => {
const status = { connected: true, connectedAt: "2026-08-14T00:00:00Z" };
let finishRefetch: (() => void) | undefined;
const response = new Promise<void>((resolve) => {
finishRefetch = resolve;
});
const { promise: response, resolve: finishRefetch } = Promise.withResolvers<void>();
let reads = 0;
server.use(
http.get("*/api/v1/tbank-connection", async () => {
@@ -141,7 +143,9 @@ describe("TbankConnectionSection", () => {
reads += 1;
return reads === 1
? HttpResponse.json({ code: "TBANK_UNAVAILABLE" }, { status: 503 })
: HttpResponse.json({ connected: false, connectedAt: null });
: HttpResponse.json((/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
{ connected: false, connectedAt: null }
/* eslint-enable unicorn/no-null */));
}),
);
renderSection(createTestQueryClient());
@@ -238,22 +242,21 @@ describe("TbankConnectionSection", () => {
it("cancels an in-flight previous-boundary query and ignores its late response", async () => {
const client = seededClient();
let finishPrevious: ((value: { source: string }) => void) | undefined;
let aborted = false;
const previousResponse = new Promise<{ source: string }>((resolve) => {
finishPrevious = resolve;
});
let isAborted = false;
const { promise: previousResponse, resolve: finishPrevious } = Promise.withResolvers<{ source: string }>();
const previousRequest = client
.fetchQuery({
queryKey: operationsQueryKey,
.query({
queryFn: ({ signal }) => {
signal.addEventListener("abort", () => {
aborted = true;
isAborted = true;
});
return previousResponse;
},
queryKey: operationsQueryKey,
})
.catch(() => undefined);
// eslint-disable-next-line unicorn/prefer-await -- Attach the handler immediately and retain the pending promise for queue/race ordering.
.catch(() => {});
renderSection(client);
await screen.findByText("Не подключено");
@@ -262,7 +265,7 @@ describe("TbankConnectionSection", () => {
});
fireEvent.click(screen.getByRole("button", { name: "Подключить" }));
await waitFor(() => expect(aborted).toBe(true));
await waitFor(() => expect(isAborted).toBe(true));
await previousRequest;
finishPrevious?.({ source: "previous-connection" });
await Promise.resolve();
@@ -298,10 +301,8 @@ describe("TbankConnectionSection", () => {
it("keeps DELETE recovery inside the dialog and preserves cache until successful retry", async () => {
let deletes = 0;
let finishDelete: (() => void) | undefined;
const response = new Promise<void>((resolve) => {
finishDelete = resolve;
});
const { promise: response, resolve: finishDelete } = Promise.withResolvers<void>();
server.use(
http.get("*/api/v1/tbank-connection", () =>
HttpResponse.json({
@@ -327,6 +328,7 @@ describe("TbankConnectionSection", () => {
name: "Удалить подключение?",
});
await waitFor(() =>
// eslint-disable-next-line testing-library/no-node-access -- This assertion checks DOM structure, decoration or focus behavior that semantic queries cannot establish.
expect(dialog.contains(document.activeElement)).toBe(true),
);
const confirm = within(dialog).getByRole("button", { name: /^Удалить$/ });
@@ -340,7 +342,7 @@ describe("TbankConnectionSection", () => {
document.body.tabIndex = -1;
document.body.focus();
document.body.removeAttribute("tabindex");
expect(document.activeElement).toBe(document.body);
expect(document.body).toHaveFocus();
finishDelete?.();
expect(await within(dialog).findByRole("alert")).toHaveTextContent(