@playpilot/tpi 8.5.10 → 8.6.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/events.md CHANGED
@@ -18,8 +18,10 @@ All events share a common payload:
18
18
  Events related to titles share an additional set of data (referred to below as `Title`):
19
19
 
20
20
  - `original_title`
21
+ - `title`
21
22
  - `title_sid`
22
23
  - `title_type`: "movie" or "series"
24
+ - `genres`: An array of all genres for the title
23
25
  - `providers`: An array of provider names
24
26
 
25
27
  Events may have additional data in their payload.
@@ -112,4 +114,5 @@ Event | Action | Info | Payload
112
114
  `explore_search` | _Fires any time the user searches for something_ | | `query`
113
115
  `venus_title_rail_modal_view` | _Fires any time a title is clicked in a rail, opening the rail modal_ | | `rail` (heading key of the rail)
114
116
  `venus_title_rail_expand_click` | _Fires any time a title is expanded in a rail directly via a click_ | Does not fire when a title opens automatically on load or navigate | `Title`, `rail` (heading key of the rail)
117
+ `venus_title_rail_set_index` | _Fires when navigating in the titles rail modal, either via arrows, swipe, or clicking titles_ | | `Title`, `index` (index of the new position of the slider)
115
118
  `venus_navigate` | _Fires when navigating on the explore page_ | Does not fire on initial load | `route` (the key of the given route)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playpilot/tpi",
3
- "version": "8.5.10",
3
+ "version": "8.6.1",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -73,6 +73,7 @@ export const TrackingEvent = {
73
73
  ExploreFetchProvidersFailed: 'venus_fetch_providers_failed',
74
74
  ExploreTitleRailModalView: 'venus_title_rail_modal_view',
75
75
  ExploreTitleRailExpandClick: 'venus_title_rail_expand_click',
76
+ ExploreTitleRailSetIndex: 'venus_title_rail_set_index',
76
77
  ExploreNavigate: 'venus_navigate',
77
78
  } as const
78
79
 
@@ -1,5 +1,4 @@
1
1
  export type ExploreRoute = {
2
2
  key: string
3
- label: string
4
3
  component: any
5
4
  }
@@ -1,28 +1,27 @@
1
1
  <script lang="ts">
2
+ import type { ExploreFilter } from '$lib/types/filter'
2
3
  import { heading } from '$lib/actions/heading'
3
4
  import { exploreParentSelector, useExploreRouter } from '$lib/explore'
4
5
  import { t } from '$lib/localization'
5
- import type { ExploreRoute } from '$lib/types/explore'
6
6
  import { track } from '$lib/tracking'
7
7
  import { TrackingEvent } from '$lib/enums/TrackingEvent'
8
8
  import { fetchAds } from '$lib/api/ads'
9
9
  import { onMount, type Snippet } from 'svelte'
10
10
  import Search from './Filter/Search.svelte'
11
- import Button from '../Button.svelte'
11
+ import Filter from './Filter/Filter.svelte'
12
12
 
13
13
  interface Props {
14
- routes: ExploreRoute[]
15
- currentRoute: ExploreRoute
16
- navigate?: (route: ExploreRoute) => void
14
+ navigate?: (key: string) => void
17
15
  searchQuery?: string
16
+ filter?: ExploreFilter
18
17
  children: Snippet
19
18
  }
20
19
 
21
- let { routes, currentRoute, navigate = () => null, searchQuery = $bindable(''), children }: Props = $props()
20
+ let { navigate = () => null, searchQuery = $bindable(''), filter = $bindable({}), children }: Props = $props()
22
21
 
23
22
  let element: HTMLElement | null = null
24
23
  let height: string | null = $state(null)
25
- let clientWidth: number = $state(0)
24
+ let clientWidth: number = $state(window.innerWidth)
26
25
 
27
26
  $effect(() => {
28
27
  // Set the height of this element to match that of it's container. That way we can
@@ -54,18 +53,14 @@
54
53
  </div>
55
54
  </div>
56
55
 
56
+ <Search oninput={(query) => searchQuery = query} />
57
+
57
58
  {#if useExploreRouter()}
58
- <div class="navigation" role="navigation">
59
- {#each routes as route}
60
- <Button variant="border" size="large" active={currentRoute.key === route.key} onclick={() => navigate(route)}>
61
- {t(route.label)}
62
- </Button>
63
- {/each}
59
+ <div class="filter">
60
+ <Filter {filter} limit={clientWidth < 500} showSorting={!searchQuery} onchange={() => navigate('results')} />
64
61
  </div>
65
62
  {/if}
66
63
 
67
- <Search oninput={(query) => searchQuery = query} />
68
-
69
64
  {@render children()}
70
65
  </div>
71
66
 
@@ -120,9 +115,11 @@
120
115
  line-height: 1.35;
121
116
  }
122
117
 
123
- .navigation {
118
+ .filter {
124
119
  display: flex;
120
+ flex-direction: column;
125
121
  gap: margin(0.5);
126
- margin-bottom: margin(0.5);
122
+ width: 100%;
123
+ margin: margin(0.5) 0 margin(1.5);
127
124
  }
128
125
  </style>
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { ExploreRoute } from '$lib/types/explore'
3
+ import type { ExploreFilter } from '$lib/types/filter'
3
4
  import { useExploreRouter } from '$lib/explore'
4
5
  import { track } from '$lib/tracking'
5
- import { t } from '$lib/localization'
6
6
  import { TrackingEvent } from '$lib/enums/TrackingEvent'
7
7
  import ExploreHome from './Routes/ExploreHome.svelte'
8
8
  import ExploreResults from './Routes/ExploreResults.svelte'
@@ -11,7 +11,6 @@
11
11
  const routes: ExploreRoute[] = [
12
12
  {
13
13
  key: 'results',
14
- label: t('Explore'),
15
14
  component: ExploreResults,
16
15
  },
17
16
  ]
@@ -19,13 +18,13 @@
19
18
  if (useExploreRouter()) {
20
19
  routes.unshift({
21
20
  key: 'home',
22
- label: t('Home'),
23
21
  component: ExploreHome,
24
22
  })
25
23
  }
26
24
 
27
25
  let currentRoute: ExploreRoute = $state(routes[0])
28
26
  let searchQuery: string = $state('')
27
+ let filter: ExploreFilter = $state({})
29
28
 
30
29
  const CurrentRouteComponent = $derived(currentRoute.component)
31
30
 
@@ -33,13 +32,13 @@
33
32
  if (searchQuery) currentRoute = routes.find(route => route.key === 'results')!
34
33
  })
35
34
 
36
- function navigate(route: ExploreRoute): void {
37
- currentRoute = route
35
+ function navigate(key: string): void {
36
+ currentRoute = routes.find(route => route.key === key) || routes[0]
38
37
 
39
- track(TrackingEvent.ExploreNavigate, null, { route: route.key })
38
+ track(TrackingEvent.ExploreNavigate, null, { route: currentRoute.key })
40
39
  }
41
40
  </script>
42
41
 
43
- <ExploreLayout {routes} {currentRoute} {navigate} bind:searchQuery>
44
- <CurrentRouteComponent {searchQuery} />
42
+ <ExploreLayout {navigate} bind:searchQuery bind:filter>
43
+ <CurrentRouteComponent {searchQuery} {filter} {navigate} />
45
44
  </ExploreLayout>
@@ -7,28 +7,31 @@
7
7
  import type { ExploreFilter } from '$lib/types/filter'
8
8
  import type { TitleData } from '$lib/types/title'
9
9
  import { hasConsentedTo } from '$lib/consent'
10
- import { trackViaPixel } from '@playpilot/retargeting-tracking'
10
+ import { useExploreRouter } from '$lib/explore'
11
11
  import { t } from '$lib/localization'
12
+ import { trackViaPixel } from '@playpilot/retargeting-tracking'
12
13
  import Button from '../../Button.svelte'
13
14
  import GridTitle from '../../GridTitle.svelte'
14
15
  import GridTitleSkeleton from '../../GridTitleSkeleton.svelte'
15
16
  import ListTitle from '../../ListTitle.svelte'
16
17
  import ListTitleSkeleton from '../../ListTitleSkeleton.svelte'
17
- import Filter from '../Filter/Filter.svelte'
18
18
  import Empty from '../Empty.svelte'
19
+ import IconArrow from '../../Icons/IconArrow.svelte'
19
20
 
20
21
  interface Props {
21
- searchQuery?: string
22
+ searchQuery?: string,
23
+ filter?: ExploreFilter,
24
+ navigate?: (key: string) => void
22
25
  }
23
26
 
24
- const { searchQuery = '' }: Props = $props()
25
-
26
- const filter: ExploreFilter = $state({})
27
+ const { searchQuery = '', filter = {}, navigate = () => null }: Props = $props()
27
28
 
29
+ // svelte-ignore non_reactive_update
30
+ let page = 1
28
31
  let titles: TitleData[] = $state([])
29
- let page = $state(1)
30
32
  let debounce: ReturnType<typeof setTimeout> | null = null
31
33
  let latestRequestId = 0
34
+ let lastRequestAsString = JSON.stringify(filter) + searchQuery
32
35
  let promise = $state(getTitlesForFilter())
33
36
  let width = $state(0)
34
37
 
@@ -46,6 +49,10 @@
46
49
  if (searchQuery || latestRequestId != 0) search(searchQuery)
47
50
  })
48
51
 
52
+ $effect(() => {
53
+ if (filter) setFilter()
54
+ })
55
+
49
56
  async function getTitlesForFilter(): Promise<APIPaginatedResult<TitleData>> {
50
57
  latestRequestId += 1
51
58
  const requestId = latestRequestId
@@ -75,6 +82,8 @@
75
82
  }
76
83
 
77
84
  async function search(query: string): Promise<void> {
85
+ if (!isNewRequest()) return
86
+
78
87
  if (debounce) clearTimeout(debounce)
79
88
 
80
89
  debounce = setTimeout(() => {
@@ -89,6 +98,8 @@
89
98
  }
90
99
 
91
100
  function setFilter(): void {
101
+ if (!isNewRequest()) return
102
+
92
103
  resetTitles()
93
104
  promise = getTitlesForFilter()
94
105
  }
@@ -109,13 +120,28 @@
109
120
  openModal({ event, data: title })
110
121
  track(TrackingEvent.ExploreTitleClick, title)
111
122
  }
123
+
124
+ function clearFilter(): void {
125
+ for (const key of Object.keys(filter)) {
126
+ delete filter[key]
127
+ }
128
+ }
129
+
130
+ function isNewRequest(): boolean {
131
+ const requestAsString = JSON.stringify(filter) + searchQuery
132
+ if (requestAsString === lastRequestAsString) return false
133
+
134
+ lastRequestAsString = requestAsString
135
+ return true
136
+ }
112
137
  </script>
113
138
 
114
- {#key grid}
115
- <div class="filter">
116
- <Filter {filter} limit={!grid} onchange={setFilter} showSorting={!searchQuery} />
117
- </div>
118
- {/key}
139
+ {#if useExploreRouter()}
140
+ <Button variant="link" onclick={() => { navigate('home'); clearFilter() }}>
141
+ <IconArrow direction="left" />
142
+ {t('Home')}
143
+ </Button>
144
+ {/if}
119
145
 
120
146
  <div class="titles" class:grid role="main" style:--grid-columns={gridColumns} bind:clientWidth={width} data-testid="explore-results">
121
147
  {#each titles as title}
@@ -148,14 +174,6 @@
148
174
  {/await}
149
175
 
150
176
  <style lang="scss">
151
- .filter {
152
- display: flex;
153
- flex-direction: column;
154
- gap: margin(0.5);
155
- width: 100%;
156
- margin: margin(0.5) 0 margin(2);
157
- }
158
-
159
177
  .titles {
160
178
  --playpilot-list-item-padding: 0;
161
179
  --playpilot-list-item-background: transparent;
@@ -164,6 +182,7 @@
164
182
  display: flex;
165
183
  flex-direction: column;
166
184
  gap: margin(0.5);
185
+ margin-top: margin(1.5);
167
186
 
168
187
  &.grid {
169
188
  display: grid;
@@ -11,10 +11,11 @@
11
11
  interface Props {
12
12
  items: Record<string, any>[]
13
13
  initialIndex?: number
14
+ onchange?: (index: number) => void
14
15
  each: Snippet<[item: any, currentIndex: number]>
15
16
  }
16
17
 
17
- const { items, initialIndex = 0, each }: Props = $props()
18
+ const { items, initialIndex = 0, onchange = () => null, each }: Props = $props()
18
19
 
19
20
  const transitionDuration = 300
20
21
 
@@ -27,6 +28,11 @@
27
28
  requestAnimationFrame(() => initialized = true)
28
29
  })
29
30
  })
31
+
32
+ function setSliderIndex(index: number): void {
33
+ onchange(index)
34
+ slider.setIndex(index)
35
+ }
30
36
  </script>
31
37
 
32
38
  <Modal blur>
@@ -37,7 +43,7 @@
37
43
  {#each items as item, index}
38
44
  <!-- svelte-ignore a11y_click_events_have_key_events -->
39
45
  <!-- svelte-ignore a11y_no_static_element_interactions -->
40
- <div class="item" class:active={index === currentIndex} onclick={() => slider.setIndex(index)}>
46
+ <div class="item" class:active={index === currentIndex} onclick={() => setSliderIndex(index)}>
41
47
  {#if Math.abs(index - currentIndex) === 1 || currentIndex === index}
42
48
  <div class="content" transition:fade={{ duration: initialized ? transitionDuration : 0 }}>
43
49
  {@render each(item, currentIndex)}
@@ -47,15 +53,15 @@
47
53
  {/each}
48
54
  {/snippet}
49
55
 
50
- {#snippet controls({ setIndex, currentIndex, reachedEnd })}
56
+ {#snippet controls({ currentIndex, reachedEnd })}
51
57
  {#if currentIndex > 0}
52
- <button class="arrow left" onclick={() => setIndex(currentIndex - 1)} aria-label="Previous" aria-live="polite">
58
+ <button class="arrow left" onclick={() => setSliderIndex(currentIndex - 1)} aria-label="Previous" aria-live="polite">
53
59
  <IconArrow size={21} direction="left" title="Previous" />
54
60
  </button>
55
61
  {/if}
56
62
 
57
63
  {#if !reachedEnd}
58
- <button class="arrow right" onclick={() => setIndex(currentIndex + 1)} aria-label="Next" aria-live="polite">
64
+ <button class="arrow right" onclick={() => setSliderIndex(currentIndex + 1)} aria-label="Next" aria-live="polite">
59
65
  <IconArrow size={21} title="Next" />
60
66
  </button>
61
67
  {/if}
@@ -1,4 +1,6 @@
1
1
  <script lang="ts">
2
+ import { TrackingEvent } from '$lib/enums/TrackingEvent'
3
+ import { track } from '$lib/tracking'
2
4
  import type { TitleData } from '$lib/types/title'
3
5
  import Title from '../Title.svelte'
4
6
  import RailModal from './RailModal.svelte'
@@ -11,7 +13,7 @@
11
13
  const { titles, initialIndex = 0 }: Props = $props()
12
14
  </script>
13
15
 
14
- <RailModal items={titles} {initialIndex}>
16
+ <RailModal items={titles} {initialIndex} onchange={(index) => track(TrackingEvent.ExploreTitleRailSetIndex, titles[index], { index })}>
15
17
  {#snippet each(title, currentIndex)}
16
18
  <Title {title} useVideoBackground={title.sid === titles[currentIndex]?.sid} />
17
19
  {/snippet}
@@ -67,6 +67,23 @@ describe('$lib/api/api', () => {
67
67
  expect(global.fetch).toHaveBeenCalledTimes(1)
68
68
  })
69
69
 
70
+ it('Should fetch twice once for the same path if the first request failed', async () => {
71
+ fakeFetch({ ok: false })
72
+ try {
73
+ await api('/some-path')
74
+ } catch {
75
+ // Ignore me
76
+ }
77
+
78
+ try {
79
+ await api('/some-path')
80
+ } catch {
81
+ // Ignore me
82
+ }
83
+
84
+ expect(global.fetch).toHaveBeenCalledTimes(2)
85
+ })
86
+
70
87
  it('Should fetch multiple times if multiple requests are made for different paths', async () => {
71
88
  await api('/some-path')
72
89
  await api('/some-other-path')
@@ -38,6 +38,9 @@ describe('main.ts', () => {
38
38
  vi.resetModules()
39
39
  vi.resetAllMocks()
40
40
 
41
+ // @ts-ignore
42
+ delete window.PlayPilotLinkInjections
43
+
41
44
  await import('../main')
42
45
  })
43
46
 
@@ -48,6 +51,7 @@ describe('main.ts', () => {
48
51
  describe('initialize', () => {
49
52
  it('Should not call setConsent when only a token is passed', () => {
50
53
  window.PlayPilotLinkInjections.initialize({ token: 'a' })
54
+ console.log(window.PlayPilotLinkInjections)
51
55
 
52
56
  expect(setConsent).not.toHaveBeenCalled()
53
57
 
@@ -10,18 +10,6 @@ import { fetchAds } from '$lib/api/ads'
10
10
 
11
11
  const children = createRawSnippet(() => ({ render: () => '<div></div>' }))
12
12
 
13
- const routes = [
14
- {
15
- key: 'route-1',
16
- label: 'Route 1',
17
- component: {},
18
- }, {
19
- key: 'route-2',
20
- label: 'Route 2',
21
- component: {},
22
- },
23
- ]
24
-
25
13
  vi.mock('$lib/tracking', () => ({
26
14
  track: vi.fn(),
27
15
  }))
@@ -38,20 +26,14 @@ describe('ExploreLayout.svelte', () => {
38
26
  window.PlayPilotLinkInjections = { config: { explore_use_router: true } }
39
27
  })
40
28
 
41
- it('Should render each given route', () => {
42
- const { getByText } = render(ExploreLayout, { routes, currentRoute: routes[0], children })
43
-
44
- expect(getByText('Route 1')).toBeTruthy()
45
- expect(getByText('Route 2')).toBeTruthy()
46
- })
47
-
48
- it('Should call navigate when route is clicked', async () => {
29
+ it('Should call navigate when filter is changed', async () => {
49
30
  const navigate = vi.fn()
50
- const { getByText } = render(ExploreLayout, { routes, currentRoute: routes[0], navigate, children })
31
+ const { getByText } = render(ExploreLayout, { navigate, children })
51
32
 
52
- await fireEvent.click(getByText('Route 2'))
33
+ await fireEvent.click(getByText('Genres'))
34
+ await fireEvent.click(getByText('Drama'))
53
35
 
54
- expect(navigate).toHaveBeenCalledWith(routes[1])
36
+ expect(navigate).toHaveBeenCalledWith('results')
55
37
  })
56
38
 
57
39
  it('Should should set its height if parent has height', async () => {
@@ -59,7 +41,7 @@ describe('ExploreLayout.svelte', () => {
59
41
 
60
42
  const { container } = render(
61
43
  ExploreLayout,
62
- { routes, currentRoute: routes[0], children },
44
+ { children },
63
45
  { baseElement: /** @type {HTMLElement} */ (document.querySelector(exploreParentSelector)),
64
46
  })
65
47
 
@@ -69,7 +51,7 @@ describe('ExploreLayout.svelte', () => {
69
51
  })
70
52
 
71
53
  it('Should call tracking event and fetchAds on mount', () => {
72
- render(ExploreLayout, { routes, currentRoute: routes[0], children })
54
+ render(ExploreLayout, { children })
73
55
 
74
56
  expect(track).toHaveBeenCalledWith(TrackingEvent.ExplorePageView)
75
57
  expect(fetchAds).toHaveBeenCalled()
@@ -79,7 +61,7 @@ describe('ExploreLayout.svelte', () => {
79
61
  // @ts-ignore
80
62
  window.PlayPilotLinkInjections.ads = ['a']
81
63
 
82
- render(ExploreLayout, { routes, currentRoute: routes[0], children })
64
+ render(ExploreLayout, { children })
83
65
 
84
66
  expect(fetchAds).not.toHaveBeenCalled()
85
67
  })
@@ -23,10 +23,11 @@ describe('ExploreRouter.svelte', () => {
23
23
  expect(getByTestId('explore-home')).toBeTruthy()
24
24
  })
25
25
 
26
- it('Should render results on click of button', async () => {
26
+ it('Should render results after navigate', async () => {
27
27
  const { getByText, getByTestId } = render(ExploreRouter)
28
28
 
29
- await fireEvent.click(getByText('Explore'))
29
+ await fireEvent.click(getByText('Genres'))
30
+ await fireEvent.click(getByText('Drama'))
30
31
 
31
32
  expect(getByTestId('explore-results')).toBeTruthy()
32
33
  })
@@ -6,6 +6,7 @@ import { fetchTitles } from '$lib/api/titles'
6
6
  import { title } from '$lib/fakeData'
7
7
  import { TrackingEvent } from '$lib/enums/TrackingEvent'
8
8
  import { track } from '$lib/tracking'
9
+ import { clearCache } from '$lib/api/api'
9
10
 
10
11
  vi.mock('$lib/api/titles', () => ({
11
12
  fetchTitles: vi.fn(),
@@ -24,12 +25,14 @@ describe('ExploreResults.svelte', () => {
24
25
  // @ts-ignore
25
26
  window.PlayPilotLinkInjections = {}
26
27
 
28
+ clearCache()
27
29
  vi.resetAllMocks()
28
30
  })
29
31
 
30
32
  it('Should call fetchTitles on mount', () => {
31
33
  render(ExploreResults)
32
34
 
35
+ expect(fetchTitles).toHaveBeenCalledTimes(1)
33
36
  expect(fetchTitles).toHaveBeenCalledWith({ page_size: 24, page: 1 })
34
37
  })
35
38
 
@@ -102,13 +105,8 @@ describe('ExploreResults.svelte', () => {
102
105
  it('Should call fetchTitles with string of comma separated values when filtering with array value', async () => {
103
106
  vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
104
107
 
105
- const { getByText } = render(ExploreResults)
106
-
107
- await fireEvent.click(getByText('Genres'))
108
- await fireEvent.click(getByText('Action'))
109
- await fireEvent.click(getByText('Adventure'))
108
+ render(ExploreResults, { filter: { genres: { type: 'array', value: ['101', '109'] } } })
110
109
 
111
- expect(fetchTitles).toHaveBeenCalledWith({ page: 1, page_size: 24, genres: '101' })
112
110
  expect(fetchTitles).toHaveBeenCalledWith({ page: 1, page_size: 24, genres: '101,109' })
113
111
  })
114
112
 
@@ -137,11 +135,7 @@ describe('ExploreResults.svelte', () => {
137
135
  it('Should call fetchTitles with min and max values when filtering with range value', async () => {
138
136
  vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
139
137
 
140
- const { container, getByText } = render(ExploreResults)
141
-
142
- await fireEvent.click(getByText('IMDb'))
143
- // @ts-ignore
144
- await fireEvent.input(container.querySelector('#lower'), { target: { value: 2 } })
138
+ render(ExploreResults, { filter: { imdb_score: { type: 'range', value: [2, 10] } } })
145
139
 
146
140
  await waitFor(() => {
147
141
  expect(fetchTitles).toHaveBeenCalledWith({ page: 1, page_size: 24, imdb_score_min: 2, imdb_score_max: 10 })
@@ -151,15 +145,12 @@ describe('ExploreResults.svelte', () => {
151
145
  it('Should call fetchTitles with multiple values when given', async () => {
152
146
  vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
153
147
 
154
- const { container, getByText } = render(ExploreResults)
155
-
156
- await fireEvent.click(getByText('Genres'))
157
- await fireEvent.click(getByText('Action'))
158
- await fireEvent.click(getByText('Adventure'))
159
-
160
- await fireEvent.click(getByText('IMDb'))
161
- // @ts-ignore
162
- await fireEvent.input(container.querySelector('#lower'), { target: { value: 2 } })
148
+ render(ExploreResults, {
149
+ filter: {
150
+ genres: { type: 'array', value: ['101', '109'] },
151
+ imdb_score: { type: 'range', value: [2, 10] },
152
+ },
153
+ })
163
154
 
164
155
  await waitFor(() => {
165
156
  expect(fetchTitles).toHaveBeenCalledWith({ page: 1, page_size: 24, genres: '101,109', imdb_score_min: 2, imdb_score_max: 10 })
@@ -169,10 +160,7 @@ describe('ExploreResults.svelte', () => {
169
160
  it('Should call fetchTitles with string for sorting when sorting is used', async () => {
170
161
  vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
171
162
 
172
- const { getByText } = render(ExploreResults)
173
-
174
- await fireEvent.click(getByText('Sort by'))
175
- await fireEvent.click(getByText('New'))
163
+ render(ExploreResults, { filter: { ordering: { type: 'string', value: '-new' } } })
176
164
 
177
165
  expect(fetchTitles).toHaveBeenCalledWith({ page: 1, page_size: 24, ordering: '-new' })
178
166
  })
@@ -204,7 +192,7 @@ describe('ExploreResults.svelte', () => {
204
192
  })
205
193
 
206
194
  it('Should show error message if api responded with error', async () => {
207
- vi.mocked(fetchTitles).mockRejectedValueOnce(null)
195
+ vi.mocked(fetchTitles).mockRejectedValue(null)
208
196
 
209
197
  const { getByText } = render(ExploreResults)
210
198