|
| 1 | +import React from "react"; |
| 2 | +import { render, screen } from "@testing-library/react"; |
| 3 | +import "@testing-library/jest-dom"; |
| 4 | +import MeetingDetail from "./MeetingDetail"; |
| 5 | +import { BrowserRouter } from "react-router"; |
| 6 | +import { vi } from "vitest"; |
| 7 | +import { IMeeting } from "@/types/sessions"; |
| 8 | +import { ISpeaker } from "@/types/speakers"; |
| 9 | + |
| 10 | +// Mock framer-motion |
| 11 | +vi.mock("framer-motion", () => ({ |
| 12 | + motion: { |
| 13 | + div: ({ |
| 14 | + children, |
| 15 | + ...props |
| 16 | + }: { |
| 17 | + children: React.ReactNode; |
| 18 | + [key: string]: unknown; |
| 19 | + }) => <div {...props}>{children}</div>, |
| 20 | + img: (props: { [key: string]: unknown }) => <img {...props} />, |
| 21 | + }, |
| 22 | +})); |
| 23 | + |
| 24 | +// Mock add-to-calendar-button-react |
| 25 | +vi.mock("add-to-calendar-button-react", () => ({ |
| 26 | + AddToCalendarButton: () => ( |
| 27 | + <button data-testid="add-to-calendar">Add to Calendar</button> |
| 28 | + ), |
| 29 | +})); |
| 30 | + |
| 31 | +// Mock useWindowSize |
| 32 | +vi.mock("react-use", () => ({ |
| 33 | + useWindowSize: () => ({ width: 1200, height: 800 }), |
| 34 | +})); |
| 35 | + |
| 36 | +const mockMeeting: IMeeting = { |
| 37 | + id: 12345, |
| 38 | + title: "Test Talk Title", |
| 39 | + description: "This is a test talk description with important content.", |
| 40 | + videoUrl: "https://www.youtube.com/embed/test123", |
| 41 | + slidesURL: "https://slides.example.com/test", |
| 42 | + videoTags: ["React", "TypeScript", "Testing"], |
| 43 | + speakers: [ |
| 44 | + { id: "speaker-1", name: "John Doe" }, |
| 45 | + { id: "speaker-2", name: "Jane Smith" }, |
| 46 | + ], |
| 47 | + level: "Intermediate", |
| 48 | + type: "Talk", |
| 49 | + language: "English", |
| 50 | + track: "Frontend", |
| 51 | + startDate: "2024-06-17", |
| 52 | + endDate: "2024-06-17", |
| 53 | + startTime: "10:00", |
| 54 | + endTime: "11:00", |
| 55 | +}; |
| 56 | + |
| 57 | +const mockSpeakers: ISpeaker[] = [ |
| 58 | + { |
| 59 | + id: "speaker-1", |
| 60 | + fullName: "John Doe", |
| 61 | + speakerImage: "/images/speakers/john.jpg", |
| 62 | + bio: "Test bio", |
| 63 | + tagLine: "Test tagline", |
| 64 | + sessions: [], |
| 65 | + links: [], |
| 66 | + }, |
| 67 | + { |
| 68 | + id: "speaker-2", |
| 69 | + fullName: "Jane Smith", |
| 70 | + speakerImage: "/images/speakers/jane.jpg", |
| 71 | + bio: "Test bio 2", |
| 72 | + tagLine: "Test tagline 2", |
| 73 | + sessions: [], |
| 74 | + links: [], |
| 75 | + }, |
| 76 | +]; |
| 77 | + |
| 78 | +const renderMeetingDetail = ( |
| 79 | + meeting: Partial<IMeeting> = {}, |
| 80 | + speakers: ISpeaker[] = mockSpeakers |
| 81 | +) => { |
| 82 | + return render( |
| 83 | + <BrowserRouter> |
| 84 | + <MeetingDetail |
| 85 | + meeting={{ ...mockMeeting, ...meeting }} |
| 86 | + speakers={speakers} |
| 87 | + openFeedbackId="test-feedback-id" |
| 88 | + /> |
| 89 | + </BrowserRouter> |
| 90 | + ); |
| 91 | +}; |
| 92 | + |
| 93 | +describe("MeetingDetail", () => { |
| 94 | + it("renders the meeting title", () => { |
| 95 | + renderMeetingDetail(); |
| 96 | + expect(screen.getByText(/Test Talk Title/)).toBeInTheDocument(); |
| 97 | + }); |
| 98 | + |
| 99 | + it("renders the meeting description", () => { |
| 100 | + renderMeetingDetail(); |
| 101 | + expect( |
| 102 | + screen.getByText(/This is a test talk description/) |
| 103 | + ).toBeInTheDocument(); |
| 104 | + }); |
| 105 | + |
| 106 | + it("renders speaker names with links", () => { |
| 107 | + renderMeetingDetail(); |
| 108 | + expect(screen.getByText("John Doe")).toBeInTheDocument(); |
| 109 | + expect(screen.getByText("Jane Smith")).toBeInTheDocument(); |
| 110 | + }); |
| 111 | + |
| 112 | + it("renders speaker images", () => { |
| 113 | + renderMeetingDetail(); |
| 114 | + const speakerImages = screen.getAllByRole("img", { name: /John Doe|Jane Smith/ }); |
| 115 | + expect(speakerImages).toHaveLength(2); |
| 116 | + }); |
| 117 | + |
| 118 | + it("renders vote talk link with correct href", () => { |
| 119 | + renderMeetingDetail(); |
| 120 | + const voteLink = screen.getByText(/Vote this talk/).closest("a"); |
| 121 | + expect(voteLink).toHaveAttribute( |
| 122 | + "href", |
| 123 | + "https://openfeedback.io/test-feedback-id/0/12345" |
| 124 | + ); |
| 125 | + }); |
| 126 | + |
| 127 | + it("renders video iframe when videoUrl is provided", () => { |
| 128 | + renderMeetingDetail(); |
| 129 | + const iframe = screen.getByTitle("Test Talk Title"); |
| 130 | + expect(iframe).toBeInTheDocument(); |
| 131 | + expect(iframe).toHaveAttribute( |
| 132 | + "src", |
| 133 | + "https://www.youtube.com/embed/test123" |
| 134 | + ); |
| 135 | + }); |
| 136 | + |
| 137 | + it("does not render video iframe when videoUrl is empty", () => { |
| 138 | + renderMeetingDetail({ videoUrl: undefined }); |
| 139 | + expect(screen.queryByTitle("Test Talk Title")).not.toBeInTheDocument(); |
| 140 | + }); |
| 141 | + |
| 142 | + it("renders slides link when slidesURL is provided", () => { |
| 143 | + renderMeetingDetail(); |
| 144 | + const slidesLink = screen.getByText(/Session Slides/).closest("a"); |
| 145 | + expect(slidesLink).toHaveAttribute( |
| 146 | + "href", |
| 147 | + "https://slides.example.com/test" |
| 148 | + ); |
| 149 | + }); |
| 150 | + |
| 151 | + it("does not render slides link when slidesURL is empty", () => { |
| 152 | + renderMeetingDetail({ slidesURL: "" }); |
| 153 | + expect(screen.queryByText(/Session Slides/)).not.toBeInTheDocument(); |
| 154 | + }); |
| 155 | + |
| 156 | + it("renders video tags", () => { |
| 157 | + renderMeetingDetail(); |
| 158 | + expect(screen.getByText("React")).toBeInTheDocument(); |
| 159 | + expect(screen.getByText("TypeScript")).toBeInTheDocument(); |
| 160 | + expect(screen.getByText("Testing")).toBeInTheDocument(); |
| 161 | + }); |
| 162 | + |
| 163 | + it("renders track information", () => { |
| 164 | + renderMeetingDetail(); |
| 165 | + expect(screen.getByText(/Track:/)).toBeInTheDocument(); |
| 166 | + expect(screen.getByText(/Frontend/)).toBeInTheDocument(); |
| 167 | + }); |
| 168 | + |
| 169 | + it("renders level and type information", () => { |
| 170 | + renderMeetingDetail(); |
| 171 | + expect(screen.getByText(/Talk Intermediate/)).toBeInTheDocument(); |
| 172 | + }); |
| 173 | + |
| 174 | + it("renders go back link", () => { |
| 175 | + renderMeetingDetail(); |
| 176 | + const backLink = screen.getByText("Go back"); |
| 177 | + expect(backLink).toBeInTheDocument(); |
| 178 | + expect(backLink.closest("a")).toHaveAttribute("href", "/talks"); |
| 179 | + }); |
| 180 | + |
| 181 | + it("renders add to calendar button", () => { |
| 182 | + renderMeetingDetail(); |
| 183 | + expect(screen.getByTestId("add-to-calendar")).toBeInTheDocument(); |
| 184 | + }); |
| 185 | +}); |
0 commit comments