Plex player: a finger's tap on the picture only shows or hides the controls, the hide timer starts with playback, a double-tap on a side third skips 10 s, the seek bar is a 2.75rem touch-none hit area with its head shown on touch. The row is play/pause, Back by position, Next only with a next item, mute, time, tracks, a fixed ⋯ (settings, media info, stats, shortcuts, download) and fullscreen; Stop, Restart and the ±10 s buttons are gone. A started card shows the video card's Continue + Restart pair (one shared MediaResumeButtons, beside the picture's button), and its menu lists the restart; the player opens that item at 0 (fromStart). YouTube modal: the description opens from an ⓘ, the queue arrows sit inside the screen.
64 lines
2.4 KiB
TypeScript
64 lines
2.4 KiB
TypeScript
// @vitest-environment jsdom
|
|
//
|
|
// The control bar must not hide while the pointer rests on it. It used to: the 3 s timer only knew
|
|
// "paused" and "a menu is open", so with the mouse parked on the row (about to press Next) the bar
|
|
// faded out from under it (E28 audit F22). YouTube and Plex Web both hold the bar while hovered.
|
|
import { describe, it, expect, vi, afterEach, beforeEach } from "vitest";
|
|
import { act, renderHook } from "@testing-library/react";
|
|
import { useControlsVisibility } from "./plexPlayerHooks";
|
|
|
|
const setup = (menuOpen = false) => {
|
|
const video = document.createElement("video");
|
|
Object.defineProperty(video, "paused", { configurable: true, value: false });
|
|
return renderHook(() =>
|
|
useControlsVisibility({
|
|
barAutoHideRef: { current: true },
|
|
menuOpenRef: { current: menuOpen },
|
|
videoRef: { current: video },
|
|
}),
|
|
);
|
|
};
|
|
|
|
describe("useControlsVisibility", () => {
|
|
beforeEach(() => vi.useFakeTimers());
|
|
afterEach(() => vi.useRealTimers());
|
|
|
|
it("hides 3 s after the last activity while playing", () => {
|
|
const { result } = setup();
|
|
act(() => result.current.wake());
|
|
act(() => vi.advanceTimersByTime(3000));
|
|
expect(result.current.uiVisible).toBe(false);
|
|
});
|
|
|
|
it("stays up while the pointer is over the bar, and re-arms the timer when it leaves", () => {
|
|
const { result } = setup();
|
|
act(() => {
|
|
result.current.wake();
|
|
result.current.holdOnHover(true);
|
|
});
|
|
act(() => vi.advanceTimersByTime(10_000));
|
|
expect(result.current.uiVisible).toBe(true);
|
|
|
|
act(() => result.current.holdOnHover(false));
|
|
act(() => vi.advanceTimersByTime(2900));
|
|
expect(result.current.uiVisible).toBe(true); // a fresh 3 s from the leave, not from the wake
|
|
act(() => vi.advanceTimersByTime(100));
|
|
expect(result.current.uiVisible).toBe(false);
|
|
});
|
|
|
|
// C3: on touch nothing moves a mouse, so a tap toggles the bar and playback arms the timer.
|
|
it("toggle hides a shown bar at once and shows a hidden one", () => {
|
|
const { result } = setup();
|
|
act(() => result.current.toggle());
|
|
expect(result.current.uiVisible).toBe(false);
|
|
act(() => result.current.toggle());
|
|
expect(result.current.uiVisible).toBe(true);
|
|
});
|
|
|
|
it("a tap does not hide the bar under an open menu", () => {
|
|
const { result } = setup(true);
|
|
act(() => result.current.toggle());
|
|
expect(result.current.uiVisible).toBe(true);
|
|
});
|
|
});
|