import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { portfolio } from "@/lib/portfolio-data"; import NotebookBrowser, { type NotebookBrowserProps } from "./NotebookBrowser"; import { selectNotebookProjects } from "./notebookProjects"; const projects = selectNotebookProjects(portfolio.projects); const frame: NotebookBrowserProps["frame"] = { cursorVisible: true, cursorX: 0.4, cursorY: 0.6, cursorClicking: false, }; function renderBrowser(overrides: Partial = {}) { return render( , ); } describe("NotebookBrowser", () => { it("renders the active project as an accessible tabpanel", () => { renderBrowser({ activeIndex: 1 }); expect( screen.getByRole("tablist", { name: /projetos em produção/i }), ).toBeInTheDocument(); expect(screen.getAllByRole("tab")[1]).toHaveAttribute( "aria-selected", "true", ); expect(screen.getByRole("tabpanel")).toHaveAccessibleName( /SC Plus Aquicultura/i, ); expect(screen.getByRole("status")).toHaveTextContent( "Projeto ativo: SC Plus Aquicultura", ); }); it("preloads the next screenshot and keeps a short outgoing crossfade", () => { const view = renderBrowser(); expect( view.container.querySelector(".notebook-screenshot-preload"), ).toBeInTheDocument(); view.rerender( , ); expect( view.container.querySelector(".notebook-screenshot-outgoing"), ).toBeInTheDocument(); }); it("moves between tabs with arrow keys and Home/End", async () => { const user = userEvent.setup(); const onSelectTab = jest.fn(); renderBrowser({ onSelectTab }); const tabs = screen.getAllByRole("tab"); await user.click(tabs[1]); await user.keyboard("{ArrowRight}"); await user.keyboard("{Home}"); await user.keyboard("{End}"); expect(onSelectTab).toHaveBeenNthCalledWith(1, 1); expect(onSelectTab).toHaveBeenNthCalledWith(2, 2); expect(onSelectTab).toHaveBeenNthCalledWith(3, 0); expect(onSelectTab).toHaveBeenNthCalledWith(4, projects.length - 1); }); it("moves DOM focus with the active tab", async () => { const user = userEvent.setup(); const tabs = renderBrowser().container.querySelectorAll( '[role="tab"]', ); tabs[0].focus(); await user.keyboard("{ArrowRight}"); expect(document.activeElement).toBe(tabs[1]); }); it("removes the closed browser from the accessibility tree", () => { renderBrowser({ interactive: false }); const browser = screen.getByTestId("notebook-browser"); expect(browser).toHaveAttribute("aria-hidden", "true"); expect(browser).toHaveAttribute("inert"); }); it("bounds arrow navigation at the first and last tab", async () => { const user = userEvent.setup(); const onSelectTab = jest.fn(); renderBrowser({ onSelectTab }); const tabs = screen.getAllByRole("tab"); await user.click(tabs[0]); await user.keyboard("{ArrowLeft}"); await user.click(tabs.at(-1) as HTMLElement); await user.keyboard("{ArrowRight}"); expect(onSelectTab).toHaveBeenNthCalledWith(2, 0); expect(onSelectTab).toHaveBeenNthCalledWith(4, projects.length - 1); }); it("exposes a real deployment link with safe new-tab attributes", () => { renderBrowser(); const link = screen.getByRole("link", { name: /abrir projeto/i }); expect(link).toHaveAttribute("href", projects[0].demoUrl); expect(link).toHaveAttribute("target", "_blank"); expect(link).toHaveAttribute("rel", "noopener noreferrer"); }); it("keeps the animated cursor decorative and never embeds an iframe", () => { const { container } = renderBrowser({ frame: { ...frame, cursorClicking: true }, }); expect(container.querySelector(".notebook-cursor")).toHaveAttribute( "aria-hidden", "true", ); expect(container.querySelector(".notebook-cursor")).toHaveStyle({ left: "40%", top: "60%", }); expect(container.querySelector("iframe")).not.toBeInTheDocument(); }); it("uses the selected tab to label the panel and screenshot", () => { renderBrowser({ activeIndex: 2 }); const tab = screen.getAllByRole("tab")[2]; const panel = screen.getByRole("tabpanel"); const image = screen.getByRole("img"); expect(tab).toHaveAttribute("aria-controls", panel.id); expect(panel).toHaveAttribute("aria-labelledby", tab.id); expect(image).toHaveAccessibleName(/SEV Moda Íntima/i); expect(image).toHaveAttribute("src", "/assets/prints/print-sev.png"); }); });