chore(release): 1.2.0 #94

Merged
codex-bot merged 20 commits from develop into main 2026-10-18 17:21:16 +03:00
4 changed files with 39 additions and 14 deletions
Showing only changes of commit f3725c202b - Show all commits
+1 -6
View File
@@ -88,7 +88,6 @@ const quote
function setup(
options: {
ambiguousTicker?: boolean;
failBond?: boolean;
failCoupons?: boolean;
noPosition?: boolean;
path?: string;
@@ -100,11 +99,7 @@ function setup(
const resolved = { ...bond, slug: options.slug ?? uid };
let isFailQuote = false;
server.use(
http.get("*/api/v1/bonds/:uid", () =>
options.failBond
? HttpResponse.json({ code: "NOT_FOUND" }, { status: 404 })
: HttpResponse.json(resource(resolved)),
),
http.get("*/api/v1/bonds/:uid", () => HttpResponse.json(resource(resolved))),
http.get("*/api/v1/bonds/by-ticker/:ticker", ({ request }) => {
requests.push(new URL(request.url));
@@ -1,6 +1,6 @@
import { MantineProvider } from "@mantine/core";
import { QueryClientProvider } from "@tanstack/react-query";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
import { http, HttpResponse } from "msw";
import { MemoryRouter } from "react-router";
import { afterEach, describe, expect, it, vi } from "vitest";
@@ -12,19 +12,37 @@ import { server } from "@/test/server";
import { StocksPage } from "./StocksPage";
import { useStocksPageVm } from "./StocksPage.vm";
const pageOperations: Promise<void>[] = [];
const StocksPageVmProbe = () => {
const vm = useStocksPageVm();
return (
<>
<button onClick={vm.onSearch}>search</button>
<button onClick={() => vm.onPage(2)}>page</button>
<button
onClick={() => {
pageOperations.push(vm.search());
}}
>
search
</button>
<button
onClick={() => {
pageOperations.push(vm.changePage(2));
}}
>
page
</button>
<output>{vm.items.map(item => item.name).join(", ")}</output>
</>
);
};
afterEach(() => vi.useRealTimers());
afterEach(() => {
pageOperations.length = 0;
return vi.useRealTimers();
});
describe("stock search", () => {
it("waits for a meaningful query and uses the server-verified ticker link", async () => {
@@ -230,9 +248,12 @@ describe("stock search", () => {
fireEvent.click(screen.getByRole("button", { name: "page" }));
fireEvent.click(screen.getByRole("button", { name: "search" }));
await screen.findByText("Новый");
oldPage.resolve();
await act(async () => {
oldPage.resolve();
await pageOperations[0];
});
await waitFor(() => expect(screen.getByText("Новый")).toBeVisible());
expect(screen.getByText("Новый")).toBeVisible();
expect(screen.queryByText("Старый результат")).not.toBeInTheDocument();
});
@@ -101,6 +101,7 @@ function useStocksPageVm() {
};
return {
changePage,
criteria,
error,
items: page?.items ?? [],
@@ -111,6 +112,8 @@ function useStocksPageVm() {
onSearch: () => void search(),
page: page?.page,
resultTime: page?.asOf,
// Test seam: settle the actual operation instead of the handler release.
search,
searched: page !== null,
totalPages: page ? page.page + Number(page.hasNext) : 0,
};
+8 -2
View File
@@ -164,10 +164,16 @@ describe("persistent resource query lifecycle", () => {
});
await waitFor(() => expect(isStarted).toBe(true));
await act(() => result.current.observe());
// Capture the observation promise before releasing the old handler; the
// final assertion must follow its settlement, not the handler release.
let observation: Promise<unknown> = Promise.resolve();
await act(async () => {
observation = result.current.observe() ?? Promise.resolve();
await observation;
});
await act(async () => {
release();
await blocked;
await observation;
});
expect(result.current.data).toEqual(snapshot);
});