@playpilot/tpi 5.32.0 → 5.33.0-beta.explore.1
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/link-injections.js +10 -11
- package/package.json +1 -1
- package/src/lib/api/titles.ts +13 -1
- package/src/lib/data/translations.ts +5 -0
- package/src/lib/explore.ts +26 -0
- package/src/lib/fakeData.ts +1 -0
- package/src/lib/images/titles-list.webp +0 -0
- package/src/lib/modal.ts +7 -6
- package/src/lib/trailer.ts +22 -0
- package/src/lib/types/api.d.ts +6 -0
- package/src/lib/types/title.d.ts +4 -1
- package/src/routes/+page.svelte +5 -1
- package/src/routes/components/Ads/TopScroll.svelte +4 -18
- package/src/routes/components/Button.svelte +73 -0
- package/src/routes/components/Explore/Explore.svelte +178 -0
- package/src/routes/components/Explore/ExploreCallToAction.svelte +58 -0
- package/src/routes/components/Explore/ExploreModal.svelte +15 -0
- package/src/routes/components/Explore/Filter.svelte +3 -0
- package/src/routes/components/Explore/Search.svelte +54 -0
- package/src/routes/components/Icons/IconClose.svelte +9 -1
- package/src/routes/components/Icons/IconPlay.svelte +3 -0
- package/src/routes/components/Icons/IconSearch.svelte +3 -0
- package/src/routes/components/ListTitle.svelte +3 -5
- package/src/routes/components/ListTitleSkeleton.svelte +42 -0
- package/src/routes/components/Modal.svelte +5 -23
- package/src/routes/components/ParticipantModal.svelte +1 -11
- package/src/routes/components/Share.svelte +5 -23
- package/src/routes/components/Title.svelte +22 -22
- package/src/routes/components/TitleModal.svelte +4 -1
- package/src/routes/components/Trailer.svelte +18 -0
- package/src/routes/components/YouTubeEmbedOverlay.svelte +96 -0
- package/src/routes/elements/+page.svelte +28 -1
- package/src/tests/lib/api/ads.test.js +0 -1
- package/src/tests/lib/api/titles.test.js +55 -0
- package/src/tests/lib/explore.test.js +49 -0
- package/src/tests/lib/trailer.test.js +56 -0
- package/src/tests/routes/components/Button.test.js +28 -0
- package/src/tests/routes/components/Explore/Explore.test.js +133 -0
- package/src/tests/routes/components/Explore/Search.test.js +26 -0
- package/src/tests/routes/components/Share.test.js +12 -12
- package/src/tests/routes/components/Title.test.js +13 -0
- package/src/tests/routes/components/Trailer.test.js +20 -0
- package/src/tests/routes/components/YouTubeEmbedOverlay.test.js +31 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { render, fireEvent, waitFor } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import Explore from '../../../../routes/components/Explore/Explore.svelte'
|
|
5
|
+
import { fetchTitles } from '$lib/api/titles'
|
|
6
|
+
import { title } from '$lib/fakeData'
|
|
7
|
+
import { searchTitles } from '$lib/api/search'
|
|
8
|
+
|
|
9
|
+
vi.mock('$lib/api/titles', () => ({
|
|
10
|
+
fetchTitles: vi.fn(),
|
|
11
|
+
}))
|
|
12
|
+
|
|
13
|
+
vi.mock('$lib/api/search', () => ({
|
|
14
|
+
searchTitles: vi.fn(),
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
describe('Explore.svelte', () => {
|
|
18
|
+
it('Should call fetchTitles on mount', () => {
|
|
19
|
+
render(Explore)
|
|
20
|
+
|
|
21
|
+
expect(fetchTitles).toHaveBeenCalledWith({ page_size: 24, page: 1 })
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('Should render all returned titles', async () => {
|
|
25
|
+
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title, title, title], next: null, previous: null })
|
|
26
|
+
|
|
27
|
+
const { getAllByText } = render(Explore)
|
|
28
|
+
|
|
29
|
+
await waitFor(() => {
|
|
30
|
+
expect(getAllByText(title.title)).toHaveLength(3)
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('Should not render Show more button when no next value is given', async () => {
|
|
35
|
+
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title], next: null, previous: null })
|
|
36
|
+
|
|
37
|
+
const { getByText, queryByText } = render(Explore)
|
|
38
|
+
|
|
39
|
+
await waitFor(() => getByText(title.title))
|
|
40
|
+
|
|
41
|
+
expect(queryByText('Show more')).not.toBeTruthy()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('Should render Show more button when next value is given', async () => {
|
|
45
|
+
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title], next: 'truthy', previous: null })
|
|
46
|
+
|
|
47
|
+
const { getByText } = render(Explore)
|
|
48
|
+
|
|
49
|
+
await waitFor(() => {
|
|
50
|
+
expect(getByText('Show more')).toBeTruthy()
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('Should fire fetchTitles again with incremented page number when show more is clicked and render the given titles', async () => {
|
|
55
|
+
vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
|
|
56
|
+
|
|
57
|
+
const { getByText, getAllByText } = render(Explore)
|
|
58
|
+
|
|
59
|
+
await waitFor(() => fireEvent.click(getByText('Show more')))
|
|
60
|
+
|
|
61
|
+
expect(fetchTitles).toHaveBeenCalledWith({ page_size: 24, page: 2 })
|
|
62
|
+
|
|
63
|
+
await waitFor(() => {
|
|
64
|
+
expect(getAllByText(title.title)).toHaveLength(2)
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('Should render skeletons while loading', async () => {
|
|
69
|
+
vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
|
|
70
|
+
|
|
71
|
+
const { getAllByTestId, queryByTestId, getByText } = render(Explore)
|
|
72
|
+
|
|
73
|
+
expect(getAllByTestId('skeleton')).toHaveLength(12)
|
|
74
|
+
|
|
75
|
+
await waitFor(() => fireEvent.click(getByText('Show more')))
|
|
76
|
+
|
|
77
|
+
expect(queryByTestId('skeleton')).not.toBeTruthy()
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('Should fetch using searchTitles when query is given, resetting previous titles', async () => {
|
|
81
|
+
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title, title], next: 'truthy', previous: null })
|
|
82
|
+
|
|
83
|
+
const { getByRole, getAllByTestId } = render(Explore)
|
|
84
|
+
|
|
85
|
+
vi.mocked(searchTitles).mockResolvedValueOnce([title])
|
|
86
|
+
|
|
87
|
+
fireEvent.input(getByRole('searchbox'), { target: { value: 'some query' } })
|
|
88
|
+
|
|
89
|
+
await waitFor(() => {
|
|
90
|
+
expect(searchTitles).toHaveBeenCalledWith('some query')
|
|
91
|
+
expect(getAllByTestId('title')).toHaveLength(1)
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('Should set filter with the given content type when clicked, resetting previous titles', async () => {
|
|
96
|
+
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title], next: null, previous: null })
|
|
97
|
+
|
|
98
|
+
const { getByText, getAllByTestId, getByTestId } = render(Explore)
|
|
99
|
+
|
|
100
|
+
await waitFor(() => getByTestId('title'))
|
|
101
|
+
|
|
102
|
+
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title, title], next: null, previous: null })
|
|
103
|
+
|
|
104
|
+
await fireEvent.click(getByText('Movies'))
|
|
105
|
+
|
|
106
|
+
expect(getByText('Movies').classList).toContain('active')
|
|
107
|
+
expect(fetchTitles).toHaveBeenCalledWith({ page_size: 24, page: 1, content_type: 'movie' })
|
|
108
|
+
|
|
109
|
+
await waitFor(() => {
|
|
110
|
+
expect(getAllByTestId('title')).toHaveLength(2)
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('Should reset titles but fetch without setting content_type when "all" content type is clicked', async () => {
|
|
115
|
+
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title], next: null, previous: null })
|
|
116
|
+
|
|
117
|
+
const { getByText, getAllByTestId, getByTestId } = render(Explore)
|
|
118
|
+
|
|
119
|
+
await waitFor(() => getByTestId('title'))
|
|
120
|
+
|
|
121
|
+
vi.resetAllMocks()
|
|
122
|
+
vi.mocked(fetchTitles).mockResolvedValueOnce({ results: [title, title], next: null, previous: null })
|
|
123
|
+
|
|
124
|
+
await fireEvent.click(getByText('All'))
|
|
125
|
+
|
|
126
|
+
expect(getByText('All').classList).toContain('active')
|
|
127
|
+
expect(fetchTitles).toHaveBeenCalledWith({ page_size: 24, page: 1 })
|
|
128
|
+
|
|
129
|
+
await waitFor(() => {
|
|
130
|
+
expect(getAllByTestId('title')).toHaveLength(2)
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { render, fireEvent } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import Search from '../../../../routes/components/Explore/Search.svelte'
|
|
5
|
+
|
|
6
|
+
describe('Search.svelte', () => {
|
|
7
|
+
it('Should fire given oninput event with the given query', () => {
|
|
8
|
+
const oninput = vi.fn()
|
|
9
|
+
|
|
10
|
+
const { getByRole } = render(Search, { oninput })
|
|
11
|
+
|
|
12
|
+
fireEvent.input(getByRole('searchbox'), { target: { value: 'some query' } })
|
|
13
|
+
|
|
14
|
+
expect(oninput).toHaveBeenCalledWith('some query')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('Should fire given oninput event even if value is empty', () => {
|
|
18
|
+
const oninput = vi.fn()
|
|
19
|
+
|
|
20
|
+
const { getByRole } = render(Search, { oninput })
|
|
21
|
+
|
|
22
|
+
fireEvent.input(getByRole('searchbox'), { target: { value: '' } })
|
|
23
|
+
|
|
24
|
+
expect(oninput).toHaveBeenCalledWith('')
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -16,57 +16,57 @@ vi.mock('$lib/tracking', () => ({
|
|
|
16
16
|
|
|
17
17
|
describe('Share.svelte', () => {
|
|
18
18
|
it('Should open context menu on click', async () => {
|
|
19
|
-
const {
|
|
19
|
+
const { getByText, queryByText } = render(Share, { title: 'Some title', url: 'some-url' })
|
|
20
20
|
|
|
21
21
|
expect(queryByText('Copy URL')).not.toBeTruthy()
|
|
22
22
|
expect(queryByText('Email')).not.toBeTruthy()
|
|
23
23
|
|
|
24
|
-
await fireEvent.click(
|
|
24
|
+
await fireEvent.click(getByText('Share'))
|
|
25
25
|
|
|
26
26
|
expect(queryByText('Copy URL')).toBeTruthy()
|
|
27
27
|
expect(queryByText('Email')).toBeTruthy()
|
|
28
28
|
})
|
|
29
29
|
|
|
30
30
|
it('Should close context menu on click of items', async () => {
|
|
31
|
-
const {
|
|
31
|
+
const { getByText, queryByText } = render(Share, { title: 'Some title', url: 'some-url' })
|
|
32
32
|
|
|
33
|
-
await fireEvent.click(
|
|
33
|
+
await fireEvent.click(getByText('Share'))
|
|
34
34
|
await fireEvent.click(getByText('Copy URL'))
|
|
35
35
|
|
|
36
36
|
expect(queryByText('Copy URL')).not.toBeTruthy()
|
|
37
37
|
})
|
|
38
38
|
|
|
39
39
|
it('Should close context menu on click of body', async () => {
|
|
40
|
-
const {
|
|
40
|
+
const { getByText, queryByText } = render(Share, { title: 'Some title', url: 'some-url' })
|
|
41
41
|
|
|
42
|
-
await fireEvent.click(
|
|
42
|
+
await fireEvent.click(getByText('Share'))
|
|
43
43
|
await fireEvent.click(document.body)
|
|
44
44
|
|
|
45
45
|
expect(queryByText('Copy URL')).not.toBeTruthy()
|
|
46
46
|
})
|
|
47
47
|
|
|
48
48
|
it('Should fire copyToClipboard on click of button', async () => {
|
|
49
|
-
const {
|
|
49
|
+
const { getByText } = render(Share, { title: 'Some title', url: 'some-url' })
|
|
50
50
|
|
|
51
|
-
await fireEvent.click(
|
|
51
|
+
await fireEvent.click(getByText('Share'))
|
|
52
52
|
await fireEvent.click(getByText('Copy URL'))
|
|
53
53
|
|
|
54
54
|
expect(copyToClipboard).toHaveBeenCalledWith('some-url?utm_source=tpi')
|
|
55
55
|
})
|
|
56
56
|
|
|
57
57
|
it('Should fire track function on click of copy URL button', async () => {
|
|
58
|
-
const {
|
|
58
|
+
const { getByText } = render(Share, { title: 'Some title', url: 'some-url' })
|
|
59
59
|
|
|
60
|
-
await fireEvent.click(
|
|
60
|
+
await fireEvent.click(getByText('Share'))
|
|
61
61
|
await fireEvent.click(getByText('Copy URL'))
|
|
62
62
|
|
|
63
63
|
expect(track).toHaveBeenCalledWith(TrackingEvent.ShareTitle, null, { title: 'Some title', url: 'http://localhost:3000/', method: 'copy' })
|
|
64
64
|
})
|
|
65
65
|
|
|
66
66
|
it('Should fire track function on click of email button', async () => {
|
|
67
|
-
const {
|
|
67
|
+
const { getByText } = render(Share, { title: 'Some title', url: 'some-url' })
|
|
68
68
|
|
|
69
|
-
await fireEvent.click(
|
|
69
|
+
await fireEvent.click(getByText('Share'))
|
|
70
70
|
await fireEvent.click(getByText('Email'))
|
|
71
71
|
|
|
72
72
|
expect(track).toHaveBeenCalledWith(TrackingEvent.ShareTitle, null, { title: 'Some title', url: 'http://localhost:3000/', method: 'email' })
|
|
@@ -91,4 +91,17 @@ describe('Title.svelte', () => {
|
|
|
91
91
|
expect(fetchParticipantsForTitle).toHaveBeenCalled()
|
|
92
92
|
expect(fetchSimilarTitles).toHaveBeenCalled()
|
|
93
93
|
})
|
|
94
|
+
|
|
95
|
+
it('Should show trailer button when embeddable_url is given', () => {
|
|
96
|
+
const { getByText } = render(Title, { title: { ...title, embeddable_url: 'some-url' } })
|
|
97
|
+
|
|
98
|
+
expect(getByText('Watch trailer')).toBeTruthy()
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
// Temporarily disabled while button is always visible
|
|
102
|
+
// it('Should not show trailer button when embeddable_url is not given', () => {
|
|
103
|
+
// const { queryByText } = render(Title, { title })
|
|
104
|
+
|
|
105
|
+
// expect(queryByText('Watch Trailer')).not.toBeTruthy()
|
|
106
|
+
// })
|
|
94
107
|
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { render, fireEvent } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import Trailer from '../../../routes/components/Trailer.svelte'
|
|
5
|
+
import { title } from '$lib/fakeData'
|
|
6
|
+
import { openTrailerOverlay } from '$lib/trailer'
|
|
7
|
+
|
|
8
|
+
vi.mock('$lib/trailer', () => ({
|
|
9
|
+
openTrailerOverlay: vi.fn(),
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
describe('Trailer.svelte', () => {
|
|
13
|
+
it('Should fire given onclick function with given title on click', async () => {
|
|
14
|
+
const { getByRole } = render(Trailer, { title })
|
|
15
|
+
|
|
16
|
+
await fireEvent.click(getByRole('button'))
|
|
17
|
+
|
|
18
|
+
expect(openTrailerOverlay).toHaveBeenCalledWith(title)
|
|
19
|
+
})
|
|
20
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import YouTubeEmbedOverlay from '../../../routes/components/YouTubeEmbedOverlay.svelte'
|
|
5
|
+
|
|
6
|
+
describe('YouTubeEmbedOverlay.svelte', () => {
|
|
7
|
+
it('Should render embed iframe with given video url', () => {
|
|
8
|
+
const { container } = render(YouTubeEmbedOverlay, { embeddable_url: 'youtube.com/watch?v=abc', onclose: () => null })
|
|
9
|
+
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
expect(container.querySelector('iframe').src).toBe('https://www.youtube.com/embed/abc?autoplay=true')
|
|
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()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('Should fire given onclose function on click of close button and backdrop', async () => {
|
|
22
|
+
const onclose = vi.fn()
|
|
23
|
+
const { getByLabelText, getByTestId } = render(YouTubeEmbedOverlay, { embeddable_url: '-', onclose })
|
|
24
|
+
|
|
25
|
+
await fireEvent.click(getByLabelText('Close'))
|
|
26
|
+
expect(onclose).toHaveBeenCalledTimes(1)
|
|
27
|
+
|
|
28
|
+
await fireEvent.click(getByTestId('backdrop'))
|
|
29
|
+
expect(onclose).toHaveBeenCalledTimes(2)
|
|
30
|
+
})
|
|
31
|
+
})
|