fix(notifications): "Find in feed" drops every narrowing that could hide the video
locate() spread the reader's filters and cleared only the tag, search and age cap, so a year, a custom range, a length, a content type (a hidden Short under "no Shorts") or the scope could still leave the video out. It builds the filters from nothing now, keeping only the sort and tag modes. (Also types the C1 test's pending plan.)
This commit is contained in:
@@ -46,7 +46,28 @@ vi.mock("../lib/notifications", async (importOriginal) => ({
|
||||
vi.mock("./navigationContext", () => ({ useNavigationActions: () => ({ setPage: h.setPage }) }));
|
||||
vi.mock("./channelsContext", () => ({ useChannelsActions: () => ({ focusChannel: vi.fn() }) }));
|
||||
vi.mock("./feedFiltersContext", () => ({
|
||||
useFeedFilters: () => ({ tags: [54], untagged: true, q: "rust", maxAgeDays: 30, sort: "newest" }),
|
||||
// Every narrowing a feed can carry (E28 review C2: the year, the custom range, the length, the
|
||||
// content types and the scope survived "Find in feed" and could still hide the video).
|
||||
useFeedFilters: () => ({
|
||||
tags: [54],
|
||||
tagModes: { language: "and", topic: "or", other: "or" },
|
||||
untagged: true,
|
||||
q: "rust",
|
||||
maxAgeDays: 30,
|
||||
dateFrom: "2024-01-01",
|
||||
dateTo: "2024-02-01",
|
||||
year: 2024,
|
||||
minDuration: 60,
|
||||
maxDuration: 600,
|
||||
includeNormal: true,
|
||||
includeShorts: false,
|
||||
includeLive: false,
|
||||
scope: "my",
|
||||
librarySource: "organic",
|
||||
sort: "oldest",
|
||||
show: "unwatched",
|
||||
channelIds: ["x"],
|
||||
}),
|
||||
useFeedFiltersActions: () => ({ setFilters: h.setFilters }),
|
||||
}));
|
||||
vi.mock("./ui/PageShell", async (importOriginal) => ({
|
||||
@@ -223,12 +244,18 @@ describe("NotificationsPanel · an activity row", () => {
|
||||
await openMenu(() => fireEvent.contextMenu(rowOf("Activity 9")));
|
||||
choose("notifications.findInFeed");
|
||||
await waitFor(() => expect(h.setFilters).toHaveBeenCalled());
|
||||
// Nothing but the state and the channel narrows; the reader's sort and tag modes stay theirs.
|
||||
expect(h.setFilters).toHaveBeenCalledWith({
|
||||
tags: [],
|
||||
tagModes: { language: "and", topic: "or", other: "or" },
|
||||
untagged: false,
|
||||
q: "",
|
||||
maxAgeDays: undefined,
|
||||
sort: "newest",
|
||||
includeNormal: true,
|
||||
includeShorts: true,
|
||||
includeLive: true,
|
||||
scope: "all",
|
||||
librarySource: "all",
|
||||
sort: "oldest",
|
||||
show: "watched",
|
||||
channelIds: ["c"],
|
||||
});
|
||||
|
||||
@@ -142,15 +142,22 @@ export default function NotificationsPanel() {
|
||||
|
||||
// "Find in feed" / undo, ported from the old bell. Works for both hidden and watched
|
||||
// notices — jump to the feed filtered to that state and the video's channel.
|
||||
// The narrowing filters that could leave the video out (a tag, "no tag", a search, an age cap) are
|
||||
// dropped: kept, a channel outside the reader's tag filter found an empty feed.
|
||||
// Built from nothing, not spread over the reader's filters: EVERY narrowing that could leave the
|
||||
// video out goes — a tag, "no tag", a search, the age cap, the year, the custom range, the length,
|
||||
// a content type (a hidden Short under "no Shorts"), the scope and the library source (E28 review
|
||||
// C2: the spread kept whatever this list forgot). Only how the reader orders and matches stays.
|
||||
function locate(meta: VideoHiddenMeta | VideoWatchedMeta) {
|
||||
setFilters({
|
||||
...filters,
|
||||
tags: [],
|
||||
tagModes: filters.tagModes,
|
||||
untagged: false,
|
||||
q: "",
|
||||
maxAgeDays: undefined,
|
||||
includeNormal: true,
|
||||
includeShorts: true,
|
||||
includeLive: true,
|
||||
scope: "all",
|
||||
librarySource: "all",
|
||||
sort: filters.sort,
|
||||
show: meta.kind === "video-hidden" ? "hidden" : "watched",
|
||||
channelIds: meta.channelId ? [meta.channelId] : [],
|
||||
});
|
||||
|
||||
@@ -161,10 +161,9 @@ describe("usePlaylistActions — a playlist's menu", () => {
|
||||
// offering a second push of the same list.
|
||||
describe("usePlaylistActions — one push at a time, across menus", () => {
|
||||
it("a push started from one menu is off in the other until it ends", async () => {
|
||||
let finish: (v: unknown) => void = () => {};
|
||||
vi.spyOn(api, "playlistPushPlan").mockReturnValue(
|
||||
new Promise((r) => (finish = r)) as ReturnType<typeof api.playlistPushPlan>,
|
||||
);
|
||||
type Plan = Awaited<ReturnType<typeof api.playlistPushPlan>>;
|
||||
let finish: (v: Plan) => void = () => {};
|
||||
vi.spyOn(api, "playlistPushPlan").mockReturnValue(new Promise<Plan>((r) => (finish = r)));
|
||||
const rail = mount();
|
||||
const header = mount();
|
||||
const dirty = { ...linked, dirty: true };
|
||||
@@ -176,7 +175,7 @@ describe("usePlaylistActions — one push at a time, across menus", () => {
|
||||
await act(async () => push(header).onSelect!());
|
||||
expect(api.playlistPushPlan).toHaveBeenCalledTimes(1);
|
||||
await act(async () => {
|
||||
finish({ action: "update", affordable: true });
|
||||
finish({ action: "update", affordable: true } as Plan);
|
||||
});
|
||||
expect(push(header).disabled).toBeFalsy();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user