The code cited its plan instead of saying why: `E28 review J4`, `(R6 S3b)`, `S1 justified…`,
`deep-review round 5`. That plan lives in the private ops repo, so for every reader of this one the
citation was noise, and a sentence whose subject was the plan step ("round 2 showed…") hid its
lesson behind an id. Each one is gone and the "why" kept: a bare citation is deleted, a sentence
carrying a lesson is reworded around it ("a later attempt showed…").
Measured (`scripts/audit_metrics.py`, product code): 652 lines in 270 files carried an epic code by
the definition the next commit holds (507 / 241 by the old, two-digit-only one) -> 0. Across all
code, tests, scripts and configs: ~1100 epic-code lines plus ~320 sprint/round ids.
Behaviour unchanged, checked mechanically: every changed .py file has the same AST once docstrings
are blanked; css/sh/toml/yml/json files are identical once comments are stripped; the only
non-comment changes in TS/JS are test titles, one description string in a contract table, and five
ESLint messages, whose text is all the gates snapshot diff holds. Not touched: Markdown (docs and
the changelog keep their history), Alembic migrations, TV episode notation (`S2 · E5`), DESIGN.md
ids (`C1`, `B4`, `S3h`), tracker ids (`SEC-16`, `DX-17`).
One stale claim fixed on the way: test_hls_reaper's docstring said the player checkpoints "every
10 s whether or not it is playing", which plex/stream.py calls wrong; it now says what the code does.
206 lines
7.4 KiB
TypeScript
206 lines
7.4 KiB
TypeScript
// @vitest-environment jsdom
|
|
//
|
|
// An audit row whose server summary is a fixed English line ("rss_poll: ok — new=5, failed=0",
|
|
// "log_level = DEBUG", "Background sync paused") reads in the reader's language, rebuilt from the row's
|
|
// data through the REAL catalog. A row whose summary is data (an e-mail, a URL) keeps it.
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import { cleanup, fireEvent, render } from "@testing-library/react";
|
|
import i18n, { setLanguage } from "../i18n";
|
|
import type { AuditRow } from "../lib/api";
|
|
import { auditColumns } from "./auditColumns";
|
|
|
|
// Unmount BEFORE the language goes back: a mounted reader re-renders on the switch, and under a loaded
|
|
// run that render landed after the test environment was gone ("window is not defined").
|
|
afterEach(() => {
|
|
cleanup();
|
|
setLanguage("en");
|
|
});
|
|
|
|
const row = (over: Partial<AuditRow>): AuditRow => ({
|
|
id: 1,
|
|
created_at: null,
|
|
actor: null,
|
|
action: "job_run",
|
|
target_type: null,
|
|
target_id: null,
|
|
summary: null,
|
|
before: null,
|
|
after: null,
|
|
...over,
|
|
});
|
|
|
|
function details(r: AuditRow): string {
|
|
setLanguage("hu");
|
|
const t = i18n.getFixedT("hu");
|
|
const col = auditColumns(t, "hu", []).find((c) => c.key === "details")!;
|
|
const { container } = render(<>{col.render!(r)}</>);
|
|
return [...container.querySelectorAll(".wrap-break-word")].map((e) => e.textContent).join(" | ");
|
|
}
|
|
|
|
describe("an audit row's details", () => {
|
|
it("name a job run and its result in the reader's language", () => {
|
|
const r = row({
|
|
target_type: "job",
|
|
target_id: "rss_poll",
|
|
summary: "rss_poll: ok — new=5, failed=0",
|
|
after: { status: "ok", summary: "new=5, failed=0" },
|
|
});
|
|
expect(details(r)).toBe("RSS-lekérdezés (új feltöltések) kész | új videó: 5 · sikertelen: 0");
|
|
});
|
|
|
|
it("keep a failed run's error text, which is diagnostic", () => {
|
|
const r = row({
|
|
target_type: "job",
|
|
target_id: "enrich",
|
|
after: { status: "error", summary: "HTTP 403: quotaExceeded" },
|
|
});
|
|
expect(details(r)).toBe(
|
|
"Nem sikerült lefuttatni: Adatdúsítás + élő frissítés | HTTP 403: quotaExceeded",
|
|
);
|
|
});
|
|
|
|
it("name a config change's field and values", () => {
|
|
const set = row({
|
|
action: "config_set",
|
|
target_type: "config",
|
|
target_id: "plex_enabled",
|
|
summary: "plex_enabled = True",
|
|
before: { value: false },
|
|
after: { value: true },
|
|
});
|
|
expect(details(set)).toMatch(/ \| Ki → Be$/);
|
|
expect(details(set)).not.toContain("plex_enabled");
|
|
const reset = row({
|
|
action: "config_reset",
|
|
target_type: "config",
|
|
target_id: "download_upload_max_bytes",
|
|
summary: "download_upload_max_bytes → default",
|
|
before: { value: 5242880 },
|
|
});
|
|
expect(details(reset)).toMatch(/ \| 5\s242\s880 → alapérték$/);
|
|
const secret = row({
|
|
action: "config_set",
|
|
target_type: "config",
|
|
target_id: "youtube_api_key",
|
|
summary: "youtube_api_key = (secret updated)",
|
|
});
|
|
expect(details(secret)).toMatch(/ \| titok frissítve/);
|
|
});
|
|
|
|
it("name a nested result and a skipped run from the row's data", () => {
|
|
const nested = row({
|
|
target_type: "job",
|
|
target_id: "people_enrich",
|
|
after: {
|
|
status: "ok",
|
|
summary: "bios={'enriched': 12}, portraits={'cached': 40}",
|
|
result: { bios: { enriched: 12 }, portraits: { cached: 40 } },
|
|
},
|
|
});
|
|
expect(details(nested)).not.toContain("{");
|
|
expect(details(nested)).toMatch(/^Személyadatok és portrék \(Plex\) kész \| /);
|
|
const skipped = row({
|
|
target_type: "job",
|
|
target_id: "rss_poll",
|
|
after: { status: "skipped", summary: "sync paused" },
|
|
});
|
|
expect(details(skipped)).toBe("RSS-lekérdezés (új feltöltések) kihagyva | a szinkron szünetel");
|
|
});
|
|
|
|
it("tell a secret's reset from its update, and name a choice", () => {
|
|
const reset = row({
|
|
action: "config_reset",
|
|
target_type: "config",
|
|
target_id: "tmdb_api_key",
|
|
summary: "tmdb_api_key → default",
|
|
});
|
|
expect(details(reset)).toMatch(/ \| titok visszaállítva/);
|
|
const choice = row({
|
|
action: "config_set",
|
|
target_type: "config",
|
|
target_id: "plex_transcode_hw",
|
|
before: { value: "auto" },
|
|
after: { value: "on" },
|
|
});
|
|
expect(details(choice)).toMatch(/ \| Automatikus → GPU$/);
|
|
});
|
|
|
|
it("name an interval, a batch and a count in the reader's language", () => {
|
|
expect(
|
|
details(
|
|
row({
|
|
action: "scheduler_interval",
|
|
target_type: "job",
|
|
target_id: "rss_poll",
|
|
summary: "rss_poll → 15 min/run",
|
|
after: { interval_minutes: 15 },
|
|
}),
|
|
),
|
|
).toBe("RSS-lekérdezés (új feltöltések) | 15 percenként");
|
|
expect(
|
|
details(row({ action: "maintenance_tune", after: { revalidate_batch: 50000 } })),
|
|
).toMatch(/^Futásonként újraellenőrzött videók \| 50\s000$/);
|
|
expect(
|
|
details(
|
|
row({ action: "audit_clear", summary: "Cleared 12 audit entries", after: { cleared: 12 } }),
|
|
),
|
|
).not.toContain("Cleared");
|
|
});
|
|
|
|
it("add nothing to a pause, whose action already says it", () => {
|
|
expect(details(row({ action: "sync_pause", summary: "Background sync paused" }))).toBe("");
|
|
});
|
|
|
|
it("keep a summary that is data", () => {
|
|
expect(details(row({ action: "invite_add", summary: "someone@example.com" }))).toBe(
|
|
"someone@example.com",
|
|
);
|
|
});
|
|
});
|
|
|
|
// A folded run (lib/auditGroups) shows its newest run and opens to the earlier ones; a failed run
|
|
// is the line to see in a page of routine ones.
|
|
describe("a folded run of one job", () => {
|
|
const ok = (id: number, enriched: number) =>
|
|
row({
|
|
id,
|
|
target_type: "job",
|
|
target_id: "enrich",
|
|
after: { status: "ok", result: { enriched } },
|
|
});
|
|
|
|
it("names how many earlier runs it holds, and opens to each", () => {
|
|
setLanguage("hu");
|
|
const t = i18n.getFixedT("hu");
|
|
const col = auditColumns(t, "hu", []).find((c) => c.key === "details")!;
|
|
const runs = [ok(3, 50), ok(2, 40), ok(1, 30)];
|
|
const { getByRole, container } = render(<>{col.render!({ ...runs[0]!, runs })}</>);
|
|
const toggle = getByRole("button", { name: "2 korábbi futás" });
|
|
expect(toggle.getAttribute("aria-expanded")).toBe("false");
|
|
expect(container.querySelector("li")).toBeNull();
|
|
fireEvent.click(toggle);
|
|
expect(toggle.getAttribute("aria-expanded")).toBe("true");
|
|
expect([...container.querySelectorAll("li")].map((li) => li.textContent)).toEqual([
|
|
"—dúsítva: 40",
|
|
"—dúsítva: 30",
|
|
]);
|
|
});
|
|
|
|
it("has no toggle for a lone run", () => {
|
|
const t = i18n.getFixedT("hu");
|
|
const col = auditColumns(t, "hu", []).find((c) => c.key === "details")!;
|
|
const { container } = render(<>{col.render!(ok(1, 5))}</>);
|
|
expect(container.querySelector("button")).toBeNull();
|
|
});
|
|
|
|
it("paints a failed run's line in the danger colour", () => {
|
|
const t = i18n.getFixedT("hu");
|
|
const col = auditColumns(t, "hu", []).find((c) => c.key === "details")!;
|
|
const failed = row({ target_type: "job", target_id: "enrich", after: { status: "error" } });
|
|
const { container } = render(<>{col.render!(failed)}</>);
|
|
expect(container.querySelector(".wrap-break-word")!.className).toContain("text-danger");
|
|
const { container: fine } = render(<>{col.render!(ok(2, 5))}</>);
|
|
expect(fine.querySelector(".wrap-break-word")!.className).not.toContain("text-danger");
|
|
});
|
|
});
|