@playpilot/tpi 8.14.0-beta.4 → 8.14.0
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/editorial.mount.js +9 -9
- package/dist/link-injections.js +1 -1
- package/dist/mount.js +9 -9
- package/events.md +5 -0
- package/package.json +2 -2
- package/src/lib/api/titles.ts +0 -10
- package/src/lib/data/translations.ts +9 -4
- package/src/lib/enums/TrackingEvent.ts +3 -0
- package/src/lib/fakeData.ts +3 -3
- package/src/lib/inTextWidgets.ts +43 -0
- package/src/lib/injection.ts +7 -13
- package/src/lib/routes.ts +0 -8
- package/src/lib/types/config.d.ts +0 -5
- package/src/routes/+layout.svelte +2 -0
- package/src/routes/components/Debugger.svelte +0 -5
- package/src/routes/components/Description.svelte +0 -1
- package/src/routes/components/Explore/ExploreLayout.svelte +19 -2
- package/src/routes/components/Explore/ExploreRouter.svelte +2 -55
- package/src/routes/components/Explore/Routes/ExploreResults.svelte +2 -12
- package/src/routes/components/Modals/RailModal.svelte +3 -4
- package/src/routes/components/Playlinks/Playlinks.svelte +0 -1
- package/src/routes/components/Rails/Rail.svelte +4 -4
- package/src/routes/components/Title.svelte +4 -12
- package/src/routes/components/Widgets/InjectionsWidgetRail.svelte +51 -0
- package/src/tests/lib/api/titles.test.js +1 -23
- package/src/tests/lib/inTextWidgets.test.js +160 -0
- package/src/tests/lib/injection.test.js +3 -44
- package/src/tests/lib/routes.test.js +2 -14
- package/src/tests/routes/components/Widgets/InjectionsWidgetRail.test.js +28 -0
- package/src/routes/components/Explore/Routes/ExploreTitle.svelte +0 -94
- package/src/tests/routes/components/Explore/Routes/ExploreTitle.test.js +0 -87
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { mount, unmount } from 'svelte'
|
|
3
|
+
import { generateInjection } from '../helpers'
|
|
4
|
+
import { insertInTextWidgets, clearInTextWidgets, inTextWidgetInsertedComponents } from '$lib/inTextWidgets'
|
|
5
|
+
|
|
6
|
+
vi.mock('svelte', () => ({
|
|
7
|
+
mount: vi.fn(),
|
|
8
|
+
unmount: vi.fn(),
|
|
9
|
+
}))
|
|
10
|
+
|
|
11
|
+
describe('inTextWidgets.ts', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.resetAllMocks()
|
|
14
|
+
document.body.innerHTML = ''
|
|
15
|
+
|
|
16
|
+
clearInTextWidgets()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
describe('insertInTextWidgets', () => {
|
|
20
|
+
it('Should not mount any component if no linkInjections are given', () => {
|
|
21
|
+
document.body.innerHTML = '<div data-playpilot-widget="tpi-rail"></div>'
|
|
22
|
+
|
|
23
|
+
insertInTextWidgets([])
|
|
24
|
+
|
|
25
|
+
expect(mount).not.toHaveBeenCalled()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('Should not mount any component if no widget targets exist', () => {
|
|
29
|
+
document.body.innerHTML = '<div>No widgets here</div>'
|
|
30
|
+
|
|
31
|
+
const injection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
32
|
+
|
|
33
|
+
insertInTextWidgets([injection])
|
|
34
|
+
|
|
35
|
+
expect(mount).not.toHaveBeenCalled()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('Should mount a component for a known widget type', () => {
|
|
39
|
+
document.body.innerHTML = '<div data-playpilot-widget="tpi-rail"></div>'
|
|
40
|
+
|
|
41
|
+
const injection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
42
|
+
|
|
43
|
+
insertInTextWidgets([injection])
|
|
44
|
+
|
|
45
|
+
expect(mount).toHaveBeenCalledOnce()
|
|
46
|
+
expect(mount).toHaveBeenCalledWith(
|
|
47
|
+
expect.anything(),
|
|
48
|
+
expect.objectContaining({
|
|
49
|
+
target: document.querySelector('[data-playpilot-widget="tpi-rail"]'),
|
|
50
|
+
props: { linkInjections: [injection] },
|
|
51
|
+
}),
|
|
52
|
+
)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('Should not mount a component for an unknown widget type', () => {
|
|
56
|
+
document.body.innerHTML = '<div data-playpilot-widget="unknown-widget"></div>'
|
|
57
|
+
|
|
58
|
+
const injection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
59
|
+
|
|
60
|
+
insertInTextWidgets([injection])
|
|
61
|
+
|
|
62
|
+
expect(mount).not.toHaveBeenCalled()
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('Should mount components for multiple widget targets on the same page', () => {
|
|
66
|
+
document.body.innerHTML = `
|
|
67
|
+
<div data-playpilot-widget="tpi-rail"></div>
|
|
68
|
+
<div data-playpilot-widget="tpi-rail"></div>
|
|
69
|
+
`
|
|
70
|
+
|
|
71
|
+
const injection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
72
|
+
|
|
73
|
+
insertInTextWidgets([injection])
|
|
74
|
+
|
|
75
|
+
expect(mount).toHaveBeenCalledTimes(2)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('Should skip unknown widget targets and mount known ones', () => {
|
|
79
|
+
document.body.innerHTML = `
|
|
80
|
+
<div data-playpilot-widget="tpi-rail"></div>
|
|
81
|
+
<div data-playpilot-widget="unknown-widget"></div>
|
|
82
|
+
`
|
|
83
|
+
|
|
84
|
+
const injection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
85
|
+
|
|
86
|
+
insertInTextWidgets([injection])
|
|
87
|
+
|
|
88
|
+
expect(mount).toHaveBeenCalledOnce()
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('Should track inserted components', () => {
|
|
92
|
+
document.body.innerHTML = `
|
|
93
|
+
<div data-playpilot-widget="tpi-rail"></div>
|
|
94
|
+
<div data-playpilot-widget="tpi-rail"></div>
|
|
95
|
+
`
|
|
96
|
+
|
|
97
|
+
const injection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
98
|
+
|
|
99
|
+
insertInTextWidgets([injection])
|
|
100
|
+
|
|
101
|
+
expect(inTextWidgetInsertedComponents).toHaveLength(2)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('Should clear previously inserted widgets before inserting new ones', () => {
|
|
105
|
+
document.body.innerHTML = '<div data-playpilot-widget="tpi-rail"></div>'
|
|
106
|
+
|
|
107
|
+
const injection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
108
|
+
|
|
109
|
+
insertInTextWidgets([injection])
|
|
110
|
+
insertInTextWidgets([injection])
|
|
111
|
+
|
|
112
|
+
expect(unmount).toHaveBeenCalled()
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
describe('clearInTextWidgets', () => {
|
|
117
|
+
it('Should unmount all inserted components', () => {
|
|
118
|
+
document.body.innerHTML = `
|
|
119
|
+
<div data-playpilot-widget="tpi-rail"></div>
|
|
120
|
+
<div data-playpilot-widget="tpi-rail"></div>
|
|
121
|
+
`
|
|
122
|
+
|
|
123
|
+
const injection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
124
|
+
insertInTextWidgets([injection])
|
|
125
|
+
|
|
126
|
+
clearInTextWidgets()
|
|
127
|
+
|
|
128
|
+
expect(unmount).toHaveBeenCalled()
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('Should clear innerHTML of all widget elements', () => {
|
|
132
|
+
document.body.innerHTML = `
|
|
133
|
+
<div data-playpilot-widget="tpi-rail"><span>leftover content</span></div>
|
|
134
|
+
`
|
|
135
|
+
|
|
136
|
+
clearInTextWidgets()
|
|
137
|
+
|
|
138
|
+
expect(/** @type {HTMLElement} */ (document.querySelector('[data-playpilot-widget]')).innerHTML).toBe('')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('Should reset inTextWidgetInsertedComponents to empty array', () => {
|
|
142
|
+
document.body.innerHTML = '<div data-playpilot-widget="tpi-rail"></div>'
|
|
143
|
+
|
|
144
|
+
const injection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
145
|
+
insertInTextWidgets([injection])
|
|
146
|
+
|
|
147
|
+
expect(inTextWidgetInsertedComponents.length).toBe(1)
|
|
148
|
+
|
|
149
|
+
clearInTextWidgets()
|
|
150
|
+
|
|
151
|
+
expect(inTextWidgetInsertedComponents.length).toBe(0)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('Should do nothing if no components are present', () => {
|
|
155
|
+
clearInTextWidgets()
|
|
156
|
+
|
|
157
|
+
expect(unmount).not.toHaveBeenCalled()
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
})
|
|
@@ -6,7 +6,6 @@ import { mount, unmount } from 'svelte'
|
|
|
6
6
|
import { fakeFetch, generateInjection } from '../helpers'
|
|
7
7
|
import { openModalForInjectedLink } from '$lib/modal'
|
|
8
8
|
import { getLinkInjectionElements } from '$lib/injectionElements'
|
|
9
|
-
import { titleUrl } from '$lib/routes'
|
|
10
9
|
|
|
11
10
|
vi.mock('svelte', () => ({
|
|
12
11
|
mount: vi.fn(),
|
|
@@ -65,9 +64,8 @@ describe('injection.ts', () => {
|
|
|
65
64
|
|
|
66
65
|
const link = /** @type {HTMLAnchorElement} */ (document.querySelector('a'))
|
|
67
66
|
|
|
68
|
-
// @ts-ignore
|
|
69
|
-
expect(link.href).toBe(titleUrl(injection.title_details))
|
|
70
67
|
expect(link.innerText).toBe(injection.title)
|
|
68
|
+
expect(link.href).toBe(injection.playpilot_url)
|
|
71
69
|
})
|
|
72
70
|
|
|
73
71
|
it('Should replace given words as expected when more than 1 injection per sentence is present', () => {
|
|
@@ -85,13 +83,11 @@ describe('injection.ts', () => {
|
|
|
85
83
|
|
|
86
84
|
const links = /** @type {HTMLAnchorElement[]} */ (Array.from(document.querySelectorAll('a')))
|
|
87
85
|
|
|
88
|
-
// @ts-ignore
|
|
89
|
-
expect(links[0].href).toBe(titleUrl(linkInjections[0].title_details))
|
|
90
86
|
expect(links[0].innerText).toBe(linkInjections[0].title)
|
|
87
|
+
expect(links[0].href).toBe(linkInjections[0].playpilot_url)
|
|
91
88
|
|
|
92
|
-
// @ts-ignore
|
|
93
|
-
expect(links[1].href).toBe(titleUrl(linkInjections[1].title_details))
|
|
94
89
|
expect(links[1].innerText).toBe(linkInjections[1].title)
|
|
90
|
+
expect(links[1].href).toBe(linkInjections[1].playpilot_url)
|
|
95
91
|
})
|
|
96
92
|
|
|
97
93
|
it('Should ignore injections that are marked as inactive', () => {
|
|
@@ -950,43 +946,6 @@ describe('injection.ts', () => {
|
|
|
950
946
|
|
|
951
947
|
expect(document.querySelector('a')?.closest('[data-playpilot-injection-key]')).toBeTruthy()
|
|
952
948
|
})
|
|
953
|
-
|
|
954
|
-
describe('config.open_tpi_links_in_explore', () => {
|
|
955
|
-
beforeEach(() => {
|
|
956
|
-
window.PlayPilotLinkInjections.config = {
|
|
957
|
-
open_tpi_links_in_explore: true,
|
|
958
|
-
explore_navigation_path: 'https://some-path.com/explore',
|
|
959
|
-
}
|
|
960
|
-
})
|
|
961
|
-
|
|
962
|
-
it('Should use href with explore links if open_tpi_links_in_explore is true', () => {
|
|
963
|
-
const injection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
964
|
-
|
|
965
|
-
document.body.innerHTML = `<p>${injection.sentence}</p>`
|
|
966
|
-
|
|
967
|
-
const elements = Array.from(document.querySelectorAll('p'))
|
|
968
|
-
|
|
969
|
-
injectLinksInDocument(elements, { aiInjections: [injection], manualInjections: [] })
|
|
970
|
-
|
|
971
|
-
const link = /** @type {HTMLAnchorElement} */ (document.querySelector('a'))
|
|
972
|
-
expect(link.href).toBe(window.PlayPilotLinkInjections.config.explore_navigation_path + `?route=title&sid=${injection.title_details?.sid}`)
|
|
973
|
-
expect(link.target).not.toBeTruthy()
|
|
974
|
-
})
|
|
975
|
-
|
|
976
|
-
it('Should not open modal when link is clicked when open_tpi_links_in_explore is true', async () => {
|
|
977
|
-
document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
|
|
978
|
-
|
|
979
|
-
const elements = Array.from(document.body.querySelectorAll('p'))
|
|
980
|
-
const injection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
981
|
-
|
|
982
|
-
injectLinksInDocument(elements, { aiInjections: [injection], manualInjections: [] })
|
|
983
|
-
|
|
984
|
-
const link = /** @type {HTMLAnchorElement} */ (document.querySelector('a'))
|
|
985
|
-
await fireEvent.click(link)
|
|
986
|
-
|
|
987
|
-
expect(openModalForInjectedLink).not.toHaveBeenCalled()
|
|
988
|
-
})
|
|
989
|
-
})
|
|
990
949
|
})
|
|
991
950
|
|
|
992
951
|
describe('clearLinkInjections', () => {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import {
|
|
2
|
+
import { titleUrl } from '$lib/routes'
|
|
3
3
|
import { playPilotBaseUrl } from '$lib/constants'
|
|
4
|
-
import { title } from '$lib/fakeData'
|
|
5
4
|
|
|
6
5
|
describe('$lib/routes', () => {
|
|
7
|
-
describe('
|
|
6
|
+
describe('mergePlaylinks', () => {
|
|
8
7
|
it('Should return url for given title', () => {
|
|
9
8
|
// @ts-ignore
|
|
10
9
|
expect(titleUrl({ type: 'series', slug: 'some-slug' })).toBe(`${playPilotBaseUrl}/series/some-slug/`)
|
|
@@ -13,15 +12,4 @@ describe('$lib/routes', () => {
|
|
|
13
12
|
expect(titleUrl({ type: 'movie', slug: 'some-other-slug' })).toBe(`${playPilotBaseUrl}/movie/some-other-slug/`)
|
|
14
13
|
})
|
|
15
14
|
})
|
|
16
|
-
|
|
17
|
-
describe('exploreTitleUrl', () => {
|
|
18
|
-
it('Should return url for given title', () => {
|
|
19
|
-
window.PlayPilotLinkInjections.config = {
|
|
20
|
-
open_tpi_links_in_explore: true,
|
|
21
|
-
explore_navigation_path: 'https://some-path.com/explore',
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
expect(exploreTitleUrl(title)).toBe(`https://some-path.com/explore?route=title&sid=${title.sid}`)
|
|
25
|
-
})
|
|
26
|
-
})
|
|
27
15
|
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { render } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import InjectionsWidgetRail from '../../../../routes/components/Widgets/InjectionsWidgetRail.svelte'
|
|
5
|
+
import { linkInjections } from '$lib/fakeData'
|
|
6
|
+
|
|
7
|
+
describe('InjectionsWidgetRail.svelte', () => {
|
|
8
|
+
it('Should render unique titles for given injections', () => {
|
|
9
|
+
const injections = [linkInjections[0], linkInjections[0], linkInjections[1], linkInjections[2], linkInjections[2]]
|
|
10
|
+
|
|
11
|
+
const { getAllByTestId } = render(InjectionsWidgetRail, { linkInjections: injections })
|
|
12
|
+
|
|
13
|
+
expect(getAllByTestId('title')).toHaveLength(3)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('Should not render if no injections were given', () => {
|
|
17
|
+
const { queryByTestId } = render(InjectionsWidgetRail, { linkInjections: [] })
|
|
18
|
+
|
|
19
|
+
expect(queryByTestId('widget')).not.toBeTruthy()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('Should not render if injections contained no valid titles', () => {
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
const { queryByTestId } = render(InjectionsWidgetRail, { linkInjections: [{ ...linkInjections, title_details: null }] })
|
|
25
|
+
|
|
26
|
+
expect(queryByTestId('widget')).not.toBeTruthy()
|
|
27
|
+
})
|
|
28
|
+
})
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { fetchTitleBySid } from '$lib/api/titles'
|
|
3
|
-
import { mobileBreakpoint } from '$lib/constants'
|
|
4
|
-
import { t } from '$lib/localization'
|
|
5
|
-
import Button from '../../Button.svelte'
|
|
6
|
-
import IconArrow from '../../Icons/IconArrow.svelte'
|
|
7
|
-
import Title from '../../Title.svelte'
|
|
8
|
-
|
|
9
|
-
interface Props {
|
|
10
|
-
navigate?: (key: string) => void
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const { navigate = () => null }: Props = $props()
|
|
14
|
-
|
|
15
|
-
let screenWidth = $state(window.innerWidth)
|
|
16
|
-
|
|
17
|
-
const isMobile = $derived(screenWidth < mobileBreakpoint)
|
|
18
|
-
const sid = new URL(document.location.toString()).searchParams.get('sid')
|
|
19
|
-
</script>
|
|
20
|
-
|
|
21
|
-
<svelte:window bind:innerWidth={screenWidth} />
|
|
22
|
-
|
|
23
|
-
{#snippet empty()}
|
|
24
|
-
{@render back()}
|
|
25
|
-
|
|
26
|
-
<p class="empty">{t('Page Not Found')}</p>
|
|
27
|
-
{/snippet}
|
|
28
|
-
|
|
29
|
-
{#snippet back(offset = false)}
|
|
30
|
-
<div class="back" class:offset>
|
|
31
|
-
<Button variant="link" onclick={() => { navigate('home') }}>
|
|
32
|
-
<IconArrow direction="left" />
|
|
33
|
-
{t('Home')}
|
|
34
|
-
</Button>
|
|
35
|
-
</div>
|
|
36
|
-
{/snippet}
|
|
37
|
-
|
|
38
|
-
{#if sid}
|
|
39
|
-
{#await fetchTitleBySid(sid)}
|
|
40
|
-
{@render back()}
|
|
41
|
-
|
|
42
|
-
Loading...
|
|
43
|
-
{:then title}
|
|
44
|
-
{@render back(true)}
|
|
45
|
-
|
|
46
|
-
<div class="title" data-testid="title">
|
|
47
|
-
<Title {title} useVideoBackground={isMobile} />
|
|
48
|
-
</div>
|
|
49
|
-
{:catch}
|
|
50
|
-
{@render empty()}
|
|
51
|
-
{/await}
|
|
52
|
-
{:else}
|
|
53
|
-
{@render empty()}
|
|
54
|
-
{/if}
|
|
55
|
-
|
|
56
|
-
<style lang="scss">
|
|
57
|
-
.title {
|
|
58
|
-
--playpilot-description-max-width: 600px;
|
|
59
|
-
--playpilot-playlinks-max-width: 600px;
|
|
60
|
-
position: relative;
|
|
61
|
-
border-radius: theme(border-radius);
|
|
62
|
-
overflow: hidden;
|
|
63
|
-
margin-top: margin(1);
|
|
64
|
-
|
|
65
|
-
@include desktop() {
|
|
66
|
-
--playpilot-detail-header-offset: #{margin(5)};
|
|
67
|
-
--playpilot-detail-background-height: #{margin(35)};
|
|
68
|
-
--playpilot-detail-background-opacity: 0.5;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.back {
|
|
73
|
-
--playpilot-button-text-color: white;
|
|
74
|
-
font-weight: theme(font-bold);
|
|
75
|
-
|
|
76
|
-
&.offset {
|
|
77
|
-
z-index: 1;
|
|
78
|
-
position: absolute;
|
|
79
|
-
margin-left: margin(1);
|
|
80
|
-
margin-top: margin(1);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.empty {
|
|
85
|
-
margin-top: margin(1);
|
|
86
|
-
padding: margin(1);
|
|
87
|
-
border: 1px solid theme(content);
|
|
88
|
-
max-width: margin(20);
|
|
89
|
-
border-radius: theme(border-radius);
|
|
90
|
-
font-size: theme(font-size-large);
|
|
91
|
-
font-weight: theme(font-bold);
|
|
92
|
-
color: theme(text-color);
|
|
93
|
-
}
|
|
94
|
-
</style>
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { render, waitFor, fireEvent } from '@testing-library/svelte'
|
|
2
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import TitleDetail from '../../../../../routes/components/Explore/Routes/ExploreTitle.svelte'
|
|
5
|
-
import { fetchTitleBySid } from '$lib/api/titles'
|
|
6
|
-
import { title } from '$lib/fakeData'
|
|
7
|
-
|
|
8
|
-
vi.mock('$lib/api/titles', () => ({
|
|
9
|
-
fetchTitleBySid: vi.fn(),
|
|
10
|
-
}))
|
|
11
|
-
|
|
12
|
-
vi.mock('/src/routes/components/Title.svelte', () => ({
|
|
13
|
-
default: vi.fn(),
|
|
14
|
-
}))
|
|
15
|
-
|
|
16
|
-
describe('ExploreTitle.svelte', () => {
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
vi.resetAllMocks()
|
|
19
|
-
vi.mocked(fetchTitleBySid).mockResolvedValue(title)
|
|
20
|
-
|
|
21
|
-
history.pushState({}, '', '/')
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('Should render empty state when no sid is in the URL', async () => {
|
|
25
|
-
const { getByText } = render(TitleDetail)
|
|
26
|
-
|
|
27
|
-
await waitFor(() => {
|
|
28
|
-
expect(getByText('Page not found')).toBeTruthy()
|
|
29
|
-
})
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('Should call fetchTitleBySid with sid from URL', async () => {
|
|
33
|
-
history.pushState({}, '', '?sid=some-sid')
|
|
34
|
-
|
|
35
|
-
render(TitleDetail)
|
|
36
|
-
|
|
37
|
-
expect(fetchTitleBySid).toHaveBeenCalledWith('some-sid')
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('Should render loading state while fetching', async () => {
|
|
41
|
-
history.pushState({}, '', '?sid=some-sid')
|
|
42
|
-
vi.mocked(fetchTitleBySid).mockReturnValue(new Promise(() => {}))
|
|
43
|
-
|
|
44
|
-
const { getByText } = render(TitleDetail)
|
|
45
|
-
|
|
46
|
-
expect(getByText('Loading...')).toBeTruthy()
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('Should render the title when fetchTitleBySid resolves', async () => {
|
|
50
|
-
history.pushState({}, '', '?sid=some-sid')
|
|
51
|
-
|
|
52
|
-
const { getByTestId } = render(TitleDetail)
|
|
53
|
-
|
|
54
|
-
await waitFor(() => {
|
|
55
|
-
expect(getByTestId('title')).toBeTruthy()
|
|
56
|
-
})
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
it('Should render empty state when fetchTitleBySid rejects', async () => {
|
|
60
|
-
history.pushState({}, '', '?sid=some-sid')
|
|
61
|
-
vi.mocked(fetchTitleBySid).mockRejectedValue(new Error('Not found'))
|
|
62
|
-
|
|
63
|
-
const { getByText } = render(TitleDetail)
|
|
64
|
-
|
|
65
|
-
await waitFor(() => {
|
|
66
|
-
expect(getByText('Page not found')).toBeTruthy()
|
|
67
|
-
})
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('Should call navigate with "home" when back button is clicked', async () => {
|
|
71
|
-
history.pushState({}, '', '?sid=some-sid')
|
|
72
|
-
|
|
73
|
-
const navigate = vi.fn()
|
|
74
|
-
|
|
75
|
-
const { getByText } = render(TitleDetail, { navigate })
|
|
76
|
-
|
|
77
|
-
await fireEvent.click(getByText('Home'))
|
|
78
|
-
|
|
79
|
-
expect(navigate).toHaveBeenCalledWith('home')
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
it('Should not call fetchTitleBySid when no sid is in the URL', async () => {
|
|
83
|
-
render(TitleDetail)
|
|
84
|
-
|
|
85
|
-
expect(fetchTitleBySid).not.toHaveBeenCalled()
|
|
86
|
-
})
|
|
87
|
-
})
|