mirror of
https://github.com/multica-ai/multica.git
synced 2026-08-12 19:06:06 +02:00
* fix(workspace): recover from stale workspace state * fix(workspace): apply review nits for recovery flow - no-access-page: navigate via nav.replace so a browser Back doesn't land the user back on NoAccessPage with the dead slug - no-access-page: refresh the stale cookie-clear comment — the recovery button no longer routes through `/`; the clear now guards other `/` entry points (manual nav, Back into `/`, fresh page load) - tab-store: drop the redundant `as string | undefined` cast (the Set value is already string | undefined under TS 5.9) - tab-store.test: cover the route-layout heal path (all stale groups dropped, then seed a fresh tab for a valid slug) and assert the dropped group's router is disposed Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: J <j@multica.ai> Co-authored-by: multica-agent <github@multica.ai>
96 lines
2.9 KiB
TypeScript
96 lines
2.9 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
import { render, screen, fireEvent } from "@testing-library/react";
|
|
import { I18nProvider } from "@multica/core/i18n/react";
|
|
import enCommon from "../locales/en/common.json";
|
|
import enWorkspace from "../locales/en/workspace.json";
|
|
import { NoAccessPage } from "./no-access-page";
|
|
|
|
const TEST_RESOURCES = {
|
|
en: { common: enCommon, workspace: enWorkspace },
|
|
};
|
|
|
|
const navigate = vi.fn();
|
|
const logout = vi.fn();
|
|
const mockWorkspaces = vi.hoisted(() => [{ slug: "valid-team" }]);
|
|
|
|
vi.mock("../navigation", () => ({
|
|
useNavigation: () => ({ push: navigate, replace: navigate }),
|
|
}));
|
|
|
|
vi.mock("../auth", () => ({
|
|
useLogout: () => logout,
|
|
}));
|
|
|
|
vi.mock("@multica/core/paths", async () => {
|
|
const actual =
|
|
await vi.importActual<typeof import("@multica/core/paths")>(
|
|
"@multica/core/paths",
|
|
);
|
|
return {
|
|
...actual,
|
|
useHasOnboarded: () => true,
|
|
};
|
|
});
|
|
|
|
vi.mock("@tanstack/react-query", () => ({
|
|
useQuery: () => ({ data: mockWorkspaces }),
|
|
}));
|
|
|
|
vi.mock("@multica/core/workspace/queries", () => ({
|
|
workspaceListOptions: () => ({ queryKey: ["workspaces", "list"] }),
|
|
}));
|
|
|
|
function I18nWrapper({ children }: { children: ReactNode }) {
|
|
return (
|
|
<I18nProvider locale="en" resources={TEST_RESOURCES}>
|
|
{children}
|
|
</I18nProvider>
|
|
);
|
|
}
|
|
|
|
function renderPage() {
|
|
return render(<NoAccessPage />, { wrapper: I18nWrapper });
|
|
}
|
|
|
|
describe("NoAccessPage", () => {
|
|
beforeEach(() => {
|
|
navigate.mockReset();
|
|
logout.mockReset();
|
|
});
|
|
|
|
it("renders generic message that doesn't leak existence", () => {
|
|
renderPage();
|
|
expect(
|
|
screen.getByText(/doesn't exist or you don't have access/i),
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it("navigates to the first accessible workspace on 'Go to my workspaces'", () => {
|
|
renderPage();
|
|
fireEvent.click(screen.getByRole("button", { name: /go to my workspaces/i }));
|
|
expect(navigate).toHaveBeenCalledWith("/valid-team/issues");
|
|
});
|
|
|
|
it("clears last_workspace_slug cookie on mount so the proxy stops looping us back", () => {
|
|
document.cookie = "last_workspace_slug=stale; path=/";
|
|
renderPage();
|
|
// Assert empty value, not just absence of "stale" — the proxy reads any
|
|
// truthy value as a redirect target, so a buggy clear that left e.g.
|
|
// `last_workspace_slug=other` would still trap users.
|
|
const value = document.cookie.match(/last_workspace_slug=([^;]*)/)?.[1];
|
|
expect(value ?? "").toBe("");
|
|
});
|
|
|
|
it("fully logs out on 'Sign in as a different user' instead of just navigating", () => {
|
|
renderPage();
|
|
fireEvent.click(
|
|
screen.getByRole("button", { name: /sign in as a different user/i }),
|
|
);
|
|
expect(logout).toHaveBeenCalledTimes(1);
|
|
// Should NOT just navigate to /login — that would leave the session
|
|
// cookie + auth state intact and AuthInitializer would re-auth.
|
|
expect(navigate).not.toHaveBeenCalledWith("/login");
|
|
});
|
|
});
|