memos/web/tests/memo-tag-navigation.test.tsx
johnnyjoygh af008b2153 feat(web): scope Spaces by URL path instead of a remembered selection
The selected Space used to live in sessionStorage and ride along invisibly
with every collection route. It now lives in the URL: collection pages exist
both globally and beneath /spaces/:spaceUid, and the Space context derives
its scope from the current location.

- Add a Space route branch (Home, Explore, Calendar, Attachments) guarded by
  a SpaceRoute that shows loading, unavailable, and retry states.
- Resolve collection routes through one matchPath-based helper built from the
  route constants; build Space-scoped paths with buildCollectionPath.
- Fetch the route Space directly, seeded from the switcher list so pages are
  not held behind a second round-trip.
- Turn the Space switcher into plain links that preserve the current
  collection view and query.
- Drop the remembered-Space machinery: clearSelectedSpace/selectMemos,
  the compose-placement policy, routeSupportsCollectionScope, and the
  quick-find switchToAll flag are all implied by the URL now.
- Return from memo details to the full origin URL, including its Space.
- Add space.unavailable and space.back-to-memos strings; align the
  Azerbaijani catalog with English.
2026-09-07 09:29:50 +08:00

62 lines
1.8 KiB
TypeScript

import { fireEvent, render, screen } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { Tag } from "@/components/MemoContent/Tag";
const navigateTo = vi.hoisted(() => vi.fn());
const origin = vi.hoisted(() => ({ parentPage: "/" as string }));
vi.mock("@/hooks/useNavigateTo", () => ({
default: () => navigateTo,
}));
vi.mock("@/components/MemoView/MemoViewContext", () => ({
useMemoViewContext: () => origin,
}));
vi.mock("@/contexts/MemoFilterContext", async (importOriginal) => {
const actual = await importOriginal<typeof import("@/contexts/MemoFilterContext")>();
return {
...actual,
useMemoFilterContext: () => ({
getFiltersByFactor: () => [],
removeFilter: vi.fn(),
addFilter: vi.fn(),
}),
};
});
vi.mock("@/contexts/AuthContext", () => ({
useAuth: () => ({ userTagsSetting: undefined }),
}));
describe("Memo tag navigation", () => {
beforeEach(() => {
navigateTo.mockClear();
origin.parentPage = "/";
});
it("navigates directly to the global collection from a global detail", () => {
render(
<MemoryRouter initialEntries={["/memos/parent"]}>
<Tag data-tag="work">#work</Tag>
</MemoryRouter>,
);
fireEvent.click(screen.getByText("#work"));
expect(navigateTo).toHaveBeenCalledWith("/?filter=tagSearch%3Awork");
});
it("returns a Profile-origin tag to that profile's memo list", () => {
origin.parentPage = "/u/alice?view=map";
render(
<MemoryRouter initialEntries={["/memos/parent"]}>
<Tag data-tag="work">#work</Tag>
</MemoryRouter>,
);
fireEvent.click(screen.getByText("#work"));
expect(navigateTo).toHaveBeenCalledWith("/u/alice?filter=tagSearch%3Awork");
});
});