/** * @file Tests for CloneProgress: a queued clone shows its place in the * server's clone queue, a running one git's phase, percent and speed with a * bar, and nothing shows before the server knows the token. Also that * `newCloneToken` makes a token the server accepts. * @author Nguyễn Ngọc Trí Vĩ */ import { describe, it, expect, vi, beforeEach } from "vitest"; import { render, screen } from "@testing-library/react"; import "../../../i18n"; vi.mock("../../../lib/api", () => ({ api: { lanes: { cloneProgress: vi.fn() } }, })); import { api, type CloneProgressView } from "../../../lib/api"; import { CloneProgress, newCloneToken } from "../CloneProgress"; const base: CloneProgressView = { state: "running", position: null, running: 2, waiting: 1, limit: 2, phase: null, label: null, percent: null, detail: null, }; describe("CloneProgress", () => { // Braces: a function returned from beforeEach is run as its teardown. beforeEach(() => { vi.mocked(api.lanes.cloneProgress).mockReset(); }); it("shows the clone's place in the queue while it waits", async () => { vi.mocked(api.lanes.cloneProgress).mockResolvedValue({ ...base, state: "queued", position: 1, }); render(); expect(await screen.findByTestId("clone-progress")).toHaveTextContent( "Waiting in the clone queue — #1 of 1 (2/2 clones running)" ); }); it("shows git's phase, percent and speed with a bar while it runs", async () => { vi.mocked(api.lanes.cloneProgress).mockResolvedValue({ ...base, phase: "receiving", label: "Receiving objects", percent: 45, detail: "450/1000, 120.50 MiB | 5.20 MiB/s", }); render(); const line = await screen.findByTestId("clone-progress"); expect(line).toHaveTextContent("Downloading 45%"); expect(line).toHaveTextContent("120.50 MiB | 5.20 MiB/s"); expect(screen.getByRole("progressbar")).toHaveAttribute("aria-valuenow", "45"); }); it("shows nothing while the server does not know the token yet", async () => { vi.mocked(api.lanes.cloneProgress).mockImplementation(() => Promise.reject(Object.assign(new Error("no such clone"), { code: "ENOTFOUND" })) ); render(); await new Promise((r) => setTimeout(r, 20)); expect(screen.queryByTestId("clone-progress")).toBeNull(); }); it("makes tokens the server accepts", () => { const a = newCloneToken(); expect(a).toMatch(/^[A-Za-z0-9_-]{16,64}$/); expect(newCloneToken()).not.toBe(a); }); });