fix(nav): Back finds an item that moved to another list by its name
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
// @vitest-environment jsdom
|
||||
//
|
||||
// Back to a page whose item changed lists while it was away. The notification center holds a row
|
||||
// that asked for the reader in "Needs you" for the visit; on the next visit the same row, read now,
|
||||
// sits in the stream below. The restore matched the unnamed list by its place, missed the name there
|
||||
// and fell back to the saved index — the focus landed on the neighbour, and Enter opened the wrong
|
||||
// notification. Its own file: listNav keeps module-level state.
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { act, cleanup, render } from "@testing-library/react";
|
||||
import { useRef } from "react";
|
||||
|
||||
import { navItemAttrs, navPosition, restoreNavPosition, useListNav } from "./listNav";
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
function List({ items }: { items: string[] }) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
useListNav(ref, { enabled: true });
|
||||
return (
|
||||
<div ref={ref}>
|
||||
{items.map((t, i) => (
|
||||
<div key={`${t}-${i}`} {...navItemAttrs(i, t)}>
|
||||
<button data-nav-open="">{t}</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const Page = ({ lists }: { lists: string[][] }) => (
|
||||
<main>
|
||||
{lists.map((items, i) => (
|
||||
<List key={i} items={items} />
|
||||
))}
|
||||
</main>
|
||||
);
|
||||
|
||||
const button = (name: string) =>
|
||||
[...document.querySelectorAll("button")].find((b) => b.textContent === name)!;
|
||||
const focused = () => document.activeElement?.closest("[data-nav-index]")?.textContent;
|
||||
const wait = (ms: number) => act(() => new Promise((r) => setTimeout(r, ms)));
|
||||
|
||||
async function leaveAndReturn(before: string[][], from: string, after: string[][]) {
|
||||
const { unmount } = render(<Page lists={before} />);
|
||||
button(from).focus();
|
||||
const pos = navPosition()!;
|
||||
unmount(); // the page switch
|
||||
render(<Page lists={after} />); // Back
|
||||
const cancel = restoreNavPosition(pos);
|
||||
await wait(120);
|
||||
cancel();
|
||||
}
|
||||
|
||||
describe("Back to an item that moved to another list", () => {
|
||||
it("finds it by its name in the list it moved to, not its neighbour at the old place", async () => {
|
||||
await leaveAndReturn([["subscribed", "download"], ["older"]], "subscribed", [
|
||||
["download"],
|
||||
["subscribed", "older"],
|
||||
]);
|
||||
expect(focused()).toBe("subscribed");
|
||||
});
|
||||
|
||||
it("finds it when the list it left is gone altogether", async () => {
|
||||
await leaveAndReturn([["subscribed"], ["older"]], "subscribed", [["subscribed", "older"]]);
|
||||
expect(focused()).toBe("subscribed");
|
||||
});
|
||||
|
||||
it("does not guess between two items of that name elsewhere: the saved place", async () => {
|
||||
await leaveAndReturn([["twin", "download"], ["older"]], "twin", [
|
||||
["download"],
|
||||
["twin", "older", "twin"],
|
||||
]);
|
||||
expect(focused()).toBe("download");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user