Files
kandev/apps/web/components/settings/system/job-progress-indicator.test.tsx
T
José Almeida 041a19f060 feat: service-managed UI self-update (#1210)
* feat: add service-managed self-update

* chore: add temporary self-update test scripts

* chore: simplify temporary script markdown fences

* chore: run frontend in temporary self-update scripts

* fix: show self-update job progress after apply

* chore: add real npm self-update test script

* fix: isolate npm self-update prefix

* fix: detect npm service installs from bin shim

* chore: reset service before real npm update test

* chore: expand real npm status diagnostics

* fix: preserve service home during self-update

* fix(cli): tee self-update helper output to a log file

* fix(cli): avoid launchd bootstrap race when reloading the macOS service

* fix(backend): run macOS self-update helper once via transient launchd plist

* fix(web): show self-update progress and lock the apply button until the update lands

* fix(cli): reinstall via the kandev wrapper on Homebrew self-update

* chore: remove temp self-update test scripts

* fix(web): drop unused apply path from useUpdates hook

* fix(backend): snapshot install state once in apply preflight

* docs: align self-update docs with transient LaunchAgent flow

* chore(release): run cli bundle from apps workspace root

* fix(backend): guard against concurrent self-update applies

* fix(backend): check scheme and helper paths in self-update apply

* fix(backend): drop duplicate binary name from npx manual command

* fix(cli): allow --help for service self-update without --intent

* fix(cli): harden self-update dir perms and darwin uid resolution

* fix(web): set required POST fields last in applyUpdate

* docs: use JSON body notation for the apply endpoint

* fix(backend): expire self-update guard so a stuck helper cannot wedge apply

* refactor(cli): collapse redundant writeSync branch in self-update log
2026-06-01 17:49:15 +01:00

70 lines
2.1 KiB
TypeScript

import { cleanup, render, screen } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { SystemJob } from "@/lib/types/system";
const mocks = vi.hoisted(() => ({
useSystemJob: vi.fn(),
useSystemJobs: vi.fn(),
}));
vi.mock("@/hooks/domains/system/use-system-jobs", () => ({
useSystemJob: mocks.useSystemJob,
useSystemJobs: mocks.useSystemJobs,
}));
import { JobProgressIndicator } from "./job-progress-indicator";
function job(overrides: Partial<SystemJob> = {}): SystemJob {
return {
id: "job-1",
kind: "self-update",
state: "succeeded",
started_at: "2026-05-30T00:00:00.000Z",
...overrides,
};
}
describe("JobProgressIndicator", () => {
beforeEach(() => {
mocks.useSystemJob.mockReset();
mocks.useSystemJobs.mockReset();
});
afterEach(() => {
cleanup();
});
it("renders a pinned job fetched by id when the websocket list missed it", () => {
mocks.useSystemJob.mockReturnValue(job({ id: "job-42" }));
mocks.useSystemJobs.mockReturnValue([]);
render(<JobProgressIndicator kind="self-update" jobId="job-42" />);
const indicator = screen.getByTestId("system-job-self-update");
expect(indicator.getAttribute("data-state")).toBe("succeeded");
expect(indicator.textContent).toContain("Done");
});
it("falls back to the latest kind-matched job when no id is pinned", () => {
mocks.useSystemJob.mockReturnValue(undefined);
mocks.useSystemJobs.mockReturnValue([job({ id: "job-2", state: "failed" })]);
render(<JobProgressIndicator kind="self-update" />);
expect(screen.getByTestId("system-job-self-update").getAttribute("data-state")).toBe("failed");
});
it("allows a flow-specific success label", () => {
mocks.useSystemJob.mockReturnValue(job({ id: "job-42", state: "succeeded" }));
mocks.useSystemJobs.mockReturnValue([]);
render(
<JobProgressIndicator kind="self-update" jobId="job-42" successLabel="Restarting service" />,
);
expect(screen.getByText("Restarting service")).not.toBeNull();
expect(screen.queryByText("Done")).toBeNull();
});
});