@playpilot/tpi 5.32.3 → 5.33.0-beta.explore.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/link-injections.js +25 -10
- package/package.json +1 -1
- package/src/lib/afterArticle.ts +40 -0
- package/src/lib/api/api.ts +1 -1
- package/src/lib/api/titles.ts +13 -1
- package/src/lib/color.ts +19 -0
- package/src/lib/data/countries.json +216 -0
- package/src/lib/data/translations.ts +5 -0
- package/src/lib/disclaimer.ts +27 -0
- package/src/lib/enums/SplitTest.ts +5 -0
- package/src/lib/explore.ts +59 -0
- package/src/lib/fakeData.ts +1 -0
- package/src/lib/images/titles-list.webp +0 -0
- package/src/lib/injection.ts +41 -147
- package/src/lib/modal.ts +38 -7
- package/src/lib/popover.ts +71 -0
- package/src/lib/scss/global.scss +39 -2
- package/src/lib/trailer.ts +22 -0
- package/src/lib/types/api.d.ts +6 -0
- package/src/lib/types/config.d.ts +12 -0
- package/src/lib/types/filter.d.ts +2 -0
- package/src/lib/types/title.d.ts +4 -1
- package/src/routes/+page.svelte +13 -4
- package/src/routes/components/Ads/TopScroll.svelte +4 -18
- package/src/routes/components/Button.svelte +101 -0
- package/src/routes/components/Debugger.svelte +36 -0
- package/src/routes/components/Explore/Explore.svelte +226 -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/Dropdown.svelte +72 -0
- package/src/routes/components/Explore/Filter/Filter.svelte +79 -0
- package/src/routes/components/Explore/Filter/FilterItem.svelte +57 -0
- package/src/routes/components/Explore/Filter/FilterSorting.svelte +70 -0
- package/src/routes/components/Explore/Filter/Search.svelte +56 -0
- package/src/routes/components/Explore/Filter/TogglesWithSearch.svelte +142 -0
- package/src/routes/components/GridTitle.svelte +122 -0
- package/src/routes/components/GridTitleSkeleton.svelte +36 -0
- package/src/routes/components/Icons/IconArrow.svelte +10 -2
- package/src/routes/components/Icons/IconClose.svelte +9 -1
- package/src/routes/components/Icons/IconFilter.svelte +5 -0
- package/src/routes/components/Icons/IconPlay.svelte +3 -0
- package/src/routes/components/Icons/IconSearch.svelte +3 -0
- package/src/routes/components/ListTitle.svelte +10 -68
- package/src/routes/components/ListTitleSkeleton.svelte +42 -0
- package/src/routes/components/Modal.svelte +27 -29
- package/src/routes/components/Participant.svelte +0 -2
- package/src/routes/components/ParticipantModal.svelte +1 -1
- package/src/routes/components/Playlinks/PlaylinkIcon.svelte +1 -1
- package/src/routes/components/Playlinks/PlaylinksCompact.svelte +71 -0
- 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 +39 -2
- package/src/routes/explore/+page.svelte +60 -0
- package/src/tests/lib/afterArticle.test.js +108 -0
- package/src/tests/lib/api/ads.test.js +0 -1
- package/src/tests/lib/api/titles.test.js +55 -0
- package/src/tests/lib/disclaimer.test.js +90 -0
- package/src/tests/lib/explore.test.js +139 -0
- package/src/tests/lib/injections.test.js +5 -157
- package/src/tests/lib/modal.test.js +64 -1
- package/src/tests/lib/popover.test.js +70 -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/Filter/Dropdown.test.js +16 -0
- package/src/tests/routes/components/Explore/Filter/Filter.test.js +20 -0
- package/src/tests/routes/components/Explore/Filter/FilterItem.test.js +50 -0
- package/src/tests/routes/components/Explore/Filter/FilterSorting.test.js +34 -0
- package/src/tests/routes/components/Explore/Filter/Search.test.js +26 -0
- package/src/tests/routes/components/Explore/Filter/TogglesWithSearch.test.js +53 -0
- package/src/tests/routes/components/GridTitle.test.js +42 -0
- package/src/tests/routes/components/ListTitle.test.js +1 -1
- package/src/tests/routes/components/Playlinks/PlaylinksCompact.test.js +42 -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
- package/src/tests/setup.js +2 -0
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
2
|
-
import { closeCurrentModal, destroyAllModals, destroyCurrentModal, getAllModals, getPreviousModal, goBackToPreviousModal, openModal } from '$lib/modal'
|
|
2
|
+
import { closeCurrentModal, destroyAllModals, destroyCurrentModal, getAllModals, getPreviousModal, goBackToPreviousModal, openModal, openModalForInjectedLink } from '$lib/modal'
|
|
3
3
|
import { linkInjections, title } from '$lib/fakeData'
|
|
4
4
|
import { mount, unmount } from 'svelte'
|
|
5
5
|
import ParticipantModal from '../../routes/components/ParticipantModal.svelte'
|
|
6
6
|
import TitleModal from '../../routes/components/TitleModal.svelte'
|
|
7
|
+
import { isHoldingSpecialKey } from '$lib/event'
|
|
8
|
+
import { destroyLinkPopover } from '$lib/popover'
|
|
7
9
|
|
|
8
10
|
vi.mock('svelte', () => ({
|
|
9
11
|
mount: vi.fn(),
|
|
10
12
|
unmount: vi.fn(),
|
|
11
13
|
}))
|
|
12
14
|
|
|
15
|
+
vi.mock('$lib/event', () => ({
|
|
16
|
+
isHoldingSpecialKey: vi.fn(),
|
|
17
|
+
}))
|
|
18
|
+
|
|
19
|
+
vi.mock('$lib/popover', () => ({
|
|
20
|
+
destroyLinkPopover: vi.fn(),
|
|
21
|
+
}))
|
|
22
|
+
|
|
13
23
|
const modal = {
|
|
14
24
|
injection: linkInjections[0],
|
|
15
25
|
data: title,
|
|
@@ -19,7 +29,9 @@ const modal = {
|
|
|
19
29
|
describe('modal.js', () => {
|
|
20
30
|
beforeEach(() => {
|
|
21
31
|
destroyAllModals()
|
|
32
|
+
|
|
22
33
|
vi.resetAllMocks()
|
|
34
|
+
vi.mocked(isHoldingSpecialKey).mockReturnValue(false)
|
|
23
35
|
})
|
|
24
36
|
|
|
25
37
|
describe('openModal', () => {
|
|
@@ -38,6 +50,8 @@ describe('modal.js', () => {
|
|
|
38
50
|
})
|
|
39
51
|
|
|
40
52
|
it('Should not mount modal if modifier key was present in event', () => {
|
|
53
|
+
vi.mocked(isHoldingSpecialKey).mockReturnValueOnce(true)
|
|
54
|
+
|
|
41
55
|
// @ts-ignore
|
|
42
56
|
openModal({ ...modal, event: { ctrlKey: true } })
|
|
43
57
|
|
|
@@ -152,4 +166,53 @@ describe('modal.js', () => {
|
|
|
152
166
|
expect(getAllModals()).toHaveLength(3)
|
|
153
167
|
})
|
|
154
168
|
})
|
|
169
|
+
|
|
170
|
+
describe('openModalForInjectedLink', () => {
|
|
171
|
+
beforeEach(() => {
|
|
172
|
+
document.body.innerHTML = '<span data-playpilot-injection-key="abc"><a href="/">Some link</a></span>'
|
|
173
|
+
|
|
174
|
+
vi.mocked(isHoldingSpecialKey).mockReturnValueOnce(false)
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('Should call destroyLinkPopover when opening modal for injection', () => {
|
|
178
|
+
// @ts-ignore
|
|
179
|
+
openModalForInjectedLink({ target: document.querySelector('a'), preventDefault: vi.fn() }, [{ key: 'abc' }])
|
|
180
|
+
|
|
181
|
+
expect(destroyLinkPopover).toHaveBeenCalled()
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
it('Should return early if special key was pressed', () => {
|
|
185
|
+
vi.mocked(isHoldingSpecialKey).mockReturnValueOnce(true)
|
|
186
|
+
|
|
187
|
+
// @ts-ignore
|
|
188
|
+
openModalForInjectedLink({}, [])
|
|
189
|
+
|
|
190
|
+
expect(destroyLinkPopover).not.toHaveBeenCalled()
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('Should return early if target was not found', () => {
|
|
194
|
+
document.body.innerHTML = '<div></div>'
|
|
195
|
+
|
|
196
|
+
// @ts-ignore
|
|
197
|
+
openModalForInjectedLink({ target: document.querySelector('a'), preventDefault: vi.fn() }, [{ key: 'abc' }])
|
|
198
|
+
|
|
199
|
+
expect(destroyLinkPopover).not.toHaveBeenCalled()
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it('Should return early if target has no key', () => {
|
|
203
|
+
document.body.innerHTML = '<a href="/">Some link</a>'
|
|
204
|
+
|
|
205
|
+
// @ts-ignore
|
|
206
|
+
openModalForInjectedLink({ target: document.querySelector('a'), preventDefault: vi.fn() }, [{ key: 'abc' }])
|
|
207
|
+
|
|
208
|
+
expect(destroyLinkPopover).not.toHaveBeenCalled()
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('Should return early if injection was not valid', () => {
|
|
212
|
+
// @ts-ignore
|
|
213
|
+
openModalForInjectedLink({ target: document.querySelector('a'), preventDefault: vi.fn() }, [{ key: 'not-valid' }])
|
|
214
|
+
|
|
215
|
+
expect(destroyLinkPopover).not.toHaveBeenCalled()
|
|
216
|
+
})
|
|
217
|
+
})
|
|
155
218
|
})
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
2
|
+
import { linkInjections } from '$lib/fakeData'
|
|
3
|
+
import { mount, unmount } from 'svelte'
|
|
4
|
+
import { clearCurrentlyHoveredInjection, currentlyHoveredInjection, destroyLinkPopover, isPopoverActive, openPopoverForInjectedLink } from '$lib/popover'
|
|
5
|
+
import TitlePopover from '../../routes/components/TitlePopover.svelte'
|
|
6
|
+
import { waitFor } from '@testing-library/svelte'
|
|
7
|
+
|
|
8
|
+
vi.mock('svelte', () => ({
|
|
9
|
+
mount: vi.fn(),
|
|
10
|
+
unmount: vi.fn(),
|
|
11
|
+
}))
|
|
12
|
+
|
|
13
|
+
describe('popover.js', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
document.body.innerHTML = '<a>Some link</a>'
|
|
16
|
+
|
|
17
|
+
destroyLinkPopover()
|
|
18
|
+
|
|
19
|
+
vi.resetAllMocks()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
describe('openPopoverForInjectedLink', () => {
|
|
23
|
+
it('Should mount popover', async () => {
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
openPopoverForInjectedLink({ currentTarget: document.querySelector('a') }, linkInjections)
|
|
26
|
+
|
|
27
|
+
await waitFor(() => {
|
|
28
|
+
expect(mount).toHaveBeenCalledWith(TitlePopover, expect.any(Object))
|
|
29
|
+
expect(currentlyHoveredInjection).toBeTruthy()
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('Should not mount popover if user is no longer hovering after delay', async () => {
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
openPopoverForInjectedLink({ currentTarget: document.querySelector('a') }, linkInjections)
|
|
36
|
+
|
|
37
|
+
await new Promise(res => setTimeout(res, 50))
|
|
38
|
+
|
|
39
|
+
clearCurrentlyHoveredInjection()
|
|
40
|
+
|
|
41
|
+
await new Promise(res => setTimeout(res, 100))
|
|
42
|
+
|
|
43
|
+
expect(isPopoverActive()).toBe(false)
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
describe('destroyLinkPopover', () => {
|
|
48
|
+
it('Should not call unmount but still remove potential popover elements if no active popover is set', async () => {
|
|
49
|
+
document.body.innerHTML = '<div data-playpilot-title-popover></div> <div data-playpilot-title-popover></div>'
|
|
50
|
+
|
|
51
|
+
destroyLinkPopover()
|
|
52
|
+
|
|
53
|
+
expect(unmount).not.toHaveBeenCalled()
|
|
54
|
+
expect(document.querySelectorAll('[data-playpilot-title-popover]')).toHaveLength(0)
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
describe('clearCurrentlyHoveredInjection', () => {
|
|
59
|
+
it('Should clear currentlyHoveredInjection', async () => {
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
openPopoverForInjectedLink({ currentTarget: document.querySelector('a') }, linkInjections)
|
|
62
|
+
|
|
63
|
+
await waitFor(() => expect(currentlyHoveredInjection).toBeTruthy())
|
|
64
|
+
|
|
65
|
+
clearCurrentlyHoveredInjection()
|
|
66
|
+
|
|
67
|
+
expect(currentlyHoveredInjection).toBe(null)
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
2
|
+
import { closeCurrentModal, destroyAllModals, destroyCurrentModal, getAllModals, getPreviousModal, goBackToPreviousModal, openModal } from '$lib/modal'
|
|
3
|
+
import { linkInjections, title } from '$lib/fakeData'
|
|
4
|
+
import { mount, unmount } from 'svelte'
|
|
5
|
+
import ParticipantModal from '../../routes/components/ParticipantModal.svelte'
|
|
6
|
+
import TitleModal from '../../routes/components/TitleModal.svelte'
|
|
7
|
+
import { closeTrailerOverlay, openTrailerOverlay } from '$lib/trailer'
|
|
8
|
+
|
|
9
|
+
vi.mock('svelte', () => ({
|
|
10
|
+
mount: vi.fn(),
|
|
11
|
+
unmount: vi.fn(),
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
const titleWithTrailer = { ...title, embeddable_url: 'abc' }
|
|
15
|
+
|
|
16
|
+
describe('modal.js', () => {
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
vi.resetAllMocks()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
describe('openTrailerOverlay', () => {
|
|
22
|
+
it('Should call mount with given title embeddable_url', () => {
|
|
23
|
+
openTrailerOverlay(titleWithTrailer)
|
|
24
|
+
|
|
25
|
+
expect(mount).toHaveBeenCalledWith(
|
|
26
|
+
expect.any(Function),
|
|
27
|
+
expect.objectContaining({
|
|
28
|
+
target: expect.anything(),
|
|
29
|
+
props: expect.objectContaining({
|
|
30
|
+
onclose: expect.any(Function),
|
|
31
|
+
embeddable_url: titleWithTrailer.embeddable_url,
|
|
32
|
+
}),
|
|
33
|
+
}),
|
|
34
|
+
)
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
describe('closeTrailerOverlay', () => {
|
|
39
|
+
it('Should call unmount if component was previously mounted', () => {
|
|
40
|
+
vi.mocked(mount).mockReturnValueOnce({})
|
|
41
|
+
|
|
42
|
+
openTrailerOverlay(titleWithTrailer)
|
|
43
|
+
closeTrailerOverlay()
|
|
44
|
+
|
|
45
|
+
expect(unmount).toHaveBeenCalled()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('Should not call unmount if component was not previously mounted', () => {
|
|
49
|
+
vi.mocked(mount).mockReturnValueOnce({})
|
|
50
|
+
|
|
51
|
+
closeTrailerOverlay()
|
|
52
|
+
|
|
53
|
+
expect(unmount).not.toHaveBeenCalled()
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { render, fireEvent } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import Button from '../../../routes/components/Button.svelte'
|
|
5
|
+
|
|
6
|
+
describe('Button.svelte', () => {
|
|
7
|
+
it('Should use filled class by default', () => {
|
|
8
|
+
const { getByRole } = render(Button)
|
|
9
|
+
|
|
10
|
+
expect(getByRole('button').classList).toContain('filled')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('Should use border class when border variant is given', () => {
|
|
14
|
+
const { getByRole } = render(Button, { variant: 'border' })
|
|
15
|
+
|
|
16
|
+
expect(getByRole('button').classList).not.toContain('filled')
|
|
17
|
+
expect(getByRole('button').classList).toContain('border')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('Should fire given onclick function on click', async () => {
|
|
21
|
+
const onclick = vi.fn()
|
|
22
|
+
const { getByRole } = render(Button, { onclick })
|
|
23
|
+
|
|
24
|
+
await fireEvent.click(getByRole('button'))
|
|
25
|
+
|
|
26
|
+
expect(onclick).toHaveBeenCalled()
|
|
27
|
+
})
|
|
28
|
+
})
|
|
@@ -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(24)
|
|
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,16 @@
|
|
|
1
|
+
import { render } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import Dropdown from '../../../../../routes/components/Explore/Filter/Dropdown.svelte'
|
|
5
|
+
import { createRawSnippet } from 'svelte'
|
|
6
|
+
|
|
7
|
+
describe('Dropdown.svelte', () => {
|
|
8
|
+
const button = createRawSnippet(() => ({ render: () => '<button>Button</button>' }))
|
|
9
|
+
const content = createRawSnippet(() => ({ render: () => '<div>Content</div>' }))
|
|
10
|
+
|
|
11
|
+
it('Should not show content by default', () => {
|
|
12
|
+
const { queryByText } = render(Dropdown, { button, content })
|
|
13
|
+
|
|
14
|
+
expect(queryByText('Content')).not.toBeTruthy()
|
|
15
|
+
})
|
|
16
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import Filter from '../../../../../routes/components/Explore/Filter/Filter.svelte'
|
|
5
|
+
|
|
6
|
+
describe('Filter.svelte', () => {
|
|
7
|
+
it('Should limit the number of filter items shown by default', () => {
|
|
8
|
+
const { getAllByTestId } = render(Filter, { filter: {} })
|
|
9
|
+
|
|
10
|
+
expect(getAllByTestId('filter-item')).toHaveLength(3)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('Should not limit the number of filter items shown after pressing expand button', async () => {
|
|
14
|
+
const { getByText, getAllByTestId } = render(Filter, { filter: {} })
|
|
15
|
+
|
|
16
|
+
await fireEvent.click(getByText('All filters'))
|
|
17
|
+
|
|
18
|
+
expect(getAllByTestId('filter-item')).toHaveLength(6)
|
|
19
|
+
})
|
|
20
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/svelte'
|
|
2
|
+
import { beforeEach, describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import FilterItem from '../../../../../routes/components/Explore/Filter/FilterItem.svelte'
|
|
5
|
+
|
|
6
|
+
describe('FilterItem.svelte', () => {
|
|
7
|
+
/** @type Record<string, string> */
|
|
8
|
+
let filter = {}
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
filter = {}
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('Should not show active state by default', () => {
|
|
15
|
+
const { getByTestId } = render(FilterItem, { filter, label: 'Some label', param: 'some-param' })
|
|
16
|
+
|
|
17
|
+
expect(getByTestId('filter-item').classList).not.toContain('active')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('Should show active state if param is present in filter', () => {
|
|
21
|
+
filter['some-param'] = 'some-value'
|
|
22
|
+
const { getByTestId } = render(FilterItem, { filter, label: 'Some label', param: 'some-param' })
|
|
23
|
+
|
|
24
|
+
expect(getByTestId('filter-item').classList).toContain('active')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('Should show dropdown after click', async () => {
|
|
28
|
+
const { getByRole, getByTestId } = render(FilterItem, { filter, label: 'Some label', param: 'some-param' })
|
|
29
|
+
|
|
30
|
+
await fireEvent.click(getByRole('button'))
|
|
31
|
+
|
|
32
|
+
expect(getByTestId('content')).toBeTruthy()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('Should show toggles with search if data is given', async () => {
|
|
36
|
+
const { getByRole, getByTestId } = render(FilterItem, { filter, label: 'Some label', param: 'some-param', data: [] })
|
|
37
|
+
|
|
38
|
+
await fireEvent.click(getByRole('button'))
|
|
39
|
+
|
|
40
|
+
expect(getByTestId('toggles-with-search')).toBeTruthy()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('Should not show toggles with search if data is not given', async () => {
|
|
44
|
+
const { getByRole, queryByTestId } = render(FilterItem, { filter, label: 'Some label', param: 'some-param', data: null })
|
|
45
|
+
|
|
46
|
+
await fireEvent.click(getByRole('button'))
|
|
47
|
+
|
|
48
|
+
expect(queryByTestId('toggles-with-search')).not.toBeTruthy()
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/svelte'
|
|
2
|
+
import { beforeEach, describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import FilterSorting from '../../../../../routes/components/Explore/Filter/FilterSorting.svelte'
|
|
5
|
+
|
|
6
|
+
describe('FilterSorting.svelte', () => {
|
|
7
|
+
/** @type Record<string, string> */
|
|
8
|
+
let filter = {}
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
filter = {}
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('Should use default label when no value is set', () => {
|
|
15
|
+
const { getByText } = render(FilterSorting, { filter })
|
|
16
|
+
|
|
17
|
+
expect(getByText('Sort by'))
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('Should show active state if param is present in filter', () => {
|
|
21
|
+
filter['ordering'] = 'new'
|
|
22
|
+
const { getByText } = render(FilterSorting, { filter })
|
|
23
|
+
|
|
24
|
+
expect(getByText('New'))
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('Should show dropdown after click', async () => {
|
|
28
|
+
const { getByRole, getByTestId } = render(FilterSorting, { filter })
|
|
29
|
+
|
|
30
|
+
await fireEvent.click(getByRole('button'))
|
|
31
|
+
|
|
32
|
+
expect(getByTestId('content')).toBeTruthy()
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -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/Filter/Search.svelte'
|
|
5
|
+
|
|
6
|
+
describe('Search.svelte', () => {
|
|
7
|
+
it('Should fire given oninput event with the given query', async () => {
|
|
8
|
+
const oninput = vi.fn()
|
|
9
|
+
|
|
10
|
+
const { getByRole } = render(Search, { oninput })
|
|
11
|
+
|
|
12
|
+
await 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', async () => {
|
|
18
|
+
const oninput = vi.fn()
|
|
19
|
+
|
|
20
|
+
const { getByRole } = render(Search, { oninput })
|
|
21
|
+
|
|
22
|
+
await fireEvent.input(getByRole('searchbox'), { target: { value: '' } })
|
|
23
|
+
|
|
24
|
+
expect(oninput).toHaveBeenCalledWith('')
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import TogglesWithSearch from '../../../../../routes/components/Explore/Filter/TogglesWithSearch.svelte'
|
|
5
|
+
|
|
6
|
+
describe('TogglesWithSearch.svelte', () => {
|
|
7
|
+
it('Should fire given onchange function with params for changed option when clicked', async () => {
|
|
8
|
+
const onchange = vi.fn()
|
|
9
|
+
const { getByText } = render(TogglesWithSearch, {
|
|
10
|
+
onchange,
|
|
11
|
+
options: [
|
|
12
|
+
{ label: 'Some label', value: 'some-value' },
|
|
13
|
+
{ label: 'Some second label', value: 'some-second-value' },
|
|
14
|
+
],
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
await fireEvent.click(getByText('Some label'))
|
|
18
|
+
expect(onchange).toHaveBeenCalledWith(['some-value'])
|
|
19
|
+
|
|
20
|
+
await fireEvent.click(getByText('Some second label'))
|
|
21
|
+
expect(onchange).toHaveBeenCalledWith(['some-value', 'some-second-value'])
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('Should show active state for the selected items when given', () => {
|
|
25
|
+
const onchange = vi.fn()
|
|
26
|
+
const { getByText } = render(TogglesWithSearch, {
|
|
27
|
+
onchange,
|
|
28
|
+
options: [
|
|
29
|
+
{ label: 'Some label', value: 'some-value' },
|
|
30
|
+
{ label: 'Some second label', value: 'some-second-value' },
|
|
31
|
+
],
|
|
32
|
+
selected: ['some-value'],
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
expect(getByText('Some label').classList).toContain('active')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('Should limit shown options to the given query', async () => {
|
|
39
|
+
const onchange = vi.fn()
|
|
40
|
+
const { queryByText, getByRole } = render(TogglesWithSearch, {
|
|
41
|
+
onchange,
|
|
42
|
+
options: [
|
|
43
|
+
{ label: 'Some label', value: 'some-value' },
|
|
44
|
+
{ label: 'Some second label', value: 'some-second-value' },
|
|
45
|
+
],
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
await fireEvent.input(getByRole('textbox'), { target: { value: 'second' } })
|
|
49
|
+
|
|
50
|
+
expect(queryByText('Some label')).not.toBeTruthy()
|
|
51
|
+
expect(queryByText('Some second label')).toBeTruthy()
|
|
52
|
+
})
|
|
53
|
+
})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import GridTitle from '../../../routes/components/GridTitle.svelte'
|
|
5
|
+
import { title } from '$lib/fakeData'
|
|
6
|
+
|
|
7
|
+
vi.mock('$lib/tracking', () => ({
|
|
8
|
+
track: vi.fn(),
|
|
9
|
+
}))
|
|
10
|
+
|
|
11
|
+
vi.mock('svelte', async (importActual) => ({
|
|
12
|
+
...(await importActual()),
|
|
13
|
+
getContext: vi.fn(),
|
|
14
|
+
}))
|
|
15
|
+
|
|
16
|
+
describe('GridTitle.svelte', () => {
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
vi.resetAllMocks()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('Should render the given image', () => {
|
|
22
|
+
const { getByAltText } = render(GridTitle, { title })
|
|
23
|
+
|
|
24
|
+
expect(getByAltText(`Movie poster for '${title.title}'`)).toBeTruthy()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('Should render the given info', () => {
|
|
28
|
+
const { getByText } = render(GridTitle, { title })
|
|
29
|
+
|
|
30
|
+
expect(getByText(title.title)).toBeTruthy()
|
|
31
|
+
expect(getByText(title.imdb_score)).toBeTruthy()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('Should fire the given onclick function when clicked', async () => {
|
|
35
|
+
const onclick = vi.fn()
|
|
36
|
+
const { getByText } = render(GridTitle, { title, onclick })
|
|
37
|
+
|
|
38
|
+
await fireEvent.click(getByText(title.title))
|
|
39
|
+
|
|
40
|
+
expect(onclick).toHaveBeenCalled()
|
|
41
|
+
})
|
|
42
|
+
})
|
|
@@ -30,7 +30,7 @@ describe('ListTitle.svelte', () => {
|
|
|
30
30
|
expect(getByText(title.title)).toBeTruthy()
|
|
31
31
|
expect(getByText(title.imdb_score)).toBeTruthy()
|
|
32
32
|
expect(getByText(title.year)).toBeTruthy()
|
|
33
|
-
expect(getByText(title.description)).toBeTruthy()
|
|
33
|
+
expect(getByText(title.description || '')).toBeTruthy()
|
|
34
34
|
})
|
|
35
35
|
|
|
36
36
|
it('Should not have small class by default', () => {
|