- Treat All as an unfiltered Space collection while preserving exact Space filters. - Keep global resources outside remembered Space context and preserve memo navigation origins. - Surface Space placement consistently across memo, attachment, and visibility UI.
143 lines
4.6 KiB
TypeScript
143 lines
4.6 KiB
TypeScript
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
import { createMemoryRouter, RouterProvider, useLocation } from "react-router-dom";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import QuickFindDialog from "@/components/AppSidebar/QuickFindDialog";
|
|
import { AppSidebarProvider, useAppSidebar } from "@/contexts/AppSidebarContext";
|
|
import { getSelectedSpaceStorageKey, SpaceProvider, useSpaceContext } from "@/contexts/SpaceContext";
|
|
|
|
const state = vi.hoisted(() => ({
|
|
currentUser: { name: "users/alice" } as { name: string } | undefined,
|
|
spaces: [{ name: "spaces/product", title: "Product", description: "" }],
|
|
filters: [] as Array<{ factor: "contentSearch"; value: string }>,
|
|
setFilters: vi.fn(),
|
|
setMemoView: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("@/contexts/MemoFilterContext", async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import("@/contexts/MemoFilterContext")>();
|
|
return {
|
|
...actual,
|
|
useMemoFilterContext: () => ({
|
|
filters: state.filters,
|
|
memoView: undefined,
|
|
setFilters: state.setFilters,
|
|
setMemoView: state.setMemoView,
|
|
}),
|
|
};
|
|
});
|
|
|
|
vi.mock("@/hooks/useCurrentUser", () => ({
|
|
default: () => state.currentUser,
|
|
}));
|
|
|
|
vi.mock("@/hooks/useSpaceQueries", () => ({
|
|
useSpaces: () => ({ data: state.spaces, isSuccess: true, isPending: false, isError: false }),
|
|
}));
|
|
|
|
vi.mock("@/hooks/useUserQueries", () => ({
|
|
useMemoViews: () => ({ data: [] }),
|
|
}));
|
|
|
|
vi.mock("@/utils/i18n", () => ({
|
|
useTranslate: () => (key: string) => key,
|
|
}));
|
|
|
|
const Harness = () => {
|
|
const location = useLocation();
|
|
const { setQuickFindOpen } = useAppSidebar();
|
|
const { collectionScope } = useSpaceContext();
|
|
|
|
return (
|
|
<>
|
|
<output data-testid="path">{`${location.pathname}${location.search}`}</output>
|
|
<output data-testid="scope">{collectionScope.kind === "space" ? collectionScope.name : collectionScope.kind}</output>
|
|
<button type="button" onClick={() => setQuickFindOpen(true)}>
|
|
Open Quick Find
|
|
</button>
|
|
<QuickFindDialog />
|
|
</>
|
|
);
|
|
};
|
|
|
|
describe("Quick Find navigation", () => {
|
|
beforeEach(() => {
|
|
sessionStorage.clear();
|
|
state.currentUser = { name: "users/alice" };
|
|
state.filters = [];
|
|
state.setFilters.mockClear();
|
|
state.setMemoView.mockClear();
|
|
});
|
|
|
|
it("switches to All in one history step so Back returns directly to Inbox", async () => {
|
|
const storageKey = getSelectedSpaceStorageKey("users/alice");
|
|
sessionStorage.setItem(storageKey, "spaces/product");
|
|
|
|
const router = createMemoryRouter(
|
|
[
|
|
{
|
|
path: "*",
|
|
element: (
|
|
<SpaceProvider>
|
|
<AppSidebarProvider>
|
|
<Harness />
|
|
</AppSidebarProvider>
|
|
</SpaceProvider>
|
|
),
|
|
},
|
|
],
|
|
{ initialEntries: ["/inbox"] },
|
|
);
|
|
render(<RouterProvider router={router} />);
|
|
|
|
expect(screen.getByTestId("scope")).toHaveTextContent("spaces/product");
|
|
fireEvent.click(screen.getByRole("button", { name: "Open Quick Find" }));
|
|
const input = await screen.findByRole("textbox");
|
|
fireEvent.change(input, { target: { value: "roadmap" } });
|
|
fireEvent.submit(input.closest("form")!);
|
|
|
|
await waitFor(() => expect(screen.getByTestId("path")).toHaveTextContent("/?filter=contentSearch:roadmap"));
|
|
expect(state.setFilters).toHaveBeenCalledWith([{ factor: "contentSearch", value: "roadmap" }]);
|
|
expect(screen.getByTestId("scope")).toHaveTextContent("all");
|
|
expect(sessionStorage.getItem(storageKey)).toBeNull();
|
|
|
|
await act(async () => {
|
|
await router.navigate(-1);
|
|
});
|
|
|
|
expect(screen.getByTestId("path")).toHaveTextContent("/inbox");
|
|
});
|
|
|
|
it("preserves an anonymous global page in history", async () => {
|
|
state.currentUser = undefined;
|
|
|
|
const router = createMemoryRouter(
|
|
[
|
|
{
|
|
path: "*",
|
|
element: (
|
|
<SpaceProvider>
|
|
<AppSidebarProvider>
|
|
<Harness />
|
|
</AppSidebarProvider>
|
|
</SpaceProvider>
|
|
),
|
|
},
|
|
],
|
|
{ initialEntries: ["/about"] },
|
|
);
|
|
render(<RouterProvider router={router} />);
|
|
|
|
fireEvent.click(screen.getByRole("button", { name: "Open Quick Find" }));
|
|
const input = await screen.findByRole("textbox");
|
|
fireEvent.change(input, { target: { value: "roadmap" } });
|
|
fireEvent.submit(input.closest("form")!);
|
|
|
|
await waitFor(() => expect(screen.getByTestId("path")).toHaveTextContent("/?filter=contentSearch:roadmap"));
|
|
|
|
await act(async () => {
|
|
await router.navigate(-1);
|
|
});
|
|
|
|
expect(screen.getByTestId("path")).toHaveTextContent("/about");
|
|
});
|
|
});
|