test: the gate's output carries no noise to hide a real warning in
- Home tests mocked the api without downloadIndex, so every card's download button logged a missing-queryFn error (64 stderr blocks per run). - QueryState rendered without an i18n instance; Modal.fullscreen awaited a synchronous act, which React reports as an act environment it does not support. - pytest: Starlette 1.x's TestClient is built on httpx2 and warned on every run without it (pinned in requirements-dev); alembic.ini declares its path separator.
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
[alembic]
|
[alembic]
|
||||||
script_location = alembic
|
script_location = alembic
|
||||||
prepend_sys_path = .
|
prepend_sys_path = .
|
||||||
|
# Split the path list the way the OS does (alembic's legacy space/comma/colon split is deprecated).
|
||||||
|
path_separator = os
|
||||||
|
|
||||||
[loggers]
|
[loggers]
|
||||||
keys = root,sqlalchemy,alembic
|
keys = root,sqlalchemy,alembic
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
# Test + lint tooling — NEVER in the prod image. Installed only by backend/Dockerfile.test (the
|
# Test + lint tooling — NEVER in the prod image. Installed only by backend/Dockerfile.test (the
|
||||||
# throwaway test image), which the prod build (root Dockerfile) never references. Pinned so the
|
# throwaway test image), which the prod build (root Dockerfile) never references. Pinned so the
|
||||||
# suite is reproducible: pytest for the pure-logic tests, and ruff at the SAME version the gate's
|
# suite is reproducible: pytest for the pure-logic tests, and ruff at the SAME version the gate's
|
||||||
# backend lint lane currently runs on the host (see the run_lint note in siftlode.sh). httpx is
|
# backend lint lane runs on the host (the gate fails when the host's ruff is not this one). httpx2:
|
||||||
# already an app dependency (requirements.txt), so its TestClient needs nothing extra here.
|
# Starlette 1.x's TestClient is built on it (`import httpx2 as httpx`) and only falls back to the
|
||||||
|
# app's own httpx with a deprecation warning on every run.
|
||||||
pytest==8.4.2
|
pytest==8.4.2
|
||||||
ruff==0.15.21
|
ruff==0.15.21
|
||||||
|
httpx2==2.13.0
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ vi.mock("../lib/api", () => ({
|
|||||||
setState: () => Promise.resolve(),
|
setState: () => Promise.resolve(),
|
||||||
watchLaterAdd: () => Promise.resolve(),
|
watchLaterAdd: () => Promise.resolve(),
|
||||||
watchLaterRemove: () => Promise.resolve(),
|
watchLaterRemove: () => Promise.resolve(),
|
||||||
|
downloadIndex: () => Promise.resolve({}), // the cards' download buttons read it
|
||||||
},
|
},
|
||||||
DISCOVER_BUDGETS: ["short", "medium", "long", "any"],
|
DISCOVER_BUDGETS: ["short", "medium", "long", "any"],
|
||||||
discoverCardKey: (c: { source: string; id: string }) => `${c.source}:${c.id}`,
|
discoverCardKey: (c: { source: string; id: string }) => `${c.source}:${c.id}`,
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ vi.mock("../lib/api", () => ({
|
|||||||
setState: () => Promise.resolve(),
|
setState: () => Promise.resolve(),
|
||||||
watchLaterAdd: () => Promise.resolve(),
|
watchLaterAdd: () => Promise.resolve(),
|
||||||
watchLaterRemove: () => Promise.resolve(),
|
watchLaterRemove: () => Promise.resolve(),
|
||||||
|
downloadIndex: () => Promise.resolve({}), // the cards' download buttons read it
|
||||||
comfortPins: (...a: unknown[]) => comfortPins(...a),
|
comfortPins: (...a: unknown[]) => comfortPins(...a),
|
||||||
addComfortPin: (...a: unknown[]) => addComfortPin(...a),
|
addComfortPin: (...a: unknown[]) => addComfortPin(...a),
|
||||||
removeComfortPin: (...a: unknown[]) => removeComfortPin(...a),
|
removeComfortPin: (...a: unknown[]) => removeComfortPin(...a),
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ describe("a dialog open while fullscreen is left", () => {
|
|||||||
it("keeps what the viewer had typed in it, and the focus inside it", async () => {
|
it("keeps what the viewer had typed in it, and the focus inside it", async () => {
|
||||||
const stage = document.createElement("div");
|
const stage = document.createElement("div");
|
||||||
document.body.appendChild(stage);
|
document.body.appendChild(stage);
|
||||||
await setFullscreen(stage);
|
setFullscreen(stage);
|
||||||
render(
|
render(
|
||||||
<Modal title="Download" onClose={() => {}}>
|
<Modal title="Download" onClose={() => {}}>
|
||||||
<input aria-label="name" defaultValue="" />
|
<input aria-label="name" defaultValue="" />
|
||||||
@@ -42,7 +42,7 @@ describe("a dialog open while fullscreen is left", () => {
|
|||||||
field.focus();
|
field.focus();
|
||||||
expect(stage.contains(field)).toBe(true);
|
expect(stage.contains(field)).toBe(true);
|
||||||
|
|
||||||
await setFullscreen(null); // the browser's own Esc leaves fullscreen; the dialog stays open
|
setFullscreen(null); // the browser's own Esc leaves fullscreen; the dialog stays open
|
||||||
|
|
||||||
const after = screen.getByLabelText("name") as HTMLInputElement;
|
const after = screen.getByLabelText("name") as HTMLInputElement;
|
||||||
expect(after.value).toBe("my cut");
|
expect(after.value).toBe("my cut");
|
||||||
@@ -78,7 +78,7 @@ describe("a dialog with an autoFocus child", () => {
|
|||||||
const field = screen.getByLabelText("query");
|
const field = screen.getByLabelText("query");
|
||||||
expect(document.activeElement).toBe(field);
|
expect(document.activeElement).toBe(field);
|
||||||
|
|
||||||
await setFullscreen(stage); // the player goes fullscreen under the open dialog
|
setFullscreen(stage); // the player goes fullscreen under the open dialog
|
||||||
|
|
||||||
expect(stage.contains(field)).toBe(true);
|
expect(stage.contains(field)).toBe(true);
|
||||||
expect(document.activeElement).toBe(field);
|
expect(document.activeElement).toBe(field);
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|||||||
import { render, cleanup } from "@testing-library/react";
|
import { render, cleanup } from "@testing-library/react";
|
||||||
import { LoadingState } from "./QueryState";
|
import { LoadingState } from "./QueryState";
|
||||||
|
|
||||||
|
// The label is not under test; without an i18n instance react-i18next warns on every render.
|
||||||
|
vi.mock("react-i18next", () => ({ useTranslation: () => ({ t: (key: string) => key }) }));
|
||||||
|
|
||||||
let now = 0;
|
let now = 0;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.spyOn(performance, "now").mockImplementation(() => now);
|
vi.spyOn(performance, "now").mockImplementation(() => now);
|
||||||
|
|||||||
Reference in New Issue
Block a user