test(channels): cover ActionMenu keyboard-skip + stats ETA value; drop redundant disabledIndices

Deep-review follow-up on R13 S3.

- Add a roving-keyboard-nav test proving a disabled ActionMenu item is
  skipped by arrow keys, and assert the stats "left" row renders the
  formatEta value (formatEta had no coverage anywhere).
- Remove the disabledIndices plumbing from AnchoredPopover + ActionMenu:
  it was redundant. useListNavigation already skips items via their DOM
  disabled/aria-disabled attribute, and PopoverItem renders a native
  disabled button — verified against @floating-ui/react 0.27
  isListIndexDisabled and by a mutation test. Behaviour is unchanged and
  now guarded by the new test.
This commit is contained in:
2026-08-15 04:45:32 +02:00
parent bb2d6999fd
commit 5838cf1c56
4 changed files with 53 additions and 15 deletions
@@ -19,6 +19,7 @@ vi.mock("react-i18next", async (importOriginal) => {
import ChannelStatsPopover from "./ChannelStatsPopover";
import { type MyStatus } from "../lib/api";
import { formatEta } from "../lib/format";
beforeAll(() => {
class Stub {
@@ -76,12 +77,17 @@ describe("ChannelStatsPopover", () => {
expect(screen.getByText((1234).toLocaleString())).toBeTruthy(); // my_videos, locale-agnostic
});
it("shows the 'left' ETA row only while a backfill is pending", () => {
it("shows the 'left' ETA row only while a backfill is pending, with the formatted ETA value", () => {
open(status({ deep_pending_count: 0 }));
expect(screen.queryByText("channels.stats.left")).toBeNull();
cleanup();
open(status({ deep_pending_count: 2 }));
open(status({ deep_pending_count: 2, deep_eta_seconds: 120 }));
expect(screen.getByText("channels.stats.left")).toBeTruthy();
// The value is the FORMATTED ETA (via formatEta), not raw seconds — asserting it guards the
// formatEta wiring, which is untested anywhere else. Using the same formatEta keeps this
// locale/impl-agnostic (expected === what the component renders).
expect(screen.getByText(formatEta(120))).toBeTruthy();
expect(screen.queryByText("120")).toBeNull(); // never the raw seconds
});
it("keeps each stat's explanation as a per-row title (hint not lost)", () => {