fix(player): related marks survive, Restart restarts, and refused pages offer nothing to click
- Every state and Watch-later write goes through features/video/videoWrites, which marks the never-refetched lists (related lists, live searches) once the server has it; a contract test holds it. The Notification Center's undo, the feed's reset and the Watch-later toggles skipped it before. - Confirmed marks are also kept apart (qk.videoMarks) and laid over the related rows: a Show more page landing later rebuilt them from the pages it read when it started, and dropped a mark made meanwhile. - Restart on a related video starts at 0 (the session's stored position won before), and on the one already playing it seeks. - The watched toggle remembers each video's mark: Back showed the opened video's launch-time state after a related one was marked. - The help sheet leaves out the player's keys while a layer above it has them waiting. - After a refusal a retry cannot answer, neither Show more (related) nor Load more (live search) is offered; a failed live-search page keeps the results already read and says why under them. - The related cap message counts requests, as the cap does.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
// @vitest-environment jsdom
|
||||
//
|
||||
// Each write reaches the lists that are never refetched once the server has it — and not before:
|
||||
// a refused write leaves them as they were.
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { api } from "../../lib/api";
|
||||
import { qk } from "../../lib/queryKeys";
|
||||
import { resetVideoState, writeVideoState, writeWatchLater } from "./videoWrites";
|
||||
|
||||
afterEach(() => vi.restoreAllMocks());
|
||||
|
||||
const marks = (qc: QueryClient) => qc.getQueryData(qk.videoMarks());
|
||||
|
||||
describe("videoWrites", () => {
|
||||
it("marks a state written", async () => {
|
||||
vi.spyOn(api, "setState").mockResolvedValue({ ok: true } as never);
|
||||
const qc = new QueryClient();
|
||||
await writeVideoState(qc, "X", "hidden");
|
||||
expect(marks(qc)).toEqual({ X: { status: "hidden" } });
|
||||
});
|
||||
|
||||
it("marks a reset as new, from the start", async () => {
|
||||
vi.spyOn(api, "clearState").mockResolvedValue({ ok: true } as never);
|
||||
const qc = new QueryClient();
|
||||
await resetVideoState(qc, "X");
|
||||
expect(marks(qc)).toEqual({ X: { status: "new", position_seconds: 0 } });
|
||||
});
|
||||
|
||||
it("marks a Watch-later save and its removal", async () => {
|
||||
vi.spyOn(api, "watchLaterAdd").mockResolvedValue({ ok: true } as never);
|
||||
vi.spyOn(api, "watchLaterRemove").mockResolvedValue({ ok: true } as never);
|
||||
const qc = new QueryClient();
|
||||
await writeWatchLater(qc, "X", true);
|
||||
expect(marks(qc)).toEqual({ X: { saved: true } });
|
||||
await writeWatchLater(qc, "X", false);
|
||||
expect(marks(qc)).toEqual({ X: { saved: false } });
|
||||
});
|
||||
|
||||
it("marks nothing the server refused", async () => {
|
||||
vi.spyOn(api, "setState").mockRejectedValue(new Error("offline"));
|
||||
const qc = new QueryClient();
|
||||
await expect(writeVideoState(qc, "X", "hidden")).rejects.toThrow("offline");
|
||||
expect(marks(qc)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user