import React from "react"
import { beforeEach, describe, expect, test, vi } from "vitest"
import { cleanup, render, waitFor } from "@testing-library/react"
import SidebarProvider from "../sidebar"
import { Sidebar } from "types"
// Mock functions
const mockIsLoading = vi.fn(() => false)
const mockSetIsLoading = vi.fn()
const mockUsePageLoading = vi.fn(() => ({
isLoading: mockIsLoading(),
setIsLoading: mockSetIsLoading,
}))
const mockScrollableElement = vi.fn(() => null as HTMLElement | null)
const mockUseScrollController = vi.fn(() => ({
scrollableElement: mockScrollableElement(),
}))
const mockPathname = vi.fn(() => "/store/test")
const mockUsePathname = vi.fn(() => mockPathname())
const mockStoreSidebar: Sidebar.Sidebar = {
sidebar_id: "store-sidebar",
title: "Store Sidebar",
items: [],
}
const mockAdminSidebar: Sidebar.Sidebar = {
sidebar_id: "admin-sidebar",
title: "Admin Sidebar",
items: [],
}
vi.mock("docs-ui", () => ({
SidebarProvider: ({
children,
isLoading,
setIsLoading,
shouldHandleHashChange,
shouldHandlePathChange,
scrollableElement,
sidebars,
persistCategoryState,
disableActiveTransition,
isSidebarStatic,
}: {
children: React.ReactNode
isLoading: boolean
setIsLoading: (value: boolean) => void
shouldHandleHashChange: boolean
shouldHandlePathChange: boolean
scrollableElement: HTMLElement | null
sidebars: Sidebar.Sidebar[]
persistCategoryState: boolean
disableActiveTransition: boolean
isSidebarStatic: boolean
}) => (
{children}
),
usePageLoading: () => mockUsePageLoading(),
useScrollController: () => mockUseScrollController(),
}))
vi.mock("next/navigation", () => ({
usePathname: () => mockUsePathname(),
}))
vi.mock("@/config", () => ({
config: {
sidebars: [{
sidebar_id: "store-sidebar",
title: "Store Sidebar",
items: [],
}],
},
}))
// Mock dynamic imports
vi.mock("@/generated/generated-store-sidebar.mjs", () => ({
default: mockStoreSidebar,
}))
vi.mock("@/generated/generated-admin-sidebar.mjs", () => ({
default: mockAdminSidebar,
}))
describe("SidebarProvider", () => {
beforeEach(() => {
vi.clearAllMocks()
cleanup()
mockIsLoading.mockReturnValue(false)
mockScrollableElement.mockReturnValue(null)
mockPathname.mockReturnValue("/store/test")
})
describe("rendering", () => {
test("renders children", () => {
const { getByText } = render(
Test Content
)
expect(getByText("Test Content")).toBeInTheDocument()
})
test("renders UiSidebarProvider with correct props", async () => {
const { getByTestId } = render(
Test
)
await waitFor(() => {
const uiProvider = getByTestId("ui-sidebar-provider")
expect(uiProvider).toBeInTheDocument()
expect(uiProvider.getAttribute("data-is-loading")).toBe("false")
expect(uiProvider.getAttribute("data-should-handle-hash-change")).toBe("true")
expect(uiProvider.getAttribute("data-should-handle-path-change")).toBe("false")
expect(uiProvider.getAttribute("data-persist-category-state")).toBe("false")
expect(uiProvider.getAttribute("data-disable-active-transition")).toBe("false")
expect(uiProvider.getAttribute("data-is-sidebar-static")).toBe("false")
})
})
})
describe("sidebar loading", () => {
test("loads store sidebar when path starts with /store", async () => {
mockPathname.mockReturnValue("/store/test")
const { getByTestId } = render(
Test
)
await waitFor(() => {
const uiProvider = getByTestId("ui-sidebar-provider")
const sidebars = JSON.parse(uiProvider.getAttribute("data-sidebars") || "[]")
expect(sidebars).toEqual([mockStoreSidebar])
})
})
test("loads admin sidebar when path does not start with /store", async () => {
mockPathname.mockReturnValue("/admin/test")
const { getByTestId } = render(
Test
)
await waitFor(() => {
const uiProvider = getByTestId("ui-sidebar-provider")
const sidebars = JSON.parse(uiProvider.getAttribute("data-sidebars") || "[]")
expect(sidebars).toEqual([mockAdminSidebar])
})
})
test("uses config sidebars as fallback when sidebar is not loaded", () => {
const { getByTestId } = render(
Test
)
// Initially should use config sidebars
const uiProvider = getByTestId("ui-sidebar-provider")
const sidebars = JSON.parse(uiProvider.getAttribute("data-sidebars") || "[]")
expect(sidebars).toEqual([mockStoreSidebar])
})
})
describe("props passing", () => {
test("passes isLoading and setIsLoading to UiSidebarProvider", async () => {
mockIsLoading.mockReturnValue(true)
const { getByTestId } = render(
Test
)
await waitFor(() => {
const uiProvider = getByTestId("ui-sidebar-provider")
expect(uiProvider.getAttribute("data-is-loading")).toBe("true")
})
})
test("passes scrollableElement to UiSidebarProvider", async () => {
const mockElement = document.createElement("div")
mockScrollableElement.mockReturnValue(mockElement)
const { getByTestId } = render(
Test
)
await waitFor(() => {
const uiProvider = getByTestId("ui-sidebar-provider")
expect(uiProvider.getAttribute("data-scrollable-element")).toBe("present")
})
})
})
describe("error handling", () => {
test("handles sidebar loading errors gracefully", async () => {
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {})
// Mock a failing import
vi.doMock("../generated/generated-store-sidebar.mjs", () => {
throw new Error("Failed to load sidebar")
})
const { getByTestId } = render(
Test
)
await waitFor(() => {
const uiProvider = getByTestId("ui-sidebar-provider")
expect(uiProvider).toBeInTheDocument()
})
consoleSpy.mockRestore()
})
})
})