- A press that begins while a field in the row is edited only ends the editing (rowOpen latches it at pointerdown); the card layout's row press is now tested. - A related video reset in the player forgets the session's stored position. - Removing the playing video passes over known-dead items and steps the way it went. - Prev/Next off only because of dead items stay focusable and say why (HU/EN). - The docked bar's scroller leaves room for focus rings. - A focus-opened About card is not closed by its own scroll into view. - EN "Clear watch progress" for the video reset, distinct from a page's "Reset view". - The signed-out title read goes to the page yt-dlp read; the retitle writes are conditional. - Tests: the cap of three errors, the bar's own Fullscreen, the group glyph, the backfill's reads.
81 lines
2.6 KiB
TypeScript
81 lines
2.6 KiB
TypeScript
// @vitest-environment jsdom
|
|
//
|
|
// The About cell's card opened the instant a pointer crossed the cell, so scrolling the table over
|
|
// a column of them popped card after card. It waits for the pointer to rest on the cell now, and a
|
|
// scroll puts an open one away — unless the keyboard's focus opened it, whose own scroll into view
|
|
// would put it away the moment it opened.
|
|
import { describe, it, expect, vi, afterEach, beforeEach } from "vitest";
|
|
import { render, screen, fireEvent, act, cleanup } from "@testing-library/react";
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
|
|
import AboutCell from "./AboutCell";
|
|
import { api } from "../../lib/api";
|
|
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
vi.spyOn(api, "channelDetail").mockReturnValue(new Promise(() => {}));
|
|
});
|
|
afterEach(() => {
|
|
cleanup();
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
function mount() {
|
|
const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
|
render(
|
|
<QueryClientProvider client={qc}>
|
|
<AboutCell text="An element of truth" channelId="UC1" />
|
|
</QueryClientProvider>,
|
|
);
|
|
return screen.getByText("An element of truth");
|
|
}
|
|
// Present in the DOM is enough: it paints once floating-ui has placed it, which a fake clock never lets happen.
|
|
const card = () => document.querySelector('[role="tooltip"]');
|
|
const wait = (ms: number) => act(() => vi.advanceTimersByTime(ms));
|
|
const enter = (el: HTMLElement) =>
|
|
act(() => {
|
|
fireEvent.pointerEnter(el);
|
|
fireEvent.mouseEnter(el);
|
|
fireEvent.mouseMove(el);
|
|
});
|
|
|
|
describe("AboutCell — the hover card", () => {
|
|
it("does not open for a pointer passing over the cell", async () => {
|
|
const cell = mount();
|
|
enter(cell);
|
|
await wait(300);
|
|
expect(card()).toBeNull();
|
|
fireEvent.mouseLeave(cell);
|
|
await wait(600);
|
|
expect(card()).toBeNull();
|
|
});
|
|
|
|
it("opens once the pointer rests on it", async () => {
|
|
const cell = mount();
|
|
enter(cell);
|
|
await wait(550);
|
|
expect(card()).not.toBeNull();
|
|
});
|
|
|
|
it("goes away when the table scrolls", async () => {
|
|
const cell = mount();
|
|
enter(cell);
|
|
await wait(550);
|
|
expect(card()).not.toBeNull();
|
|
act(() => void window.dispatchEvent(new Event("scroll")));
|
|
await wait(50);
|
|
expect(card()).toBeNull();
|
|
});
|
|
|
|
it("stays when the focus that opened it scrolls its cell into view", async () => {
|
|
const cell = mount();
|
|
act(() => cell.focus());
|
|
await wait(10);
|
|
expect(card()).not.toBeNull();
|
|
act(() => void window.dispatchEvent(new Event("scroll")));
|
|
await wait(50);
|
|
expect(card()).not.toBeNull();
|
|
});
|
|
});
|