fix: make all CI jobs pass (integration, ui) and restore prefix dialog reset
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 28s
CI / tests-integration (push) Successful in 1m34s
CI / tests-unit (push) Successful in 1m35s
CI / tests-ui (push) Successful in 2m20s
CI / preflight (push) Skipped
CI / deploy (push) Failing after 2m37s
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 28s
CI / tests-integration (push) Successful in 1m34s
CI / tests-unit (push) Successful in 1m35s
CI / tests-ui (push) Successful in 2m20s
CI / preflight (push) Skipped
CI / deploy (push) Failing after 2m37s
Three failing test suites blocked CI. All three were test defects, not application bugs. Integration tests (integration/database.test.ts) ------------------------------------------------ The suite set NODE_ENV=test, which makes cache.cached() short-circuit both its Redis read (src/lib/cache.ts:226) and its write (:249). A suite whose stated purpose is exercising the real Redis path therefore never touched Redis. Switched to NODE_ENV=development, the only non-production value src/env.ts accepts, so the shared-cache code paths are genuinely covered. Three assertions then needed correcting for real Redis semantics: - `await cache.cached(...)` followed by `.resolves` can never hold: await yields a value, not a Promise. Assert the value directly. - A cached negative result is stored as the JSON encoding of null, so `redis.get(key)` returns "null", not null. - The news negative-cache key does not exist at all, so `ttl()` returned -2. Now that the write path is live the key is created and the TTL assertion holds as originally written. UI tests (src/app/admin/prefixes/prefix-dialog.tsx) --------------------------------------------------- The form-reset effect had `isOpen` removed from its dependency array. The component returns null when closed, so the effect only ever ran on mount: reopening the dialog no longer cleared the fields and a dismissed-but- unsaved edit reappeared. Two tests in e2e/ui/unsaved-changes.spec.ts caught this. Restored the dependency and documented why it is load-bearing. The remaining edits in this branch drop stale biome-ignore comments that suppressed useExhaustiveDependencies and noArrayIndexKey diagnostics. Where the suppression had been load-bearing for behaviour, the underlying dependency is now listed explicitly rather than silenced. Verified: check (toolchain, audit, lint, i18n, typecheck), unit 3315 passed, integration 20 passed, UI 72 passed / 2 skipped.
This commit is contained in:
1 parent
1c9ddcd48a
commit
eddb7edea4
21 files changed
+88
-72
No files matched your search
@@ -1,7 +1,15 @@
|
||||
import { describe, it, expect, vi, beforeAll, afterAll, afterEach } from "vitest";
|
||||
import { setupServer } from "msw/node";
|
||||
import { http, HttpResponse } from "msw";
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
import { HttpResponse, http } from "msw";
|
||||
import { setupServer } from "msw/node";
|
||||
import {
|
||||
afterAll,
|
||||
afterEach,
|
||||
beforeAll,
|
||||
describe,
|
||||
expect,
|
||||
it,
|
||||
vi,
|
||||
} from "vitest";
|
||||
import { furnitureJobsQueryOptions } from "./furniture-jobs-query";
|
||||
|
||||
let calls = 0;
|
||||
@@ -9,39 +17,48 @@ let release: (() => void) | null = null;
|
||||
|
||||
// Cast to any to bypass strict MSW v3 config types in the test environment
|
||||
const server = setupServer(
|
||||
http.get("https://localhost/api/admin/studio/furniture/jobs", async () => {
|
||||
calls++;
|
||||
if (release) await new Promise<void>((resolve) => { release = resolve; });
|
||||
return HttpResponse.json({ jobs: [], nextCursor: null });
|
||||
})
|
||||
http.get("https://localhost/api/admin/studio/furniture/jobs", async () => {
|
||||
calls++;
|
||||
if (release)
|
||||
await new Promise<void>((resolve) => {
|
||||
release = resolve;
|
||||
});
|
||||
return HttpResponse.json({ jobs: [], nextCursor: null });
|
||||
}),
|
||||
);
|
||||
|
||||
beforeAll(() => server.listen({ onUnhandledRequest: "bypass" } as any));
|
||||
afterEach(() => {
|
||||
calls = 0;
|
||||
release = null;
|
||||
server.resetHandlers();
|
||||
calls = 0;
|
||||
release = null;
|
||||
server.resetHandlers();
|
||||
});
|
||||
afterAll(() => {
|
||||
try { server.close(); } catch (e) {}
|
||||
try {
|
||||
server.close();
|
||||
} catch (_e) {}
|
||||
});
|
||||
|
||||
describe("furniture history HTTP query", () => {
|
||||
const client = () => new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
const client = () =>
|
||||
new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
|
||||
it("deduplicates simultaneous refreshes and caches their validated result", async () => {
|
||||
const cache = client();
|
||||
// Use type assertions to allow the test to manipulate options freely
|
||||
const options = furnitureJobsQueryOptions(false, null) as any;
|
||||
options.queryKey = ["furniture-import-history", false, null];
|
||||
options.queryFn = () => fetch("https://localhost/api/admin/studio/furniture/jobs").then(r => r.json());
|
||||
it("deduplicates simultaneous refreshes and caches their validated result", async () => {
|
||||
const cache = client();
|
||||
// Use type assertions to allow the test to manipulate options freely
|
||||
const options = furnitureJobsQueryOptions(false, null) as any;
|
||||
options.queryKey = ["furniture-import-history", false, null];
|
||||
options.queryFn = () =>
|
||||
fetch("https://localhost/api/admin/studio/furniture/jobs").then((r) =>
|
||||
r.json(),
|
||||
);
|
||||
|
||||
const first = cache.fetchQuery(options);
|
||||
const second = cache.fetchQuery(options);
|
||||
|
||||
await vi.waitFor(() => expect(calls).toBe(1));
|
||||
if (release) release();
|
||||
|
||||
await Promise.all([first, second]);
|
||||
});
|
||||
const first = cache.fetchQuery(options);
|
||||
const second = cache.fetchQuery(options);
|
||||
|
||||
await vi.waitFor(() => expect(calls).toBe(1));
|
||||
if (release) release();
|
||||
|
||||
await Promise.all([first, second]);
|
||||
});
|
||||
});
|
||||
@@ -113,7 +113,6 @@ export function LayoutPreview({
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: positional layout grid placeholders
|
||||
key={`empty-${index}`}
|
||||
className="rounded bg-muted/40"
|
||||
style={{ width: compact ? 22 : 36, height: compact ? 22 : 36 }}
|
||||
|
||||
Reference in new issue
Block a user