diff --git a/__tests__/UI/Tabs.test.tsx b/__tests__/UI/Tabs.test.tsx new file mode 100644 index 00000000..b1f75dee --- /dev/null +++ b/__tests__/UI/Tabs.test.tsx @@ -0,0 +1,152 @@ +/** + * @jest-environment jsdom + */ + +import React from "react"; +import { render, screen, fireEvent } from "@testing-library/react"; +import Tabs from "../../src/components/UI/Tabs.component"; + +// Mock framer-motion to avoid issues with animations in tests +jest.mock("framer-motion", () => ({ + motion: { + div: "div", + button: "button", + }, + AnimatePresence: ({ children }: { children: React.ReactNode }) => ( + <>{children} + ), +})); + +const mockCVData = { + keyQualifications: ["Qualification 1", "Qualification 2"], + experience: [ + { + period: "2020-2022", + company: "Example Company", + role: "Software Developer", + description: "Worked on various projects", + }, + ], + education: [ + { + period: "2016-2020", + institution: "University of Example", + degree: "Bachelor in Computer Science", + description: "Studied various aspects of computer science", + }, + ], +}; + +const mockTabs = [ + { + id: "qualifications", + label: "Nøkkelkvalifikasjoner", + content: ( + + ), + expectedTexts: mockCVData.keyQualifications, + unexpectedTexts: ["Example Company", "University of Example"], + }, + { + id: "experience", + label: "Erfaring", + content: ( +
+ {mockCVData.experience.map((exp) => ( +
+

+ {exp.period} - {exp.company} +

+ {exp.role &&

{exp.role}

} +

{exp.description}

+
+ ))} +
+ ), + expectedTexts: [ + "2020-2022 - Example Company", + "Software Developer", + "Worked on various projects", + ], + unexpectedTexts: ["Qualification 1"], + }, + { + id: "education", + label: "Utdanning", + content: ( +
+ {mockCVData.education.map((edu) => ( +
+

+ {edu.period} - {edu.institution} +

+ {edu.degree &&

{edu.degree}

} +

{edu.description}

+
+ ))} +
+ ), + expectedTexts: [ + "2016-2020 - University of Example", + "Bachelor in Computer Science", + "Studied various aspects of computer science", + ], + unexpectedTexts: ["Qualification 1"], + }, +]; + +describe("Tabs", () => { + const renderTabs = () => render(); + + const expectTextsToBePresent = (texts: string[]) => { + texts.forEach((text) => { + expect(screen.getByText(text)).toBeInTheDocument(); + }); + }; + + const expectTextsNotToBePresent = (texts: string[]) => { + texts.forEach((text) => { + expect(screen.queryByText(text)).not.toBeInTheDocument(); + }); + }; + + it("renders all CV tab labels", () => { + renderTabs(); + mockTabs.forEach((tab) => { + expect(screen.getByRole("tab", { name: tab.label })).toBeInTheDocument(); + }); + }); + + it.each(mockTabs)("renders correct content for $label tab", (tab) => { + renderTabs(); + if (tab.id !== mockTabs[0].id) { + fireEvent.click(screen.getByRole("tab", { name: tab.label })); + } + expectTextsToBePresent(tab.expectedTexts); + expectTextsNotToBePresent(tab.unexpectedTexts); + }); + + it("applies correct ARIA attributes to CV tabs", () => { + renderTabs(); + mockTabs.forEach((tab, index) => { + const tabElement = screen.getByRole("tab", { name: tab.label }); + expect(tabElement).toHaveAttribute( + "aria-selected", + index === 0 ? "true" : "false" + ); + expect(tabElement).toHaveAttribute("aria-controls", `tabpanel-${tab.id}`); + }); + }); + + it("renders in vertical orientation by default", () => { + renderTabs(); + const tabList = screen.getByRole("tablist"); + expect(tabList).toHaveClass("sm:flex-col"); + }); +}); diff --git a/package.json b/package.json index 926d7ab3..0d76c3cb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dfweb-v4", - "version": "1.0.2", + "version": "1.0.3", "private": true, "scripts": { "dev": "next dev",