@times-components/ts-components 1.145.1-82bc6796129e892c1eb22c6257c5e3809c159767.3 → 1.145.1-cfea81c4084e6f91221ea00fec9fc730d5b933cb.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/dist/components/carousel-component/CarouselComponent.stories.js +146 -0
  2. package/dist/components/carousel-component/CarouselItem.d.ts +3 -0
  3. package/dist/components/carousel-component/CarouselItem.js +11 -0
  4. package/dist/components/carousel-component/DefaultNavigationArrow.d.ts +8 -0
  5. package/dist/components/carousel-component/DefaultNavigationArrow.js +6 -0
  6. package/dist/components/carousel-component/DefaultPageDot.d.ts +8 -0
  7. package/dist/components/carousel-component/DefaultPageDot.js +4 -0
  8. package/dist/components/carousel-component/__tests__/CarouselComponent.test.js +163 -0
  9. package/dist/components/carousel-component/__tests__/CarouselItem.test.js +80 -0
  10. package/dist/components/carousel-component/__tests__/DefaultNavigationArrow.test.js +62 -0
  11. package/dist/components/{opta/football/opta-match-stats/matchday-live/__tests__/OptaMatchStatsMatchdayLive.test.d.ts → carousel-component/__tests__/DefaultPageDot.test.d.ts} +0 -1
  12. package/dist/components/carousel-component/__tests__/DefaultPageDot.test.js +68 -0
  13. package/dist/components/carousel-component/hooks/__tests__/useCarousel.test.d.ts +1 -0
  14. package/dist/components/carousel-component/hooks/__tests__/useCarousel.test.js +314 -0
  15. package/dist/components/carousel-component/hooks/useCarousel.d.ts +2 -0
  16. package/dist/components/carousel-component/hooks/useCarousel.js +140 -0
  17. package/dist/components/carousel-component/index.d.ts +4 -0
  18. package/dist/components/carousel-component/index.js +20 -0
  19. package/dist/components/carousel-component/styles.d.ts +30 -0
  20. package/dist/components/carousel-component/styles.js +120 -0
  21. package/dist/components/carousel-component/types.d.ts +46 -0
  22. package/dist/components/carousel-component/types.js +2 -0
  23. package/dist/components/opta/football/opta-match-stats/shared/styles.js +1 -8
  24. package/dist/components/opta/football/opta-match-stats/summary/OptaMatchStatsSummary.js +2 -2
  25. package/dist/components/opta/football/opta-match-stats/summary/OptaMatchStatsSummary.stories.js +1 -1
  26. package/dist/components/opta/football/opta-match-stats/summary/WidgetContainer.js +4 -13
  27. package/dist/components/trip-cards/SkeletonCard.d.ts +2 -0
  28. package/dist/components/trip-cards/SkeletonCard.js +21 -0
  29. package/dist/components/trip-cards/TripCard.d.ts +3 -0
  30. package/dist/components/trip-cards/TripCard.js +47 -0
  31. package/dist/components/trip-cards/TripCards.stories.d.ts +1 -0
  32. package/dist/components/trip-cards/TripCards.stories.js +40 -0
  33. package/dist/components/trip-cards/TripCardsLayout.d.ts +3 -0
  34. package/dist/components/trip-cards/TripCardsLayout.js +26 -0
  35. package/dist/components/trip-cards/__tests__/SkeletonCard.test.d.ts +1 -0
  36. package/dist/components/trip-cards/__tests__/SkeletonCard.test.js +139 -0
  37. package/dist/components/trip-cards/__tests__/TripCard.test.d.ts +1 -0
  38. package/dist/components/trip-cards/__tests__/TripCard.test.js +95 -0
  39. package/dist/components/trip-cards/__tests__/TripCardsLayout.test.d.ts +1 -0
  40. package/dist/components/trip-cards/__tests__/TripCardsLayout.test.js +277 -0
  41. package/dist/components/trip-cards/__tests__/assets.test.d.ts +1 -0
  42. package/dist/components/trip-cards/__tests__/assets.test.js +165 -0
  43. package/dist/components/trip-cards/__tests__/helpers.test.d.ts +1 -0
  44. package/dist/components/trip-cards/__tests__/helpers.test.js +135 -0
  45. package/dist/components/trip-cards/__tests__/index.test.d.ts +1 -0
  46. package/dist/components/trip-cards/__tests__/index.test.js +437 -0
  47. package/dist/components/trip-cards/__tests__/mockData.test.d.ts +1 -0
  48. package/dist/components/trip-cards/__tests__/mockData.test.js +57 -0
  49. package/dist/components/trip-cards/__tests__/skeletonStyles.test.d.ts +1 -0
  50. package/dist/components/trip-cards/__tests__/skeletonStyles.test.js +194 -0
  51. package/dist/components/trip-cards/assets/BoatIcon.d.ts +1 -0
  52. package/dist/components/trip-cards/assets/BoatIcon.js +4 -0
  53. package/dist/components/trip-cards/assets/CalendarIcon.d.ts +1 -0
  54. package/dist/components/trip-cards/assets/CalendarIcon.js +4 -0
  55. package/dist/components/trip-cards/assets/ChevronRightIcon.d.ts +1 -0
  56. package/dist/components/trip-cards/assets/ChevronRightIcon.js +4 -0
  57. package/dist/components/trip-cards/assets/LocationIcon.d.ts +1 -0
  58. package/dist/components/trip-cards/assets/LocationIcon.js +4 -0
  59. package/dist/components/trip-cards/assets/MoonIcon.d.ts +1 -0
  60. package/dist/components/trip-cards/assets/MoonIcon.js +4 -0
  61. package/dist/components/trip-cards/assets/index.d.ts +6 -0
  62. package/dist/components/trip-cards/assets/index.js +7 -0
  63. package/dist/components/trip-cards/helpers.d.ts +4 -0
  64. package/dist/components/trip-cards/helpers.js +74 -0
  65. package/dist/components/trip-cards/index.d.ts +4 -0
  66. package/dist/components/trip-cards/index.js +70 -0
  67. package/dist/components/trip-cards/mockData.d.ts +3 -0
  68. package/dist/components/trip-cards/mockData.js +323 -0
  69. package/dist/components/trip-cards/skeletonStyles.d.ts +9 -0
  70. package/dist/components/trip-cards/skeletonStyles.js +37 -0
  71. package/dist/components/trip-cards/styles.d.ts +39 -0
  72. package/dist/components/trip-cards/styles.js +387 -0
  73. package/dist/components/trip-cards/types.d.ts +87 -0
  74. package/dist/components/trip-cards/types.js +2 -0
  75. package/dist/index.d.ts +1 -1
  76. package/dist/index.js +2 -2
  77. package/package.json +3 -3
  78. package/rnw.js +1 -1
  79. package/src/components/carousel-component/CarouselComponent.stories.tsx +220 -0
  80. package/src/components/carousel-component/CarouselItem.tsx +20 -0
  81. package/src/components/carousel-component/DefaultNavigationArrow.tsx +37 -0
  82. package/src/components/carousel-component/DefaultPageDot.tsx +20 -0
  83. package/src/components/carousel-component/__tests__/CarouselComponent.test.tsx +259 -0
  84. package/src/components/carousel-component/__tests__/CarouselItem.test.tsx +140 -0
  85. package/src/components/carousel-component/__tests__/DefaultNavigationArrow.test.tsx +153 -0
  86. package/src/components/carousel-component/__tests__/DefaultPageDot.test.tsx +105 -0
  87. package/src/components/carousel-component/hooks/__tests__/useCarousel.test.ts +438 -0
  88. package/src/components/carousel-component/hooks/useCarousel.ts +187 -0
  89. package/src/components/carousel-component/index.tsx +88 -0
  90. package/src/components/carousel-component/styles.ts +140 -0
  91. package/src/components/carousel-component/types.ts +51 -0
  92. package/src/components/opta/football/opta-match-stats/commentary/__tests__/__snapshots__/OptaMatchStatsCommentary.test.tsx.snap +1 -1
  93. package/src/components/opta/football/opta-match-stats/shared/styles.ts +0 -8
  94. package/src/components/opta/football/opta-match-stats/stats-graphs/__tests__/__snapshots__/OptaMatchStatsGraphs.test.tsx.snap +1 -1
  95. package/src/components/opta/football/opta-match-stats/summary/OptaMatchStatsSummary.stories.tsx +1 -1
  96. package/src/components/opta/football/opta-match-stats/summary/OptaMatchStatsSummary.tsx +1 -1
  97. package/src/components/opta/football/opta-match-stats/summary/WidgetContainer.tsx +3 -12
  98. package/src/components/opta/football/opta-match-stats/summary/__tests__/__snapshots__/OptaMatchStatsSummary.test.tsx.snap +1 -1
  99. package/src/components/trip-cards/SkeletonCard.tsx +54 -0
  100. package/src/components/trip-cards/TripCard.tsx +135 -0
  101. package/src/components/trip-cards/TripCards.stories.tsx +67 -0
  102. package/src/components/trip-cards/TripCardsLayout.tsx +75 -0
  103. package/src/components/trip-cards/__tests__/SkeletonCard.test.tsx +169 -0
  104. package/src/components/trip-cards/__tests__/TripCard.test.tsx +120 -0
  105. package/src/components/trip-cards/__tests__/TripCardsLayout.test.tsx +532 -0
  106. package/src/components/trip-cards/__tests__/assets.test.tsx +206 -0
  107. package/src/components/trip-cards/__tests__/helpers.test.ts +165 -0
  108. package/src/components/trip-cards/__tests__/index.test.tsx +499 -0
  109. package/src/components/trip-cards/__tests__/mockData.test.ts +67 -0
  110. package/src/components/trip-cards/__tests__/skeletonStyles.test.tsx +256 -0
  111. package/src/components/trip-cards/assets/BoatIcon.tsx +17 -0
  112. package/src/components/trip-cards/assets/CalendarIcon.tsx +17 -0
  113. package/src/components/trip-cards/assets/ChevronRightIcon.tsx +20 -0
  114. package/src/components/trip-cards/assets/LocationIcon.tsx +17 -0
  115. package/src/components/trip-cards/assets/MoonIcon.tsx +17 -0
  116. package/src/components/trip-cards/assets/index.ts +7 -0
  117. package/src/components/trip-cards/helpers.ts +99 -0
  118. package/src/components/trip-cards/index.tsx +104 -0
  119. package/src/components/trip-cards/mockData.ts +351 -0
  120. package/src/components/trip-cards/skeletonStyles.ts +46 -0
  121. package/src/components/trip-cards/styles.ts +426 -0
  122. package/src/components/trip-cards/types.ts +91 -0
  123. package/src/index.ts +2 -3
  124. package/dist/components/opta/football/opta-match-stats/matchday-live/DesktopWidget.d.ts +0 -10
  125. package/dist/components/opta/football/opta-match-stats/matchday-live/DesktopWidget.js +0 -69
  126. package/dist/components/opta/football/opta-match-stats/matchday-live/MobileWidget.d.ts +0 -12
  127. package/dist/components/opta/football/opta-match-stats/matchday-live/MobileWidget.js +0 -90
  128. package/dist/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.d.ts +0 -12
  129. package/dist/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.js +0 -10
  130. package/dist/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.stories.js +0 -24
  131. package/dist/components/opta/football/opta-match-stats/matchday-live/__tests__/MobileWidget.test.js +0 -57
  132. package/dist/components/opta/football/opta-match-stats/matchday-live/__tests__/OptaMatchStatsMatchdayLive.test.js +0 -48
  133. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/MatchdayLiveController.d.ts +0 -1
  134. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/MatchdayLiveController.js +0 -19
  135. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/NavigationWrapper.d.ts +0 -12
  136. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/NavigationWrapper.js +0 -67
  137. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/WidgetContainer.d.ts +0 -6
  138. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/WidgetContainer.js +0 -730
  139. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/__tests__/NavigationWrapper.test.js +0 -33
  140. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/__tests__/WidgetContainer.test.js +0 -36
  141. package/src/components/opta/football/opta-match-stats/matchday-live/DesktopWidget.tsx +0 -108
  142. package/src/components/opta/football/opta-match-stats/matchday-live/MobileWidget.tsx +0 -158
  143. package/src/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.stories.tsx +0 -38
  144. package/src/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.tsx +0 -23
  145. package/src/components/opta/football/opta-match-stats/matchday-live/__tests__/MobileWidget.test.tsx +0 -69
  146. package/src/components/opta/football/opta-match-stats/matchday-live/__tests__/OptaMatchStatsMatchdayLive.test.tsx +0 -61
  147. package/src/components/opta/football/opta-match-stats/matchday-live/__tests__/__snapshots__/OptaMatchStatsMatchdayLive.test.tsx.snap +0 -61
  148. package/src/components/opta/football/opta-match-stats/matchday-live/styles/MatchdayLiveController.tsx +0 -19
  149. package/src/components/opta/football/opta-match-stats/matchday-live/styles/NavigationWrapper.tsx +0 -81
  150. package/src/components/opta/football/opta-match-stats/matchday-live/styles/WidgetContainer.tsx +0 -761
  151. package/src/components/opta/football/opta-match-stats/matchday-live/styles/__tests__/NavigationWrapper.test.tsx +0 -67
  152. package/src/components/opta/football/opta-match-stats/matchday-live/styles/__tests__/WidgetContainer.test.tsx +0 -64
  153. /package/dist/components/{opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.stories.d.ts → carousel-component/CarouselComponent.stories.d.ts} +0 -0
  154. /package/dist/components/{opta/football/opta-match-stats/matchday-live/__tests__/MobileWidget.test.d.ts → carousel-component/__tests__/CarouselComponent.test.d.ts} +0 -0
  155. /package/dist/components/{opta/football/opta-match-stats/matchday-live/styles/__tests__/NavigationWrapper.test.d.ts → carousel-component/__tests__/CarouselItem.test.d.ts} +0 -0
  156. /package/dist/components/{opta/football/opta-match-stats/matchday-live/styles/__tests__/WidgetContainer.test.d.ts → carousel-component/__tests__/DefaultNavigationArrow.test.d.ts} +0 -0
@@ -0,0 +1,532 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+ import { TripCardsLayout } from '../TripCardsLayout';
5
+ import { TripCardApiData } from '../types';
6
+
7
+ const mockElement = {
8
+ class: 'trip-cards',
9
+ tripcards: btoa(JSON.stringify([1, 2])),
10
+ title: 'Test Cruises',
11
+ titleUrl: 'https://example.com',
12
+ description: 'Test Description'
13
+ };
14
+
15
+ const MockCard = ({ card }: { card?: TripCardApiData }) => (
16
+ <div data-testid="mock-card">
17
+ {card ? card.headline || 'Mock Card' : 'Mock Card'}
18
+ </div>
19
+ );
20
+
21
+ describe('TripCardsLayout', () => {
22
+ beforeEach(() => {
23
+ Element.prototype.scrollTo = jest.fn();
24
+ });
25
+
26
+ describe('Rendering', () => {
27
+ it('renders with title and description', () => {
28
+ const items = [
29
+ { id: '1', data: undefined },
30
+ { id: '2', data: undefined }
31
+ ];
32
+
33
+ render(
34
+ <TripCardsLayout
35
+ element={mockElement}
36
+ items={items}
37
+ CardComponent={MockCard}
38
+ itemsPerPage={2}
39
+ />
40
+ );
41
+
42
+ expect(screen.getByText('Test Cruises')).toBeInTheDocument();
43
+ expect(screen.getByText('Test Description')).toBeInTheDocument();
44
+ });
45
+
46
+ it('renders empty title when not provided', () => {
47
+ const elementWithoutTitle = {
48
+ ...mockElement,
49
+ title: undefined
50
+ };
51
+
52
+ const items = [{ id: '1', data: undefined }];
53
+
54
+ const { container } = render(
55
+ <TripCardsLayout
56
+ element={elementWithoutTitle}
57
+ items={items}
58
+ CardComponent={MockCard}
59
+ itemsPerPage={2}
60
+ />
61
+ );
62
+
63
+ const title = container.querySelector('h2');
64
+ expect(title).toBeInTheDocument();
65
+ expect(title).toBeEmptyDOMElement();
66
+ });
67
+
68
+ it('renders empty description when not provided', () => {
69
+ const elementWithoutDesc = {
70
+ ...mockElement,
71
+ description: undefined
72
+ };
73
+
74
+ const items = [{ id: '1', data: undefined }];
75
+
76
+ const { container } = render(
77
+ <TripCardsLayout
78
+ element={elementWithoutDesc}
79
+ items={items}
80
+ CardComponent={MockCard}
81
+ itemsPerPage={2}
82
+ />
83
+ );
84
+
85
+ const description = container.querySelector('p');
86
+ expect(description).toBeInTheDocument();
87
+ expect(description).toBeEmptyDOMElement();
88
+ });
89
+
90
+ it('renders title link when provided', () => {
91
+ const items = [{ id: '1', data: undefined }];
92
+
93
+ render(
94
+ <TripCardsLayout
95
+ element={mockElement}
96
+ items={items}
97
+ CardComponent={MockCard}
98
+ itemsPerPage={2}
99
+ />
100
+ );
101
+
102
+ const link = screen.getByRole('link');
103
+ expect(link).toHaveAttribute('href', 'https://example.com');
104
+ expect(link).toHaveAttribute('target', '_blank');
105
+ expect(link).toHaveAttribute('rel', 'noopener noreferrer');
106
+ });
107
+
108
+ it('does not render title link when not provided', () => {
109
+ const elementWithoutLink = {
110
+ ...mockElement,
111
+ titleUrl: undefined
112
+ };
113
+
114
+ const items = [{ id: '1', data: undefined }];
115
+
116
+ render(
117
+ <TripCardsLayout
118
+ element={elementWithoutLink}
119
+ items={items}
120
+ CardComponent={MockCard}
121
+ itemsPerPage={2}
122
+ />
123
+ );
124
+
125
+ const links = screen.queryAllByRole('link');
126
+ expect(links.length).toBe(0);
127
+ });
128
+
129
+ it('renders ChevronRightIcon in title link', () => {
130
+ const items = [{ id: '1', data: undefined }];
131
+
132
+ const { container } = render(
133
+ <TripCardsLayout
134
+ element={mockElement}
135
+ items={items}
136
+ CardComponent={MockCard}
137
+ itemsPerPage={2}
138
+ />
139
+ );
140
+
141
+ const svg = container.querySelector('svg');
142
+ expect(svg).toBeInTheDocument();
143
+ });
144
+ });
145
+
146
+ describe('Static Grid Layout', () => {
147
+ it('renders static grid for exactly 2 items', () => {
148
+ const items = [
149
+ { id: '1', data: undefined },
150
+ { id: '2', data: undefined }
151
+ ];
152
+
153
+ render(
154
+ <TripCardsLayout
155
+ element={mockElement}
156
+ items={items}
157
+ CardComponent={MockCard}
158
+ itemsPerPage={2}
159
+ />
160
+ );
161
+
162
+ const staticGrid = screen.getByTestId('static-cards-grid');
163
+ expect(staticGrid).toBeInTheDocument();
164
+ });
165
+
166
+ it('renders correct number of cards in static grid', () => {
167
+ const items = [
168
+ { id: '1', data: undefined },
169
+ { id: '2', data: undefined }
170
+ ];
171
+
172
+ render(
173
+ <TripCardsLayout
174
+ element={mockElement}
175
+ items={items}
176
+ CardComponent={MockCard}
177
+ itemsPerPage={2}
178
+ />
179
+ );
180
+
181
+ const cards = screen.getAllByTestId('mock-card');
182
+ expect(cards.length).toBe(2);
183
+ });
184
+
185
+ it('passes correct props to CardComponent in static grid', () => {
186
+ const mockData: TripCardApiData = {
187
+ cruise_id: '1',
188
+ image: 'test.jpg',
189
+ headline: 'Test Cruise',
190
+ date: 'Jan 2024',
191
+ duration: '7 nights',
192
+ route: 'Test Route',
193
+ ship: 'Test Ship',
194
+ price: '£1000',
195
+ logo: 'logo.png',
196
+ logo_url: 'https://example.com',
197
+ cta_url: 'https://example.com',
198
+ cta_text: 'View'
199
+ };
200
+
201
+ const items = [{ id: '1', data: mockData }, { id: '2', data: undefined }];
202
+
203
+ render(
204
+ <TripCardsLayout
205
+ element={mockElement}
206
+ items={items}
207
+ CardComponent={MockCard}
208
+ itemsPerPage={2}
209
+ />
210
+ );
211
+
212
+ expect(screen.getByText('Test Cruise')).toBeInTheDocument();
213
+ });
214
+ });
215
+
216
+ describe('Carousel Layout', () => {
217
+ it('renders carousel for more than 2 items', () => {
218
+ const items = [
219
+ { id: '1', data: undefined },
220
+ { id: '2', data: undefined },
221
+ { id: '3', data: undefined }
222
+ ];
223
+
224
+ render(
225
+ <TripCardsLayout
226
+ element={mockElement}
227
+ items={items}
228
+ CardComponent={MockCard}
229
+ itemsPerPage={2}
230
+ />
231
+ );
232
+
233
+ const cards = screen.getAllByTestId('mock-card');
234
+ expect(cards.length).toBe(3);
235
+ });
236
+
237
+ it('renders navigation arrows in carousel', () => {
238
+ const items = [
239
+ { id: '1', data: undefined },
240
+ { id: '2', data: undefined },
241
+ { id: '3', data: undefined }
242
+ ];
243
+
244
+ render(
245
+ <TripCardsLayout
246
+ element={mockElement}
247
+ items={items}
248
+ CardComponent={MockCard}
249
+ itemsPerPage={2}
250
+ />
251
+ );
252
+
253
+ expect(screen.getByLabelText('Previous items')).toBeInTheDocument();
254
+ expect(screen.getByLabelText('Next items')).toBeInTheDocument();
255
+ });
256
+
257
+ it('renders page dots in carousel', () => {
258
+ const items = [
259
+ { id: '1', data: undefined },
260
+ { id: '2', data: undefined },
261
+ { id: '3', data: undefined },
262
+ { id: '4', data: undefined }
263
+ ];
264
+
265
+ render(
266
+ <TripCardsLayout
267
+ element={mockElement}
268
+ items={items}
269
+ CardComponent={MockCard}
270
+ itemsPerPage={2}
271
+ />
272
+ );
273
+
274
+ expect(screen.getByLabelText('Previous items')).toBeInTheDocument();
275
+ expect(screen.getByLabelText('Next items')).toBeInTheDocument();
276
+
277
+ // With 4 items and 2 per page, we have 2 pages, so we should have 2 dot buttons
278
+ const pageDots = screen.getAllByLabelText(/Go to page/i);
279
+ expect(pageDots.length).toBe(2);
280
+ });
281
+
282
+ it('renders carousel for 1 item', () => {
283
+ const items = [{ id: '1', data: undefined }];
284
+
285
+ render(
286
+ <TripCardsLayout
287
+ element={mockElement}
288
+ items={items}
289
+ CardComponent={MockCard}
290
+ itemsPerPage={2}
291
+ />
292
+ );
293
+
294
+ const cards = screen.getAllByTestId('mock-card');
295
+ expect(cards.length).toBe(1);
296
+ });
297
+
298
+ it('wraps cards in CarouselItem with correct widthConfig', () => {
299
+ const items = [
300
+ { id: '1', data: undefined },
301
+ { id: '2', data: undefined },
302
+ { id: '3', data: undefined }
303
+ ];
304
+
305
+ render(
306
+ <TripCardsLayout
307
+ element={mockElement}
308
+ items={items}
309
+ CardComponent={MockCard}
310
+ itemsPerPage={2}
311
+ />
312
+ );
313
+
314
+ // Verify carousel is rendering by checking for cards
315
+ const cards = screen.getAllByTestId('mock-card');
316
+ expect(cards.length).toBe(3);
317
+ });
318
+ });
319
+
320
+ describe('Card Rendering', () => {
321
+ it('renders each item with unique key', () => {
322
+ const items = [
323
+ { id: 'card-1', data: undefined },
324
+ { id: 'card-2', data: undefined }
325
+ ];
326
+
327
+ render(
328
+ <TripCardsLayout
329
+ element={mockElement}
330
+ items={items}
331
+ CardComponent={MockCard}
332
+ itemsPerPage={2}
333
+ />
334
+ );
335
+
336
+ const cards = screen.getAllByTestId('mock-card');
337
+ expect(cards.length).toBe(2);
338
+ });
339
+
340
+ it('passes data to CardComponent', () => {
341
+ const mockData: TripCardApiData = {
342
+ cruise_id: '123',
343
+ image: 'image.jpg',
344
+ headline: 'Specific Cruise',
345
+ date: 'Feb 2024',
346
+ duration: '10 nights',
347
+ route: 'Route A',
348
+ ship: 'Ship X',
349
+ price: '£2000',
350
+ logo: 'logo.png',
351
+ logo_url: 'https://example.com',
352
+ cta_url: 'https://example.com',
353
+ cta_text: 'Book'
354
+ };
355
+
356
+ const items = [
357
+ { id: '1', data: mockData },
358
+ { id: '2', data: undefined },
359
+ { id: '3', data: undefined }
360
+ ];
361
+
362
+ render(
363
+ <TripCardsLayout
364
+ element={mockElement}
365
+ items={items}
366
+ CardComponent={MockCard}
367
+ itemsPerPage={2}
368
+ />
369
+ );
370
+
371
+ expect(screen.getByText('Specific Cruise')).toBeInTheDocument();
372
+ });
373
+
374
+ it('handles empty items array', () => {
375
+ const { container } = render(
376
+ <TripCardsLayout
377
+ element={mockElement}
378
+ items={[]}
379
+ CardComponent={MockCard}
380
+ itemsPerPage={2}
381
+ />
382
+ );
383
+
384
+ expect(container.firstChild).toBeInTheDocument();
385
+ const cards = screen.queryAllByTestId('mock-card');
386
+ expect(cards.length).toBe(0);
387
+ });
388
+ });
389
+
390
+ describe('Container Structure', () => {
391
+ it('renders main container', () => {
392
+ const items = [{ id: '1', data: undefined }];
393
+
394
+ render(
395
+ <TripCardsLayout
396
+ element={mockElement}
397
+ items={items}
398
+ CardComponent={MockCard}
399
+ itemsPerPage={2}
400
+ />
401
+ );
402
+
403
+ const mainContainer = screen.getByTestId('trip-cards-container');
404
+ expect(mainContainer).toBeInTheDocument();
405
+ });
406
+
407
+ it('renders title section', () => {
408
+ const items = [{ id: '1', data: undefined }];
409
+
410
+ render(
411
+ <TripCardsLayout
412
+ element={mockElement}
413
+ items={items}
414
+ CardComponent={MockCard}
415
+ itemsPerPage={2}
416
+ />
417
+ );
418
+
419
+ const titleSection = screen.getByTestId('title-section');
420
+ expect(titleSection).toBeInTheDocument();
421
+ });
422
+
423
+ it('renders title bar with content', () => {
424
+ const items = [{ id: '1', data: undefined }];
425
+
426
+ render(
427
+ <TripCardsLayout
428
+ element={mockElement}
429
+ items={items}
430
+ CardComponent={MockCard}
431
+ itemsPerPage={2}
432
+ />
433
+ );
434
+
435
+ const titleBar = screen.getByTestId('title-bar');
436
+ const titleContent = screen.getByTestId('title-content');
437
+
438
+ expect(titleBar).toBeInTheDocument();
439
+ expect(titleContent).toBeInTheDocument();
440
+ });
441
+ });
442
+
443
+ describe('ItemsPerPage', () => {
444
+ it('respects itemsPerPage prop', () => {
445
+ const items = Array.from({ length: 6 }, (_, i) => ({
446
+ id: `${i}`,
447
+ data: undefined
448
+ }));
449
+
450
+ render(
451
+ <TripCardsLayout
452
+ element={mockElement}
453
+ items={items}
454
+ CardComponent={MockCard}
455
+ itemsPerPage={3}
456
+ />
457
+ );
458
+
459
+ const cards = screen.getAllByTestId('mock-card');
460
+ expect(cards.length).toBe(6);
461
+ });
462
+
463
+ it('handles itemsPerPage of 1', () => {
464
+ const items = [
465
+ { id: '1', data: undefined },
466
+ { id: '2', data: undefined }
467
+ ];
468
+
469
+ render(
470
+ <TripCardsLayout
471
+ element={mockElement}
472
+ items={items}
473
+ CardComponent={MockCard}
474
+ itemsPerPage={1}
475
+ />
476
+ );
477
+
478
+ const cards = screen.getAllByTestId('mock-card');
479
+ expect(cards.length).toBe(2);
480
+ });
481
+ });
482
+
483
+ describe('Edge Cases', () => {
484
+ it('handles large number of items', () => {
485
+ const items = Array.from({ length: 50 }, (_, i) => ({
486
+ id: `${i}`,
487
+ data: undefined
488
+ }));
489
+
490
+ render(
491
+ <TripCardsLayout
492
+ element={mockElement}
493
+ items={items}
494
+ CardComponent={MockCard}
495
+ itemsPerPage={2}
496
+ />
497
+ );
498
+
499
+ const cards = screen.getAllByTestId('mock-card');
500
+ expect(cards.length).toBe(50);
501
+ });
502
+
503
+ it('handles empty title and description', () => {
504
+ const emptyElement = {
505
+ ...mockElement,
506
+ title: '',
507
+ description: ''
508
+ };
509
+
510
+ const items = [{ id: '1', data: undefined }];
511
+
512
+ const { container } = render(
513
+ <TripCardsLayout
514
+ element={emptyElement}
515
+ items={items}
516
+ CardComponent={MockCard}
517
+ itemsPerPage={2}
518
+ />
519
+ );
520
+
521
+ const title = container.querySelector('h2');
522
+ const description = container.querySelector('p');
523
+
524
+ expect(title).toBeInTheDocument();
525
+ expect(description).toBeInTheDocument();
526
+ if (title && description) {
527
+ expect(title.textContent).toBe('');
528
+ expect(description.textContent).toBe('');
529
+ }
530
+ });
531
+ });
532
+ });