import React from "react"; import { vi } from "vitest"; import { screen } from "@testing-library/react"; import { NavigateToResource } from "./navigate-to-resource"; import { render, TestWrapper, type ITestWrapperProps } from "./test/index"; import { mockRouterProvider } from "./test/dataMocks"; // Mock Navigate component to capture navigation vi.mock("react-router", async () => { const actual = await vi.importActual("react-router"); return { ...actual, Navigate: ({ to }: { to: string }) => (
{to}
), }; }); const renderNavigateToResource = ( props: React.ComponentProps = {}, wrapperProps: ITestWrapperProps = {}, ) => { return render(, { wrapper: TestWrapper(wrapperProps), }); }; describe("NavigateToResource", () => { it("should navigate to the first resource with list action", async () => { renderNavigateToResource( {}, { resources: [ { name: "posts", list: "/posts" }, { name: "categories", list: "/categories" }, ], routerProvider: mockRouterProvider({ fns: { go: () => { return ({ to, type }) => { if (type === "path") return to; return undefined; }; }, }, }), }, ); expect(screen.getByTestId("navigate-to").textContent).toBe("/posts"); }); it("should navigate to the specified resource", async () => { renderNavigateToResource( { resource: "categories" }, { resources: [ { name: "posts", list: "/posts" }, { name: "categories", list: "/categories" }, ], routerProvider: mockRouterProvider({ fns: { go: () => { return ({ to, type }) => { if (type === "path") return to; return undefined; }; }, }, }), }, ); expect(screen.getByTestId("navigate-to").textContent).toBe("/categories"); }); it("should navigate to fallbackTo when no resource is found", async () => { const consoleWarnSpy = vi .spyOn(console, "warn") .mockImplementation(() => {}); renderNavigateToResource( { fallbackTo: "/dashboard" }, { resources: [], routerProvider: mockRouterProvider({ fns: { go: () => { return ({ to, type }) => { if (type === "path") return to; return undefined; }; }, }, }), }, ); expect(consoleWarnSpy).toHaveBeenCalledWith( "No resource is found. navigation to /dashboard.", ); expect(screen.getByTestId("navigate-to").textContent).toBe("/dashboard"); consoleWarnSpy.mockRestore(); }); it("should not navigate when no resource and no fallbackTo is provided", async () => { const consoleWarnSpy = vi .spyOn(console, "warn") .mockImplementation(() => {}); renderNavigateToResource( {}, { resources: [], routerProvider: mockRouterProvider({ fns: { go: () => { return ({ to, type }) => { if (type === "path") return to; return undefined; }; }, }, }), }, ); expect(consoleWarnSpy).toHaveBeenCalledWith( 'No resource and "fallbackTo" is found. No navigation will be made.', ); expect(screen.queryByTestId("navigate-to")).toBeNull(); consoleWarnSpy.mockRestore(); }); it("should pass meta to getToPath", async () => { const meta = { foo: "bar" }; renderNavigateToResource( { resource: "posts", meta }, { resources: [{ name: "posts", list: "/posts" }], routerProvider: mockRouterProvider({ fns: { go: () => { return ({ to, type }) => { if (type === "path") return to; return undefined; }; }, }, }), }, ); expect(screen.getByTestId("navigate-to").textContent).toBe("/posts"); }); it("should prefer specified resource over first resource with list", async () => { renderNavigateToResource( { resource: "categories" }, { resources: [ { name: "posts", list: "/posts" }, { name: "categories", list: "/categories" }, ], routerProvider: mockRouterProvider({ fns: { go: () => { return ({ to, type }) => { if (type === "path") return to; return undefined; }; }, }, }), }, ); expect(screen.getByTestId("navigate-to").textContent).toBe("/categories"); }); it("should return null when resource exists but path is not available", async () => { renderNavigateToResource( { resource: "posts" }, { resources: [{ name: "posts" }], routerProvider: mockRouterProvider({ fns: { go: () => { return ({ to, type }) => { if (type === "path") return undefined; return undefined; }; }, }, }), }, ); expect(screen.queryByTestId("navigate-to")).toBeNull(); }); });