- Share: a link that expired is never copied (the dialog and one-click Share pick a live one, else make one), says it expired, and the copy-on-open claim clears on the next copy. - A password-protected file link asks to open a file, not to watch a video. - Upload: Cancel, the close button or the backdrop while naming a folder makes no folder; a failed refetch keeps the target; a folder being made says so. - Crop: an infinite number is dropped, not a 500; an unprobed clip's size follows a shown-size crop; the edit_spec docs name frame_w/frame_h; the join and rotated paths are tested. - Auto-skip: the wait gives way on a marker too short for it, so the skip still fires. - Tag chips count the followed channels (subscribed_count) and a toggled chip keeps the focus. - Continue watching's See all sorts by last watched when in progress was already on.
61 lines
2.3 KiB
TypeScript
61 lines
2.3 KiB
TypeScript
// @vitest-environment jsdom
|
|
//
|
|
// A crop's numbers count the picture as the browser reports it, its shown size, which differs from the
|
|
// file's own on a video with wide pixels. The size goes along, or the server cuts the wrong part.
|
|
import { describe, it, expect, vi, beforeAll, afterEach } from "vitest";
|
|
import { render, screen, fireEvent, waitFor, cleanup } from "@testing-library/react";
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
|
|
vi.mock("react-i18next", async (importOriginal) => ({
|
|
...(await importOriginal<typeof import("react-i18next")>()),
|
|
useTranslation: () => ({ t: (key: string) => key, i18n: { language: "en" } }),
|
|
}));
|
|
|
|
import VideoEditor from "./VideoEditor";
|
|
import { api, type DownloadJob } from "../../lib/api";
|
|
|
|
beforeAll(() => {
|
|
class Stub {
|
|
observe() {}
|
|
unobserve() {}
|
|
disconnect() {}
|
|
takeRecords() {
|
|
return [];
|
|
}
|
|
}
|
|
globalThis.ResizeObserver ??= Stub as unknown as typeof ResizeObserver;
|
|
globalThis.IntersectionObserver ??= Stub as unknown as typeof IntersectionObserver;
|
|
});
|
|
afterEach(() => {
|
|
cleanup();
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
// Wide pixels: stored 960 across, shown 1920 — the browser reports the shown size, the asset the
|
|
// stored one, and the two must not be mistaken for each other.
|
|
const job = {
|
|
id: 7,
|
|
display_name: "Talk",
|
|
asset: { duration_s: 100, width: 960, height: 1080, title: "Talk" },
|
|
} as unknown as DownloadJob;
|
|
|
|
describe("VideoEditor crop", () => {
|
|
it("sends the size the crop was measured on with it", async () => {
|
|
vi.spyOn(HTMLVideoElement.prototype, "videoWidth", "get").mockReturnValue(1920);
|
|
vi.spyOn(HTMLVideoElement.prototype, "videoHeight", "get").mockReturnValue(1080);
|
|
const enqueue = vi
|
|
.spyOn(api, "enqueueEdit")
|
|
.mockResolvedValue({ id: 8 } as unknown as DownloadJob);
|
|
render(
|
|
<QueryClientProvider client={new QueryClient()}>
|
|
<VideoEditor job={job} onClose={() => {}} />
|
|
</QueryClientProvider>,
|
|
);
|
|
fireEvent.click(screen.getByRole("button", { name: "editor.cropOff" }));
|
|
fireEvent.click(screen.getByRole("button", { name: "editor.create" }));
|
|
await waitFor(() => expect(enqueue).toHaveBeenCalledTimes(1));
|
|
const crop = enqueue.mock.calls[0]?.[0].edit_spec.crop;
|
|
expect(crop).toMatchObject({ frame_w: 1920, frame_h: 1080, w: 1536, h: 864 });
|
|
});
|
|
});
|