@times-components/ts-components 1.145.1-777882a8b99dc7733f00b94202a91fa8b7dc2a7e.1 → 1.145.1-7e7a12feaf05c514789e802bf49cadca92e6a2b9.10
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.
- package/dist/components/carousel-component/CarouselComponent.stories.js +146 -0
- package/dist/components/carousel-component/CarouselItem.d.ts +3 -0
- package/dist/components/carousel-component/CarouselItem.js +11 -0
- package/dist/components/carousel-component/DefaultNavigationArrow.d.ts +8 -0
- package/dist/components/carousel-component/DefaultNavigationArrow.js +6 -0
- package/dist/components/carousel-component/DefaultPageDot.d.ts +8 -0
- package/dist/components/carousel-component/DefaultPageDot.js +4 -0
- package/dist/components/{opta/football/opta-match-stats/matchday-live/__tests__/OptaMatchStatsMatchdayLive.test.d.ts → carousel-component/__tests__/CarouselComponent.test.d.ts} +0 -1
- package/dist/components/carousel-component/__tests__/CarouselComponent.test.js +163 -0
- package/dist/components/carousel-component/__tests__/CarouselItem.test.d.ts +1 -0
- package/dist/components/carousel-component/__tests__/CarouselItem.test.js +80 -0
- package/dist/components/carousel-component/__tests__/DefaultNavigationArrow.test.d.ts +1 -0
- package/dist/components/carousel-component/__tests__/DefaultNavigationArrow.test.js +62 -0
- package/dist/components/carousel-component/__tests__/DefaultPageDot.test.d.ts +1 -0
- package/dist/components/carousel-component/__tests__/DefaultPageDot.test.js +68 -0
- package/dist/components/carousel-component/hooks/__tests__/useCarousel.test.d.ts +1 -0
- package/dist/components/carousel-component/hooks/__tests__/useCarousel.test.js +459 -0
- package/dist/components/carousel-component/hooks/useCarousel.d.ts +2 -0
- package/dist/components/carousel-component/hooks/useCarousel.js +175 -0
- package/dist/components/carousel-component/index.d.ts +4 -0
- package/dist/components/carousel-component/index.js +20 -0
- package/dist/components/carousel-component/styles.d.ts +27 -0
- package/dist/components/carousel-component/styles.js +169 -0
- package/dist/components/carousel-component/types.d.ts +53 -0
- package/dist/components/carousel-component/types.js +2 -0
- package/dist/components/opta/football/opta-match-stats/shared/styles.js +1 -8
- package/dist/components/trip-cards/SkeletonCard.d.ts +6 -0
- package/dist/components/trip-cards/SkeletonCard.js +21 -0
- package/dist/components/trip-cards/TripCard.d.ts +3 -0
- package/dist/components/trip-cards/TripCard.js +49 -0
- package/dist/components/trip-cards/TripCards.stories.d.ts +1 -0
- package/dist/components/trip-cards/TripCards.stories.js +189 -0
- package/dist/components/trip-cards/TripCardsLayout.d.ts +3 -0
- package/dist/components/trip-cards/TripCardsLayout.js +37 -0
- package/dist/components/trip-cards/__tests__/SkeletonCard.test.d.ts +1 -0
- package/dist/components/trip-cards/__tests__/SkeletonCard.test.js +139 -0
- package/dist/components/trip-cards/__tests__/TripCard.test.d.ts +1 -0
- package/dist/components/trip-cards/__tests__/TripCard.test.js +95 -0
- package/dist/components/trip-cards/__tests__/TripCardsLayout.test.d.ts +1 -0
- package/dist/components/trip-cards/__tests__/TripCardsLayout.test.js +277 -0
- package/dist/components/trip-cards/__tests__/assets.test.d.ts +1 -0
- package/dist/components/trip-cards/__tests__/assets.test.js +165 -0
- package/dist/components/trip-cards/__tests__/helpers.test.d.ts +1 -0
- package/dist/components/trip-cards/__tests__/helpers.test.js +216 -0
- package/dist/components/trip-cards/__tests__/index.test.d.ts +1 -0
- package/dist/components/trip-cards/__tests__/index.test.js +433 -0
- package/dist/components/trip-cards/__tests__/mockData.test.d.ts +1 -0
- package/dist/components/trip-cards/__tests__/mockData.test.js +57 -0
- package/dist/components/trip-cards/__tests__/skeletonStyles.test.d.ts +1 -0
- package/dist/components/trip-cards/__tests__/skeletonStyles.test.js +194 -0
- package/dist/components/trip-cards/assets/BoatIcon.d.ts +1 -0
- package/dist/components/trip-cards/assets/BoatIcon.js +4 -0
- package/dist/components/trip-cards/assets/CalendarIcon.d.ts +1 -0
- package/dist/components/trip-cards/assets/CalendarIcon.js +4 -0
- package/dist/components/trip-cards/assets/ChevronRightIcon.d.ts +1 -0
- package/dist/components/trip-cards/assets/ChevronRightIcon.js +4 -0
- package/dist/components/trip-cards/assets/LocationIcon.d.ts +1 -0
- package/dist/components/trip-cards/assets/LocationIcon.js +4 -0
- package/dist/components/trip-cards/assets/MoonIcon.d.ts +1 -0
- package/dist/components/trip-cards/assets/MoonIcon.js +4 -0
- package/dist/components/trip-cards/assets/index.d.ts +6 -0
- package/dist/components/trip-cards/assets/index.js +7 -0
- package/dist/components/trip-cards/helpers.d.ts +4 -0
- package/dist/components/trip-cards/helpers.js +115 -0
- package/dist/components/trip-cards/index.d.ts +4 -0
- package/dist/components/trip-cards/index.js +70 -0
- package/dist/components/trip-cards/mockData.d.ts +3 -0
- package/dist/components/trip-cards/mockData.js +317 -0
- package/dist/components/trip-cards/skeletonStyles.d.ts +9 -0
- package/dist/components/trip-cards/skeletonStyles.js +37 -0
- package/dist/components/trip-cards/styles.d.ts +38 -0
- package/dist/components/trip-cards/styles.js +401 -0
- package/dist/components/trip-cards/types.d.ts +119 -0
- package/dist/components/trip-cards/types.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/package.json +3 -3
- package/rnw.js +1 -1
- package/src/components/carousel-component/CarouselComponent.stories.tsx +220 -0
- package/src/components/carousel-component/CarouselItem.tsx +25 -0
- package/src/components/carousel-component/DefaultNavigationArrow.tsx +37 -0
- package/src/components/carousel-component/DefaultPageDot.tsx +20 -0
- package/src/components/carousel-component/__tests__/CarouselComponent.test.tsx +259 -0
- package/src/components/carousel-component/__tests__/CarouselItem.test.tsx +140 -0
- package/src/components/carousel-component/__tests__/DefaultNavigationArrow.test.tsx +153 -0
- package/src/components/carousel-component/__tests__/DefaultPageDot.test.tsx +105 -0
- package/src/components/carousel-component/hooks/__tests__/useCarousel.test.ts +625 -0
- package/src/components/carousel-component/hooks/useCarousel.ts +231 -0
- package/src/components/carousel-component/index.tsx +92 -0
- package/src/components/carousel-component/styles.ts +185 -0
- package/src/components/carousel-component/types.ts +62 -0
- package/src/components/opta/football/opta-match-stats/commentary/__tests__/__snapshots__/OptaMatchStatsCommentary.test.tsx.snap +1 -1
- package/src/components/opta/football/opta-match-stats/shared/styles.ts +0 -8
- package/src/components/opta/football/opta-match-stats/stats-graphs/__tests__/__snapshots__/OptaMatchStatsGraphs.test.tsx.snap +1 -1
- package/src/components/trip-cards/SkeletonCard.tsx +62 -0
- package/src/components/trip-cards/TripCard.tsx +143 -0
- package/src/components/trip-cards/TripCards.stories.tsx +254 -0
- package/src/components/trip-cards/TripCardsLayout.tsx +108 -0
- package/src/components/trip-cards/__tests__/SkeletonCard.test.tsx +169 -0
- package/src/components/trip-cards/__tests__/TripCard.test.tsx +120 -0
- package/src/components/trip-cards/__tests__/TripCardsLayout.test.tsx +532 -0
- package/src/components/trip-cards/__tests__/assets.test.tsx +206 -0
- package/src/components/trip-cards/__tests__/helpers.test.ts +266 -0
- package/src/components/trip-cards/__tests__/index.test.tsx +495 -0
- package/src/components/trip-cards/__tests__/mockData.test.ts +67 -0
- package/src/components/trip-cards/__tests__/skeletonStyles.test.tsx +256 -0
- package/src/components/trip-cards/assets/BoatIcon.tsx +17 -0
- package/src/components/trip-cards/assets/CalendarIcon.tsx +17 -0
- package/src/components/trip-cards/assets/ChevronRightIcon.tsx +20 -0
- package/src/components/trip-cards/assets/LocationIcon.tsx +17 -0
- package/src/components/trip-cards/assets/MoonIcon.tsx +17 -0
- package/src/components/trip-cards/assets/index.ts +7 -0
- package/src/components/trip-cards/helpers.ts +150 -0
- package/src/components/trip-cards/index.tsx +119 -0
- package/src/components/trip-cards/mockData.ts +345 -0
- package/src/components/trip-cards/skeletonStyles.ts +46 -0
- package/src/components/trip-cards/styles.ts +446 -0
- package/src/components/trip-cards/types.ts +128 -0
- package/src/index.ts +2 -3
- package/dist/components/opta/football/opta-match-stats/matchday-live/DesktopWidget.d.ts +0 -10
- package/dist/components/opta/football/opta-match-stats/matchday-live/DesktopWidget.js +0 -69
- package/dist/components/opta/football/opta-match-stats/matchday-live/MobileWidget.d.ts +0 -12
- package/dist/components/opta/football/opta-match-stats/matchday-live/MobileWidget.js +0 -90
- package/dist/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.d.ts +0 -12
- package/dist/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.js +0 -10
- package/dist/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.stories.js +0 -24
- package/dist/components/opta/football/opta-match-stats/matchday-live/__tests__/OptaMatchStatsMatchdayLive.test.js +0 -48
- package/dist/components/opta/football/opta-match-stats/matchday-live/styles/MatchdayLiveController.d.ts +0 -1
- package/dist/components/opta/football/opta-match-stats/matchday-live/styles/MatchdayLiveController.js +0 -19
- package/dist/components/opta/football/opta-match-stats/matchday-live/styles/NavigationWrapper.d.ts +0 -12
- package/dist/components/opta/football/opta-match-stats/matchday-live/styles/NavigationWrapper.js +0 -67
- package/dist/components/opta/football/opta-match-stats/matchday-live/styles/WidgetContainer.d.ts +0 -6
- package/dist/components/opta/football/opta-match-stats/matchday-live/styles/WidgetContainer.js +0 -714
- package/src/components/opta/football/opta-match-stats/matchday-live/DesktopWidget.tsx +0 -108
- package/src/components/opta/football/opta-match-stats/matchday-live/MobileWidget.tsx +0 -158
- package/src/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.stories.tsx +0 -38
- package/src/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.tsx +0 -23
- package/src/components/opta/football/opta-match-stats/matchday-live/__tests__/OptaMatchStatsMatchdayLive.test.tsx +0 -61
- package/src/components/opta/football/opta-match-stats/matchday-live/__tests__/__snapshots__/OptaMatchStatsMatchdayLive.test.tsx.snap +0 -61
- package/src/components/opta/football/opta-match-stats/matchday-live/styles/MatchdayLiveController.tsx +0 -19
- package/src/components/opta/football/opta-match-stats/matchday-live/styles/NavigationWrapper.tsx +0 -81
- package/src/components/opta/football/opta-match-stats/matchday-live/styles/WidgetContainer.tsx +0 -745
- /package/dist/components/{opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.stories.d.ts → carousel-component/CarouselComponent.stories.d.ts} +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
import { TripCard } from '../TripCard';
|
|
5
|
+
import { TripCardApiData } from '../types';
|
|
6
|
+
|
|
7
|
+
const mockCard: TripCardApiData = {
|
|
8
|
+
cruise_id: '2074350',
|
|
9
|
+
image: 'https://example.com/image.jpg',
|
|
10
|
+
headline: 'Mediterranean from Barcelona',
|
|
11
|
+
date: 'Oct 2025 - Oct 2025',
|
|
12
|
+
duration: 'Seven Days',
|
|
13
|
+
route: 'Barcelona → Marseille',
|
|
14
|
+
ship: 'MSC Seaside',
|
|
15
|
+
price: '£2000',
|
|
16
|
+
logo: 'https://example.com/logo.png',
|
|
17
|
+
logo_url: 'https://example.com',
|
|
18
|
+
cta_url: 'https://example.com/cruise',
|
|
19
|
+
cta_text: 'View Itinerary'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
describe('TripCard', () => {
|
|
23
|
+
it('renders card with all required data', () => {
|
|
24
|
+
render(<TripCard card={mockCard} />);
|
|
25
|
+
|
|
26
|
+
expect(
|
|
27
|
+
screen.getByText('Mediterranean from Barcelona')
|
|
28
|
+
).toBeInTheDocument();
|
|
29
|
+
expect(screen.getByText('Oct 2025 - Oct 2025')).toBeInTheDocument();
|
|
30
|
+
expect(screen.getByText('Seven Days')).toBeInTheDocument();
|
|
31
|
+
expect(screen.getByText('Barcelona → Marseille')).toBeInTheDocument();
|
|
32
|
+
expect(screen.getByText('MSC Seaside')).toBeInTheDocument();
|
|
33
|
+
expect(screen.getByText('£2000')).toBeInTheDocument();
|
|
34
|
+
expect(screen.getByText('From')).toBeInTheDocument();
|
|
35
|
+
expect(screen.getByText('View Itinerary')).toBeInTheDocument();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('renders image with correct src and alt', () => {
|
|
39
|
+
render(<TripCard card={mockCard} />);
|
|
40
|
+
|
|
41
|
+
const image = screen.getByAltText('Mediterranean from Barcelona');
|
|
42
|
+
expect(image).toHaveAttribute('src', 'https://example.com/image.jpg');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('renders offer label when provided', () => {
|
|
46
|
+
const cardWithOffer = {
|
|
47
|
+
...mockCard,
|
|
48
|
+
offer_label: 'Special Offer'
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
render(<TripCard card={cardWithOffer} />);
|
|
52
|
+
|
|
53
|
+
expect(screen.getByText('Special Offer')).toBeInTheDocument();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('renders gift banner when provided', () => {
|
|
57
|
+
const cardWithGift = {
|
|
58
|
+
...mockCard,
|
|
59
|
+
gift_banner: 'Free gift with purchase'
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
render(<TripCard card={cardWithGift} />);
|
|
63
|
+
|
|
64
|
+
expect(screen.getByText('Free gift with purchase')).toBeInTheDocument();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('renders original price when provided', () => {
|
|
68
|
+
const cardWithOriginalPrice = {
|
|
69
|
+
...mockCard,
|
|
70
|
+
original_price: '£2500'
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
render(<TripCard card={cardWithOriginalPrice} />);
|
|
74
|
+
|
|
75
|
+
expect(screen.getByText('£2500')).toBeInTheDocument();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('does not render "From" when price is "Enquire now"', () => {
|
|
79
|
+
const cardWithEnquire = {
|
|
80
|
+
...mockCard,
|
|
81
|
+
price: 'Enquire now'
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
render(<TripCard card={cardWithEnquire} />);
|
|
85
|
+
|
|
86
|
+
expect(screen.queryByText('From')).not.toBeInTheDocument();
|
|
87
|
+
expect(screen.getByText('Enquire now')).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('renders all CTA links with correct href and target', () => {
|
|
91
|
+
render(<TripCard card={mockCard} />);
|
|
92
|
+
|
|
93
|
+
const links = screen.getAllByRole('link');
|
|
94
|
+
const imageLink = links[0];
|
|
95
|
+
const headlineLink = links[1];
|
|
96
|
+
const ctaButton = screen.getByText('View Itinerary').closest('a');
|
|
97
|
+
|
|
98
|
+
expect(imageLink).toHaveAttribute('href', 'https://example.com/cruise');
|
|
99
|
+
expect(imageLink).toHaveAttribute('target', '_blank');
|
|
100
|
+
expect(headlineLink).toHaveAttribute('href', 'https://example.com/cruise');
|
|
101
|
+
expect(ctaButton).toHaveAttribute('href', 'https://example.com/cruise');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('renders logo with link when provided', () => {
|
|
105
|
+
render(<TripCard card={mockCard} />);
|
|
106
|
+
const logoLink = screen.getByRole('link', { name: /partner logo/i });
|
|
107
|
+
expect(logoLink).toHaveAttribute('href', 'https://example.com');
|
|
108
|
+
const logoImg = screen.getByAltText('Partner logo');
|
|
109
|
+
expect(logoImg).toHaveAttribute('src', 'https://example.com/logo.png');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('shows card image after it loads', () => {
|
|
113
|
+
render(<TripCard card={mockCard} />);
|
|
114
|
+
|
|
115
|
+
const cardImage = screen.getByAltText('Mediterranean from Barcelona');
|
|
116
|
+
expect(cardImage).toHaveStyle({ display: 'none' });
|
|
117
|
+
fireEvent.load(cardImage);
|
|
118
|
+
expect(cardImage).toHaveStyle({ display: 'block' });
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -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
|
+
});
|