@playpilot/tpi 7.3.0 → 8.0.0-beta.explore-home.3
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/.env +1 -0
- package/dist/editorial.mount.js +9 -9
- package/dist/link-injections.js +1 -1
- package/dist/mount.js +8 -8
- package/events.md +1 -5
- package/package.json +1 -1
- package/src/lib/api/youtubeAvailability.ts +26 -0
- package/src/lib/enums/TrackingEvent.ts +1 -0
- package/src/lib/explore.ts +3 -21
- package/src/lib/modal.ts +3 -3
- package/src/lib/trailer.ts +31 -0
- package/src/lib/types/config.d.ts +0 -1
- package/src/lib/types/explore.d.ts +5 -0
- package/src/routes/components/Button.svelte +2 -1
- package/src/routes/components/Explore/ExploreLayout.svelte +102 -0
- package/src/routes/components/Explore/ExploreModal.svelte +2 -2
- package/src/routes/components/Explore/ExploreRouter.svelte +35 -0
- package/src/routes/components/Explore/Routes/ExploreHome.svelte +23 -0
- package/src/routes/components/Explore/{Explore.svelte → Routes/ExploreResults.svelte} +46 -115
- package/src/routes/components/Rails/TitlesRail.svelte +125 -14
- package/src/routes/components/Title.svelte +27 -11
- package/src/routes/components/TitleModal.svelte +2 -2
- package/src/routes/components/YouTubeEmbed.svelte +36 -0
- package/src/routes/components/YouTubeEmbedBackground.svelte +34 -0
- package/src/routes/components/YouTubeEmbedOverlay.svelte +14 -29
- package/src/routes/elements/+page.svelte +12 -2
- package/src/routes/explore/+page.svelte +1 -2
- package/src/tests/lib/api/youtubeAvailability.test.js +70 -0
- package/src/tests/lib/explore.test.js +1 -38
- package/src/tests/lib/trailer.test.js +57 -1
- package/src/tests/routes/components/Explore/ExploreLayout.test.js +52 -0
- package/src/tests/routes/components/Explore/ExploreRouter.test.js +20 -0
- package/src/tests/routes/components/Explore/Routes/ExploreHome.test.js +18 -0
- package/src/tests/routes/components/Explore/{Explore.test.js → Routes/ExploreResults.test.js} +29 -22
- package/src/tests/routes/components/Rails/TitlesRail.test.js +79 -2
- package/src/tests/routes/components/Title.test.js +35 -0
- package/src/tests/routes/components/YouTubeEmbed.test.js +38 -0
- package/src/tests/routes/components/YouTubeEmbedBackground.test.js +13 -0
- package/src/tests/routes/components/YouTubeEmbedOverlay.test.js +1 -8
- package/vite._main.config.js +0 -1
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
2
2
|
import { title } from '$lib/fakeData'
|
|
3
3
|
import { mount, unmount } from 'svelte'
|
|
4
|
-
import { closeTrailerOverlay, openTrailerOverlay } from '$lib/trailer'
|
|
4
|
+
import { closeTrailerOverlay, getFirstTitleWithAvailableTrailer, getVideoId, openTrailerOverlay } from '$lib/trailer'
|
|
5
|
+
import { isYouTubeVideoAvailableInRegion } from '$lib/api/youtubeAvailability'
|
|
5
6
|
|
|
6
7
|
vi.mock('svelte', () => ({
|
|
7
8
|
mount: vi.fn(),
|
|
8
9
|
unmount: vi.fn(),
|
|
9
10
|
}))
|
|
10
11
|
|
|
12
|
+
vi.mock('$lib/api/youtubeAvailability', () => ({
|
|
13
|
+
isYouTubeVideoAvailableInRegion: vi.fn(),
|
|
14
|
+
}))
|
|
15
|
+
|
|
11
16
|
const titleWithTrailer = { ...title, embeddable_url: 'abc' }
|
|
12
17
|
|
|
13
18
|
describe('modal.js', () => {
|
|
@@ -50,4 +55,55 @@ describe('modal.js', () => {
|
|
|
50
55
|
expect(unmount).not.toHaveBeenCalled()
|
|
51
56
|
})
|
|
52
57
|
})
|
|
58
|
+
|
|
59
|
+
describe('getVideoId', () => {
|
|
60
|
+
it('Should return video id for various youtube formats', () => {
|
|
61
|
+
expect(getVideoId('youtube.com/watch?v=a')).toBe('a')
|
|
62
|
+
expect(getVideoId('youtu.be/b')).toBe('b')
|
|
63
|
+
expect(getVideoId('youtube.com/embed/c')).toBe('c')
|
|
64
|
+
expect(getVideoId('not')).toBe(null)
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
describe('getFirstTitleWithAvailableTrailer', () => {
|
|
69
|
+
it('Should return null if no titles are given', async () => {
|
|
70
|
+
expect(await getFirstTitleWithAvailableTrailer([])).toBe(null)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('Should return first title if it has a valid video id and video is available', async () => {
|
|
74
|
+
vi.mocked(isYouTubeVideoAvailableInRegion).mockResolvedValueOnce(true)
|
|
75
|
+
|
|
76
|
+
const titles = [{ ...title, embeddable_url: 'youtu.be/a' }]
|
|
77
|
+
|
|
78
|
+
expect(await getFirstTitleWithAvailableTrailer(titles)).toBe(titles[0])
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('Should not return first title if it has a valid video id and but video is not available', async () => {
|
|
82
|
+
vi.mocked(isYouTubeVideoAvailableInRegion).mockResolvedValueOnce(false)
|
|
83
|
+
|
|
84
|
+
expect(await getFirstTitleWithAvailableTrailer([{ ...title, embeddable_url: 'youtu.be/a' }])).toBe(null)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('Should not return first title if it has no valid video id', async () => {
|
|
88
|
+
vi.mocked(isYouTubeVideoAvailableInRegion).mockResolvedValueOnce(false)
|
|
89
|
+
|
|
90
|
+
expect(await getFirstTitleWithAvailableTrailer([title])).toBe(null)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('Should return second title if first is not valid', async () => {
|
|
94
|
+
vi.mocked(isYouTubeVideoAvailableInRegion).mockResolvedValueOnce(false).mockResolvedValueOnce(true)
|
|
95
|
+
|
|
96
|
+
const titles = [{ ...title, embeddable_url: 'youtu.be/a' }, { ...title, embeddable_url: 'youtu.be/b' }]
|
|
97
|
+
|
|
98
|
+
expect(await getFirstTitleWithAvailableTrailer(titles)).toBe(titles[1])
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('Should return second title if first rejects', async () => {
|
|
102
|
+
vi.mocked(isYouTubeVideoAvailableInRegion).mockRejectedValueOnce(null).mockResolvedValueOnce(true)
|
|
103
|
+
|
|
104
|
+
const titles = [{ ...title, embeddable_url: 'youtu.be/a' }, { ...title, embeddable_url: 'youtu.be/b' }]
|
|
105
|
+
|
|
106
|
+
expect(await getFirstTitleWithAvailableTrailer(titles)).toBe(titles[1])
|
|
107
|
+
})
|
|
108
|
+
})
|
|
53
109
|
})
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { fireEvent, render, waitFor } from '@testing-library/svelte'
|
|
2
|
+
import { expect, describe, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import ExploreLayout from '../../../../routes/components/Explore/ExploreLayout.svelte'
|
|
5
|
+
import { createRawSnippet } from 'svelte'
|
|
6
|
+
import { exploreParentSelector } from '$lib/explore'
|
|
7
|
+
|
|
8
|
+
const children = createRawSnippet(() => ({ render: () => '<div></div>' }))
|
|
9
|
+
|
|
10
|
+
const routes = [
|
|
11
|
+
{
|
|
12
|
+
key: 'route-1',
|
|
13
|
+
label: 'Route 1',
|
|
14
|
+
component: {},
|
|
15
|
+
}, {
|
|
16
|
+
key: 'route-2',
|
|
17
|
+
label: 'Route 2',
|
|
18
|
+
component: {},
|
|
19
|
+
},
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
describe('ExploreLayout.svelte', () => {
|
|
23
|
+
it('Should render each given route', () => {
|
|
24
|
+
const { getByText } = render(ExploreLayout, { routes, currentRoute: routes[0], children })
|
|
25
|
+
|
|
26
|
+
expect(getByText('Route 1')).toBeTruthy()
|
|
27
|
+
expect(getByText('Route 2')).toBeTruthy()
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('Should call navigate when route is clicked', async () => {
|
|
31
|
+
const navigate = vi.fn()
|
|
32
|
+
const { getByText } = render(ExploreLayout, { routes, currentRoute: routes[0], navigate, children })
|
|
33
|
+
|
|
34
|
+
await fireEvent.click(getByText('Route 2'))
|
|
35
|
+
|
|
36
|
+
expect(navigate).toHaveBeenCalledWith(routes[1])
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('Should should set its height if parent has height', async () => {
|
|
40
|
+
document.body.innerHTML = '<div data-playpilot-explore style="height: 500px"></div>'
|
|
41
|
+
|
|
42
|
+
const { container } = render(
|
|
43
|
+
ExploreLayout,
|
|
44
|
+
{ routes, currentRoute: routes[0], children },
|
|
45
|
+
{ baseElement: /** @type {HTMLElement} */ (document.querySelector(exploreParentSelector)),
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
await waitFor(() => {
|
|
49
|
+
expect(container.querySelector('.explore')?.getAttribute('style')).toBe('height: 500px;')
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/svelte'
|
|
2
|
+
import { expect, describe, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import ExploreRouter from '../../../../routes/components/Explore/ExploreRouter.svelte'
|
|
5
|
+
|
|
6
|
+
describe('ExploreRouter.svelte', () => {
|
|
7
|
+
it('Should render home by default', () => {
|
|
8
|
+
const { getByTestId } = render(ExploreRouter)
|
|
9
|
+
|
|
10
|
+
expect(getByTestId('explore-home')).toBeTruthy()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('Should render results on click of button', async () => {
|
|
14
|
+
const { getByText, getByTestId } = render(ExploreRouter)
|
|
15
|
+
|
|
16
|
+
await fireEvent.click(getByText('Explore'))
|
|
17
|
+
|
|
18
|
+
expect(getByTestId('explore-results')).toBeTruthy()
|
|
19
|
+
})
|
|
20
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { render } from '@testing-library/svelte'
|
|
2
|
+
import { beforeEach, describe, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import ExploreHome from '../../../../../routes/components/Explore/Routes/ExploreHome.svelte'
|
|
5
|
+
|
|
6
|
+
vi.mock('$lib/api/titles', () => ({
|
|
7
|
+
fetchSimilarTitles: vi.fn(),
|
|
8
|
+
}))
|
|
9
|
+
|
|
10
|
+
describe('ExploreResults.svelte', () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
vi.resetAllMocks()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('Should do nothing yet, this is a placeholder', () => {
|
|
16
|
+
render(ExploreHome)
|
|
17
|
+
})
|
|
18
|
+
})
|
package/src/tests/routes/components/Explore/{Explore.test.js → Routes/ExploreResults.test.js}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { render, fireEvent, waitFor } from '@testing-library/svelte'
|
|
2
2
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import ExploreResults from '../../../../../routes/components/Explore/Routes/ExploreResults.svelte'
|
|
5
5
|
import { fetchTitles } from '$lib/api/titles'
|
|
6
6
|
import { title } from '$lib/fakeData'
|
|
7
7
|
import { TrackingEvent } from '$lib/enums/TrackingEvent'
|
|
@@ -24,7 +24,7 @@ vi.mock('$lib/api/ads', () => ({
|
|
|
24
24
|
fetchAds: vi.fn(),
|
|
25
25
|
}))
|
|
26
26
|
|
|
27
|
-
describe('
|
|
27
|
+
describe('ExploreResults.svelte', () => {
|
|
28
28
|
beforeEach(() => {
|
|
29
29
|
// @ts-ignore
|
|
30
30
|
window.PlayPilotLinkInjections = {}
|
|
@@ -33,13 +33,13 @@ describe('Explore.svelte', () => {
|
|
|
33
33
|
})
|
|
34
34
|
|
|
35
35
|
it('Should call fetchTitles on mount', () => {
|
|
36
|
-
render(
|
|
36
|
+
render(ExploreResults)
|
|
37
37
|
|
|
38
38
|
expect(fetchTitles).toHaveBeenCalledWith({ page_size: 24, page: 1 })
|
|
39
39
|
})
|
|
40
40
|
|
|
41
41
|
it('Should call tracking event and fetchAds on mount', () => {
|
|
42
|
-
render(
|
|
42
|
+
render(ExploreResults)
|
|
43
43
|
|
|
44
44
|
expect(track).toHaveBeenCalledWith(TrackingEvent.ExplorePageView)
|
|
45
45
|
expect(fetchAds).toHaveBeenCalled()
|
|
@@ -52,7 +52,7 @@ describe('Explore.svelte', () => {
|
|
|
52
52
|
ads: ['a'],
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
render(
|
|
55
|
+
render(ExploreResults)
|
|
56
56
|
|
|
57
57
|
expect(fetchAds).not.toHaveBeenCalled()
|
|
58
58
|
})
|
|
@@ -60,7 +60,7 @@ describe('Explore.svelte', () => {
|
|
|
60
60
|
it('Should render all returned titles', async () => {
|
|
61
61
|
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title, title, title], next: null, previous: null })
|
|
62
62
|
|
|
63
|
-
const { getAllByText } = render(
|
|
63
|
+
const { getAllByText } = render(ExploreResults)
|
|
64
64
|
|
|
65
65
|
await waitFor(() => {
|
|
66
66
|
expect(getAllByText(title.title)).toHaveLength(3)
|
|
@@ -70,7 +70,7 @@ describe('Explore.svelte', () => {
|
|
|
70
70
|
it('Should not render Show more button when no next value is given', async () => {
|
|
71
71
|
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title], next: null, previous: null })
|
|
72
72
|
|
|
73
|
-
const { getByText, queryByText } = render(
|
|
73
|
+
const { getByText, queryByText } = render(ExploreResults)
|
|
74
74
|
|
|
75
75
|
await waitFor(() => getByText(title.title))
|
|
76
76
|
|
|
@@ -80,7 +80,7 @@ describe('Explore.svelte', () => {
|
|
|
80
80
|
it('Should render Show more button when next value is given', async () => {
|
|
81
81
|
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title], next: 'truthy', previous: null })
|
|
82
82
|
|
|
83
|
-
const { getByText } = render(
|
|
83
|
+
const { getByText } = render(ExploreResults)
|
|
84
84
|
|
|
85
85
|
await waitFor(() => {
|
|
86
86
|
expect(getByText('Show more')).toBeTruthy()
|
|
@@ -90,7 +90,7 @@ describe('Explore.svelte', () => {
|
|
|
90
90
|
it('Should fire fetchTitles again with incremented page number when show more is clicked and render the given titles', async () => {
|
|
91
91
|
vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
|
|
92
92
|
|
|
93
|
-
const { getByText, getAllByText } = render(
|
|
93
|
+
const { getByText, getAllByText } = render(ExploreResults)
|
|
94
94
|
|
|
95
95
|
await waitFor(() => fireEvent.click(getByText('Show more')))
|
|
96
96
|
|
|
@@ -104,7 +104,7 @@ describe('Explore.svelte', () => {
|
|
|
104
104
|
it('Should fire tracking event when show more is clicked', async () => {
|
|
105
105
|
vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
|
|
106
106
|
|
|
107
|
-
const { getByText } = render(
|
|
107
|
+
const { getByText } = render(ExploreResults)
|
|
108
108
|
|
|
109
109
|
await waitFor(() => fireEvent.click(getByText('Show more')))
|
|
110
110
|
|
|
@@ -114,7 +114,7 @@ describe('Explore.svelte', () => {
|
|
|
114
114
|
it('Should render skeletons while loading', async () => {
|
|
115
115
|
vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
|
|
116
116
|
|
|
117
|
-
const { getAllByTestId, queryByTestId, getByText } = render(
|
|
117
|
+
const { getAllByTestId, queryByTestId, getByText } = render(ExploreResults)
|
|
118
118
|
|
|
119
119
|
expect(getAllByTestId('skeleton')).toHaveLength(24)
|
|
120
120
|
|
|
@@ -126,7 +126,7 @@ describe('Explore.svelte', () => {
|
|
|
126
126
|
it('Should call fetchTitles with string of comma separated values when filtering with array value', async () => {
|
|
127
127
|
vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
|
|
128
128
|
|
|
129
|
-
const { getByText } = render(
|
|
129
|
+
const { getByText } = render(ExploreResults)
|
|
130
130
|
|
|
131
131
|
await fireEvent.click(getByText('Genres'))
|
|
132
132
|
await fireEvent.click(getByText('Action'))
|
|
@@ -137,16 +137,23 @@ describe('Explore.svelte', () => {
|
|
|
137
137
|
})
|
|
138
138
|
|
|
139
139
|
it('Should include search param when query is given', async () => {
|
|
140
|
-
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title
|
|
140
|
+
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title], next: 'truthy', previous: null })
|
|
141
|
+
|
|
142
|
+
const { getAllByTestId } = render(ExploreResults, { searchQuery: 'some query' })
|
|
141
143
|
|
|
142
|
-
|
|
144
|
+
await waitFor(() => {
|
|
145
|
+
expect(fetchTitles).toHaveBeenCalledWith({ page: 1, page_size: 24, search: 'some query' })
|
|
146
|
+
expect(getAllByTestId('title')).toHaveLength(1)
|
|
147
|
+
})
|
|
148
|
+
})
|
|
143
149
|
|
|
150
|
+
it('Should include search param when query is empty', async () => {
|
|
144
151
|
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title], next: 'truthy', previous: null })
|
|
145
152
|
|
|
146
|
-
|
|
153
|
+
const { getAllByTestId } = render(ExploreResults, { searchQuery: '' })
|
|
147
154
|
|
|
148
155
|
await waitFor(() => {
|
|
149
|
-
expect(fetchTitles).toHaveBeenCalledWith(
|
|
156
|
+
expect(fetchTitles).toHaveBeenCalledWith(expect.not.stringContaining('search'))
|
|
150
157
|
expect(getAllByTestId('title')).toHaveLength(1)
|
|
151
158
|
})
|
|
152
159
|
})
|
|
@@ -154,7 +161,7 @@ describe('Explore.svelte', () => {
|
|
|
154
161
|
it('Should call fetchTitles with min and max values when filtering with range value', async () => {
|
|
155
162
|
vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
|
|
156
163
|
|
|
157
|
-
const { container, getByText } = render(
|
|
164
|
+
const { container, getByText } = render(ExploreResults)
|
|
158
165
|
|
|
159
166
|
await fireEvent.click(getByText('IMDb'))
|
|
160
167
|
// @ts-ignore
|
|
@@ -168,7 +175,7 @@ describe('Explore.svelte', () => {
|
|
|
168
175
|
it('Should call fetchTitles with multiple values when given', async () => {
|
|
169
176
|
vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
|
|
170
177
|
|
|
171
|
-
const { container, getByText } = render(
|
|
178
|
+
const { container, getByText } = render(ExploreResults)
|
|
172
179
|
|
|
173
180
|
await fireEvent.click(getByText('Genres'))
|
|
174
181
|
await fireEvent.click(getByText('Action'))
|
|
@@ -186,7 +193,7 @@ describe('Explore.svelte', () => {
|
|
|
186
193
|
it('Should call fetchTitles with string for sorting when sorting is used', async () => {
|
|
187
194
|
vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
|
|
188
195
|
|
|
189
|
-
const { getByText } = render(
|
|
196
|
+
const { getByText } = render(ExploreResults)
|
|
190
197
|
|
|
191
198
|
await fireEvent.click(getByText('Sort by'))
|
|
192
199
|
await fireEvent.click(getByText('New'))
|
|
@@ -197,7 +204,7 @@ describe('Explore.svelte', () => {
|
|
|
197
204
|
it('Should show empty message if no titles are returned for first page', async () => {
|
|
198
205
|
vi.mocked(fetchTitles).mockResolvedValue({ results: [], next: null, previous: null })
|
|
199
206
|
|
|
200
|
-
const { getByText } = render(
|
|
207
|
+
const { getByText } = render(ExploreResults)
|
|
201
208
|
|
|
202
209
|
await waitFor(() => {
|
|
203
210
|
expect(getByText('No results were found')).toBeTruthy()
|
|
@@ -207,7 +214,7 @@ describe('Explore.svelte', () => {
|
|
|
207
214
|
it('Should not show empty message if no titles are returned for pages past the first page', async () => {
|
|
208
215
|
vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
|
|
209
216
|
|
|
210
|
-
const { getByText, queryByText } = render(
|
|
217
|
+
const { getByText, queryByText } = render(ExploreResults)
|
|
211
218
|
|
|
212
219
|
await waitFor(() => getByText('Show more'))
|
|
213
220
|
|
|
@@ -223,7 +230,7 @@ describe('Explore.svelte', () => {
|
|
|
223
230
|
it('Should show error message if api responded with error', async () => {
|
|
224
231
|
vi.mocked(fetchTitles).mockRejectedValueOnce(null)
|
|
225
232
|
|
|
226
|
-
const { getByText } = render(
|
|
233
|
+
const { getByText } = render(ExploreResults)
|
|
227
234
|
|
|
228
235
|
await waitFor(() => {
|
|
229
236
|
expect(getByText('Something went wrong')).toBeTruthy()
|
|
@@ -4,17 +4,23 @@ import { describe, expect, it, vi } from 'vitest'
|
|
|
4
4
|
import TitlesRail from '../../../../routes/components/Rails/TitlesRail.svelte'
|
|
5
5
|
import { title } from '$lib/fakeData'
|
|
6
6
|
import { openModal } from '$lib/modal'
|
|
7
|
+
import { getFirstTitleWithAvailableTrailer } from '$lib/trailer'
|
|
7
8
|
|
|
8
9
|
vi.mock('$lib/modal', () => ({
|
|
9
10
|
openModal: vi.fn(),
|
|
10
11
|
}))
|
|
11
12
|
|
|
13
|
+
vi.mock('$lib/trailer', () => ({
|
|
14
|
+
getFirstTitleWithAvailableTrailer: vi.fn(),
|
|
15
|
+
getVideoId: vi.fn(),
|
|
16
|
+
}))
|
|
17
|
+
|
|
12
18
|
describe('TitlesRail.svelte', () => {
|
|
13
19
|
it('Should show loading state while promise is resolving', async () => {
|
|
14
20
|
// @ts-ignore
|
|
15
21
|
const { queryAllByTestId } = render(TitlesRail, { titles: new Promise(res => setTimeout(res, 100)) })
|
|
16
22
|
|
|
17
|
-
expect(queryAllByTestId('skeleton')).toHaveLength(
|
|
23
|
+
expect(queryAllByTestId('skeleton')).toHaveLength(12)
|
|
18
24
|
|
|
19
25
|
await waitFor(() => {
|
|
20
26
|
expect(queryAllByTestId('skeleton')).toHaveLength(0)
|
|
@@ -33,7 +39,7 @@ describe('TitlesRail.svelte', () => {
|
|
|
33
39
|
|
|
34
40
|
await fireEvent.click(getAllByRole('link')[0])
|
|
35
41
|
|
|
36
|
-
expect(openModal).toHaveBeenCalledWith({ event: expect.any(Object), data: title, returnToTitle: null })
|
|
42
|
+
expect(openModal).toHaveBeenCalledWith({ event: expect.any(Object), data: title, returnToTitle: null, props: { useVideoBackground: false } })
|
|
37
43
|
})
|
|
38
44
|
|
|
39
45
|
it('Should fire given onclick function when title is clicked', async () => {
|
|
@@ -44,4 +50,75 @@ describe('TitlesRail.svelte', () => {
|
|
|
44
50
|
|
|
45
51
|
expect(onclick).toHaveBeenCalledWith(title)
|
|
46
52
|
})
|
|
53
|
+
|
|
54
|
+
it('Should expand first title if expandable is true', async () => {
|
|
55
|
+
vi.mocked(getFirstTitleWithAvailableTrailer).mockResolvedValueOnce(title)
|
|
56
|
+
|
|
57
|
+
const { getByTestId } = render(TitlesRail, { titles: [{ ...title, embeddable_url: 'some-url' }], expandable: true })
|
|
58
|
+
|
|
59
|
+
expect(getByTestId('title').classList).not.toContain('expanded')
|
|
60
|
+
|
|
61
|
+
await new Promise(res => setTimeout(res, 1000))
|
|
62
|
+
|
|
63
|
+
expect(getByTestId('title').classList).toContain('expanded')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('Should not expand first title if expandable is not true', async () => {
|
|
67
|
+
const { getByTestId } = render(TitlesRail, { titles: [{ ...title, embeddable_url: 'some-url' }] })
|
|
68
|
+
|
|
69
|
+
expect(getByTestId('title').classList).not.toContain('expanded')
|
|
70
|
+
|
|
71
|
+
await new Promise(res => setTimeout(res, 1000))
|
|
72
|
+
|
|
73
|
+
expect(getByTestId('title').classList).not.toContain('expanded')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('Should not expand first title if it has no embeddable_url', async () => {
|
|
77
|
+
const { getByTestId } = render(TitlesRail, { titles: [title] })
|
|
78
|
+
|
|
79
|
+
expect(getByTestId('title').classList).not.toContain('expanded')
|
|
80
|
+
|
|
81
|
+
await new Promise(res => setTimeout(res, 1000))
|
|
82
|
+
|
|
83
|
+
expect(getByTestId('title').classList).not.toContain('expanded')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('Should expand second title if expandable is true but first title has no trailer', async () => {
|
|
87
|
+
const titles = [{ ...title }, { ...title, sid: 'some-other-sid', embeddable_url: 'some-url' }]
|
|
88
|
+
vi.mocked(getFirstTitleWithAvailableTrailer).mockResolvedValueOnce(titles[1])
|
|
89
|
+
|
|
90
|
+
const { getAllByTestId } = render(TitlesRail, { titles, expandable: true })
|
|
91
|
+
|
|
92
|
+
expect(getAllByTestId('title')[1].classList).not.toContain('expanded')
|
|
93
|
+
|
|
94
|
+
await new Promise(res => setTimeout(res, 1000))
|
|
95
|
+
|
|
96
|
+
expect(getAllByTestId('title')[1].classList).toContain('expanded')
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('Should expand second title and contract first when clicked', async () => {
|
|
100
|
+
const titles = [{ ...title }, { ...title, sid: 'some-other-sid' }]
|
|
101
|
+
|
|
102
|
+
const { getAllByTestId } = render(TitlesRail, { titles, expandable: true })
|
|
103
|
+
|
|
104
|
+
await fireEvent.click(getAllByTestId('heading')[1])
|
|
105
|
+
|
|
106
|
+
expect(getAllByTestId('title')[1].classList).toContain('expanded')
|
|
107
|
+
expect(getAllByTestId('title')[0].classList).not.toContain('expanded')
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('Should only open title when clicked while expanded', async () => {
|
|
111
|
+
const titles = [{ ...title }, { ...title, sid: 'some-other-sid' }]
|
|
112
|
+
|
|
113
|
+
const onclick = vi.fn()
|
|
114
|
+
const { getAllByTestId } = render(TitlesRail, { titles, expandable: true, onclick })
|
|
115
|
+
|
|
116
|
+
await fireEvent.click(getAllByTestId('heading')[1])
|
|
117
|
+
expect(onclick).not.toHaveBeenCalled()
|
|
118
|
+
|
|
119
|
+
await fireEvent.click(getAllByTestId('heading')[1])
|
|
120
|
+
expect(onclick).toHaveBeenCalled()
|
|
121
|
+
|
|
122
|
+
expect(openModal).toHaveBeenCalledWith(expect.objectContaining({ props: { useVideoBackground: false } }))
|
|
123
|
+
})
|
|
47
124
|
})
|
|
@@ -5,6 +5,7 @@ import Title from '../../../routes/components/Title.svelte'
|
|
|
5
5
|
import { title } from '$lib/fakeData'
|
|
6
6
|
import { fetchParticipantsForTitle } from '$lib/api/participants'
|
|
7
7
|
import { fetchSimilarTitles } from '$lib/api/titles'
|
|
8
|
+
import { isYouTubeVideoAvailableInRegion } from '$lib/api/youtubeAvailability'
|
|
8
9
|
|
|
9
10
|
vi.mock('$lib/tracking', () => ({
|
|
10
11
|
track: vi.fn(),
|
|
@@ -19,6 +20,10 @@ vi.mock('$lib/api/titles', () => ({
|
|
|
19
20
|
fetchSimilarTitles: vi.fn(),
|
|
20
21
|
}))
|
|
21
22
|
|
|
23
|
+
vi.mock('$lib/api/youtubeAvailability', () => ({
|
|
24
|
+
isYouTubeVideoAvailableInRegion: vi.fn(),
|
|
25
|
+
}))
|
|
26
|
+
|
|
22
27
|
vi.mock('svelte', async (importActual) => ({
|
|
23
28
|
...(await importActual()),
|
|
24
29
|
getContext: vi.fn(),
|
|
@@ -128,4 +133,34 @@ describe('Title.svelte', () => {
|
|
|
128
133
|
|
|
129
134
|
expect(getByText('Some description')).toBeTruthy()
|
|
130
135
|
})
|
|
136
|
+
|
|
137
|
+
it('Should render video background when useVideoBackground is true', async () => {
|
|
138
|
+
vi.mocked(isYouTubeVideoAvailableInRegion).mockResolvedValueOnce(true)
|
|
139
|
+
|
|
140
|
+
const { getByTestId } = render(Title, { title: { ...title, embeddable_url: 'https://youtu.be/abc' }, useVideoBackground: true })
|
|
141
|
+
|
|
142
|
+
await new Promise(res => setTimeout(res, 100))
|
|
143
|
+
|
|
144
|
+
expect(getByTestId('video-background')).toBeTruthy()
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('Should not render video background when useVideoBackground is true but title has no embeddable_url', async () => {
|
|
148
|
+
vi.mocked(isYouTubeVideoAvailableInRegion).mockResolvedValueOnce(true)
|
|
149
|
+
|
|
150
|
+
const { queryByTestId } = render(Title, { title, useVideoBackground: true })
|
|
151
|
+
|
|
152
|
+
await new Promise(res => setTimeout(res, 100))
|
|
153
|
+
|
|
154
|
+
expect(queryByTestId('video-background')).not.toBeTruthy()
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it('Should not render video background when useVideoBackground is true but youtube url is not available', async () => {
|
|
158
|
+
vi.mocked(isYouTubeVideoAvailableInRegion).mockResolvedValueOnce(false)
|
|
159
|
+
|
|
160
|
+
const { queryByTestId } = render(Title, { title: { ...title, embeddable_url: 'https://youtu.be/abc' }, useVideoBackground: true })
|
|
161
|
+
|
|
162
|
+
await new Promise(res => setTimeout(res, 100))
|
|
163
|
+
|
|
164
|
+
expect(queryByTestId('video-background')).not.toBeTruthy()
|
|
165
|
+
})
|
|
131
166
|
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { render } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import YouTubeEmbed from '../../../routes/components/YouTubeEmbed.svelte'
|
|
5
|
+
|
|
6
|
+
describe('YouTubeEmbed.svelte', () => {
|
|
7
|
+
it('Should render embed iframe with given video url and default options', () => {
|
|
8
|
+
const { container } = render(YouTubeEmbed, { embeddable_url: 'youtube.com/watch?v=abc' })
|
|
9
|
+
|
|
10
|
+
expect(/** @type {HTMLIFrameElement} */ (container.querySelector('iframe')).src).toBe('https://video.playpilot.net/?video_id=abc&color=fa548a&muted=false&loop=false&controls=&autoplay=true&playsinline=true')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('Should render embed iframe with given controls', () => {
|
|
14
|
+
const { container } = render(YouTubeEmbed, { embeddable_url: 'youtube.com/watch?v=abc', controls: ['fullscreen', 'mute'] })
|
|
15
|
+
|
|
16
|
+
expect(/** @type {HTMLIFrameElement} */ (container.querySelector('iframe')).src).toContain('&controls=fullscreen,mute')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('Should render embed iframe with muted if given', () => {
|
|
20
|
+
const { container } = render(YouTubeEmbed, { embeddable_url: 'youtube.com/watch?v=abc', muted: true })
|
|
21
|
+
|
|
22
|
+
expect(/** @type {HTMLIFrameElement} */ (container.querySelector('iframe')).src).toContain('&muted=true')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('Should render embed iframe with loop if given', () => {
|
|
26
|
+
const { container } = render(YouTubeEmbed, { embeddable_url: 'youtube.com/watch?v=abc', loop: true })
|
|
27
|
+
|
|
28
|
+
expect(/** @type {HTMLIFrameElement} */ (container.querySelector('iframe')).src).toContain('&loop=true')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
it('Should render error message if embeddable_url is invalid', () => {
|
|
33
|
+
const { container, getByText } = render(YouTubeEmbed, { embeddable_url: '-' })
|
|
34
|
+
|
|
35
|
+
expect(container.querySelector('iframe')).not.toBeTruthy()
|
|
36
|
+
expect(getByText('Something went wrong')).toBeTruthy()
|
|
37
|
+
})
|
|
38
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { render } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import YouTubeEmbedBackground from '../../../routes/components/YouTubeEmbedBackground.svelte'
|
|
5
|
+
|
|
6
|
+
describe('YouTubeEmbedBackground.svelte', () => {
|
|
7
|
+
it('Should render embed iframe with given video url', () => {
|
|
8
|
+
const { container } = render(YouTubeEmbedBackground, { embeddable_url: 'youtube.com/watch?v=abc' })
|
|
9
|
+
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
expect(container.querySelector('iframe').src).toBe('https://video.playpilot.net/?video_id=abc&color=fa548a&muted=true&loop=false&controls=&autoplay=true&playsinline=true')
|
|
12
|
+
})
|
|
13
|
+
})
|
|
@@ -8,14 +8,7 @@ describe('YouTubeEmbedOverlay.svelte', () => {
|
|
|
8
8
|
const { container } = render(YouTubeEmbedOverlay, { embeddable_url: 'youtube.com/watch?v=abc', onclose: () => null })
|
|
9
9
|
|
|
10
10
|
// @ts-ignore
|
|
11
|
-
expect(container.querySelector('iframe').src).toBe('https://video.playpilot.net/?video_id=abc&color=fa548a&
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
it('Should render error message if embeddable_url is invalid', () => {
|
|
15
|
-
const { container, getByText } = render(YouTubeEmbedOverlay, { embeddable_url: '-', onclose: () => null })
|
|
16
|
-
|
|
17
|
-
expect(container.querySelector('iframe')).not.toBeTruthy()
|
|
18
|
-
expect(getByText('Something went wrong')).toBeTruthy()
|
|
11
|
+
expect(container.querySelector('iframe').src).toBe('https://video.playpilot.net/?video_id=abc&color=fa548a&muted=false&loop=false&controls=current-time,fullscreen,mute,play,progress&autoplay=true&playsinline=true')
|
|
19
12
|
})
|
|
20
13
|
|
|
21
14
|
it('Should fire given onclose function on click of close button and backdrop', async () => {
|