@playpilot/tpi 8.25.1 → 8.26.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playpilot/tpi",
3
- "version": "8.25.1",
3
+ "version": "8.26.2",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -2,7 +2,7 @@ import { RETARGETING_USER_ID_KEY } from '@playpilot/retargeting-tracking'
2
2
  import { hasConsentedTo } from './consent'
3
3
  import { getUserId } from './user'
4
4
 
5
- export function isPixelAllowed(): boolean {
5
+ export function isRetargetingAllowed(): boolean {
6
6
  if (!window.PlayPilotLinkInjections.config?.allow_retargeting_pixels) return false
7
7
 
8
8
  if (!hasConsentedTo('pixels')) return false
@@ -5,7 +5,6 @@
5
5
  import { track } from '$lib/tracking'
6
6
  import { TrackingEvent } from '$lib/enums/TrackingEvent'
7
7
  import TitlesRail from '../../Rails/TitlesRail.svelte'
8
- import { mobileBreakpoint } from '$lib/constants'
9
8
  import { getLanguage } from '$lib/language'
10
9
  import type { LanguageCode } from '$lib/types/language'
11
10
  import { api } from '$lib/api/api'
@@ -40,7 +39,7 @@
40
39
  {#await fetchRails()}
41
40
  {#each { length: 3 }}
42
41
  <div class="rail">
43
- <TitlesRail titles={new Promise(() => {})} size={windowWidth >= mobileBreakpoint ? 'flexible' : 'huge'} />
42
+ <TitlesRail heading=" " titles={new Promise(() => {})} size="huge" />
44
43
  </div>
45
44
  {/each}
46
45
  {:then rails}
@@ -53,10 +52,11 @@
53
52
  {...properties}
54
53
  bind:expandedTitle
55
54
  bind:expandedRailKey
55
+ lazy
56
56
  onclick={() => track(TrackingEvent.ExploreTitleRailModalView, null, { rail: headings })}
57
57
  onexpand={(title) => track(TrackingEvent.ExploreTitleRailExpandClick, title, { rail: headings })}
58
58
  fetchFunction={(page) => getListTitles({ ...params, page })}
59
- size={windowWidth >= mobileBreakpoint ? (properties.size || 'flexible') : 'huge'}
59
+ size={properties.size || 'flexible'}
60
60
  minimumLength={7} />
61
61
  </div>
62
62
  {/each}
@@ -7,7 +7,7 @@
7
7
  import type { APIPaginatedResult } from '$lib/types/api'
8
8
  import type { ExploreFilter } from '$lib/types/filter'
9
9
  import type { TitleData } from '$lib/types/title'
10
- import { hasConsentedTo } from '$lib/consent'
10
+ import { isRetargetingAllowed } from '$lib/retargeting'
11
11
  import { t } from '$lib/localization'
12
12
  import { trackViaPixel } from '@playpilot/retargeting-tracking'
13
13
  import Button from '../../Button.svelte'
@@ -101,7 +101,7 @@
101
101
  if (!query) return
102
102
 
103
103
  track(TrackingEvent.ExploreSearch, null, { query })
104
- if (hasConsentedTo('pixels')) trackViaPixel(MetaEvent.SearchQuery, { query })
104
+ if (isRetargetingAllowed()) trackViaPixel(MetaEvent.SearchQuery, { query })
105
105
  }, 100)
106
106
  }
107
107
 
@@ -2,7 +2,7 @@
2
2
  import genreData from '$lib/data/genres.json'
3
3
  import { MetaEvent, MetaSource } from '$lib/enums/TrackingEvent'
4
4
  import { t } from '$lib/localization'
5
- import { isPixelAllowed } from '$lib/pixel'
5
+ import { isRetargetingAllowed } from '$lib/retargeting'
6
6
  import { trackViewViaPixel } from '@playpilot/retargeting-tracking'
7
7
 
8
8
  interface Props {
@@ -20,7 +20,7 @@
20
20
  {@const genreName = genreData.find(g => g.slug === genre)?.name}
21
21
 
22
22
  {#if genreName}
23
- <div class="genre" {@attach isPixelAllowed() ? trackViewViaPixel(MetaEvent.GenreInterest, { genre: genreName, source: MetaSource.Card }) : null}>
23
+ <div class="genre" {@attach isRetargetingAllowed() ? trackViewViaPixel(MetaEvent.GenreInterest, { genre: genreName, source: MetaSource.Card }) : null}>
24
24
  {t(genreName)}
25
25
  </div>
26
26
  {/if}
@@ -6,7 +6,7 @@
6
6
  import type { ParticipantData } from '$lib/types/participant'
7
7
  import type { LinkInjectionDataType } from '$lib/types/injection'
8
8
  import { onMount, setContext } from 'svelte'
9
- import { isPixelAllowed } from '$lib/pixel'
9
+ import { isRetargetingAllowed } from '$lib/retargeting'
10
10
  import { trackViaPixel } from '@playpilot/retargeting-tracking'
11
11
  import Popover from './Popover.svelte'
12
12
  import Title from './Title.svelte'
@@ -32,7 +32,7 @@
32
32
  if (type === 'title') track(TrackingEvent.InjectionPopoverView, data as TitleData, { type })
33
33
  if (type === 'participant') track(TrackingEvent.InjectionPopoverView, null, { type, participant: (data as ParticipantData).name })
34
34
 
35
- if (isPixelAllowed() && type === 'title') trackViaPixel(MetaEvent.TitleInterest, { title: (data as TitleData).title, source: MetaSource.Card })
35
+ if (isRetargetingAllowed() && type === 'title') trackViaPixel(MetaEvent.TitleInterest, { title: (data as TitleData).title, source: MetaSource.Card })
36
36
 
37
37
  onMount(() => {
38
38
  setOffset()
@@ -5,7 +5,7 @@
5
5
  import { getFirstAdOfType } from '$lib/api/ads'
6
6
  import { exploreParentSelector } from '$lib/explore'
7
7
  import { onMount, setContext } from 'svelte'
8
- import { isPixelAllowed } from '$lib/pixel'
8
+ import { isRetargetingAllowed } from '$lib/retargeting'
9
9
  import { trackViaPixel } from '@playpilot/retargeting-tracking'
10
10
  import Modal from './Modal.svelte'
11
11
  import Title from '../Title.svelte'
@@ -31,7 +31,7 @@
31
31
 
32
32
  track(TrackingEvent.TitleModalView, title)
33
33
 
34
- if (isPixelAllowed()) trackViaPixel(MetaEvent.TitleInterest, { title: title.title, source: MetaSource.Card })
34
+ if (isRetargetingAllowed()) trackViaPixel(MetaEvent.TitleInterest, { title: title.title, source: MetaSource.Card })
35
35
 
36
36
  onMount(() => {
37
37
  const openTimestamp = Date.now()
@@ -7,7 +7,7 @@
7
7
  import type { TitleData } from '$lib/types/title'
8
8
  import ListTitle from './ListTitle.svelte'
9
9
  import { t } from '$lib/localization'
10
- import { hasConsentedTo } from '$lib/consent'
10
+ import { isRetargetingAllowed } from '$lib/retargeting'
11
11
  import { trackViaPixel } from '@playpilot/retargeting-tracking'
12
12
  import { MetaEvent } from '$lib/enums/TrackingEvent'
13
13
 
@@ -29,7 +29,7 @@
29
29
 
30
30
  onMount(loadMore)
31
31
 
32
- if (hasConsentedTo('pixels')) trackViaPixel(MetaEvent.ParticipantView, { participant: participant.name })
32
+ if (isRetargetingAllowed()) trackViaPixel(MetaEvent.ParticipantView, { participant: participant.name })
33
33
 
34
34
  function formatDate(dateString: string): string {
35
35
  const date = new Date(dateString)
@@ -7,7 +7,7 @@
7
7
  import type { PlaylinkData } from '$lib/types/playlink'
8
8
  import { trackClickViaPixel, trackViewViaPixel } from '@playpilot/retargeting-tracking'
9
9
  import { MetaEvent, MetaSource } from '$lib/enums/TrackingEvent'
10
- import { isPixelAllowed } from '$lib/pixel'
10
+ import { isRetargetingAllowed } from '$lib/retargeting'
11
11
 
12
12
  interface Props {
13
13
  playlink: PlaylinkData
@@ -20,7 +20,7 @@
20
20
 
21
21
  const { name, url, logo_url, highlighted, cta_text, action_text, pixels, extra_info: { category } } = $derived(playlink)
22
22
 
23
- const usePixel = $derived(isPixelAllowed() && !highlighted)
23
+ const usePixel = $derived(isRetargetingAllowed() && !highlighted)
24
24
 
25
25
  const categoryStrings = {
26
26
  AVOD: t('Stream'),
@@ -7,11 +7,13 @@
7
7
  interface Props extends Omit<ComponentProps<typeof TitlesRail>, 'titles'> {
8
8
  fetchFunction: (page: number) => Promise<APIPaginatedResult<TitleData>>
9
9
  maxPage?: number
10
+ lazy?: boolean
10
11
  }
11
12
 
12
13
  const {
13
14
  fetchFunction,
14
15
  maxPage = 4,
16
+ lazy = false,
15
17
  expandedTitle = $bindable(null),
16
18
  expandedRailKey = $bindable(null),
17
19
  ...rest
@@ -24,6 +26,12 @@
24
26
  let page = $state(1)
25
27
  let hasMorePages = $state(false)
26
28
  let loading = $state(true)
29
+ let element: HTMLElement | null = $state(null)
30
+ let hasBeenVisible = $derived(!lazy)
31
+
32
+ $effect(() => {
33
+ if (hasBeenVisible) fetchTitles()
34
+ })
27
35
 
28
36
  $effect(() => {
29
37
  if (loading) return
@@ -35,7 +43,22 @@
35
43
  fetchTitles()
36
44
  })
37
45
 
38
- onMount(fetchTitles)
46
+ onMount(() => {
47
+ if (!lazy) return
48
+ if (!element) return
49
+
50
+ const observer = new IntersectionObserver(([entry]) => {
51
+ if (!entry.isIntersecting) return
52
+
53
+ hasBeenVisible = true
54
+
55
+ observer.disconnect()
56
+ }, { rootMargin: window.innerHeight / 2 + 'px' })
57
+
58
+ observer.observe(element)
59
+
60
+ return () => observer?.disconnect()
61
+ })
39
62
 
40
63
  async function fetchTitles(): Promise<void> {
41
64
  loading = true
@@ -52,8 +75,10 @@
52
75
  }
53
76
  </script>
54
77
 
55
- {#if !titles.length && loading}
56
- <TitlesRail titles={emptyPromise} {...rest} />
57
- {:else}
58
- <TitlesRail {titles} {...rest} bind:shown />
59
- {/if}
78
+ <div bind:this={element}>
79
+ {#if (lazy && !hasBeenVisible) || (!titles.length && loading)}
80
+ <TitlesRail titles={emptyPromise} {...rest} />
81
+ {:else}
82
+ <TitlesRail {titles} {...rest} bind:shown />
83
+ {/if}
84
+ </div>
@@ -49,6 +49,7 @@
49
49
 
50
50
  <style lang="scss">
51
51
  .heading {
52
+ min-height: 1lh;
52
53
  margin: margin(1) 0 margin(0.5);
53
54
  font-size: theme(rail-title-font-size, 18px);
54
55
  line-height: normal;
@@ -2,7 +2,7 @@
2
2
  import genreData from '$lib/data/genres.json'
3
3
  import { MetaEvent, MetaSource } from '$lib/enums/TrackingEvent'
4
4
  import { keyDataAttribute } from '$lib/injection'
5
- import { isPixelAllowed } from '$lib/pixel'
5
+ import { isRetargetingAllowed } from '$lib/retargeting'
6
6
  import type { LinkInjection } from '$lib/types/injection'
7
7
  import type { TitleData } from '$lib/types/title'
8
8
  import { trackViaPixel } from '@playpilot/retargeting-tracking'
@@ -15,7 +15,7 @@
15
15
  const { linkInjections }: Props = $props()
16
16
 
17
17
  onMount(() => {
18
- if (!isPixelAllowed()) return
18
+ if (!isRetargetingAllowed()) return
19
19
 
20
20
  const observer = new IntersectionObserver((entries) => {
21
21
  entries.forEach(entry => {
@@ -1,5 +1,5 @@
1
1
  import { hasConsentedTo } from '$lib/consent'
2
- import { isPixelAllowed } from '$lib/pixel'
2
+ import { isRetargetingAllowed } from '$lib/retargeting'
3
3
  import { getUserId } from '$lib/user'
4
4
  import { RETARGETING_USER_ID_KEY } from '@playpilot/retargeting-tracking'
5
5
  import { beforeEach, describe, expect, it, vi } from 'vitest'
@@ -12,7 +12,7 @@ vi.mock('$lib/user', () => ({
12
12
  getUserId: vi.fn(),
13
13
  }))
14
14
 
15
- describe('pixel.ts', () => {
15
+ describe('retargeting.ts', () => {
16
16
  beforeEach(() => {
17
17
  // @ts-ignore
18
18
  window.PlayPilotLinkInjections = {}
@@ -28,35 +28,35 @@ describe('pixel.ts', () => {
28
28
  vi.mocked(hasConsentedTo).mockImplementation(() => true)
29
29
  window.PlayPilotLinkInjections.config = null
30
30
 
31
- expect(isPixelAllowed()).toBe(false)
31
+ expect(isRetargetingAllowed()).toBe(false)
32
32
  })
33
33
 
34
34
  it('Should return false if config object is without allow_retargeting_pixels', () => {
35
35
  vi.mocked(hasConsentedTo).mockImplementation(() => true)
36
36
  window.PlayPilotLinkInjections.config = { something: true }
37
37
 
38
- expect(isPixelAllowed()).toBe(false)
38
+ expect(isRetargetingAllowed()).toBe(false)
39
39
  })
40
40
 
41
41
  it('Should return false if config object is allow_retargeting_pixels is false', () => {
42
42
  vi.mocked(hasConsentedTo).mockImplementation(() => true)
43
43
  window.PlayPilotLinkInjections.config = { allow_retargeting_pixels: false }
44
44
 
45
- expect(isPixelAllowed()).toBe(false)
45
+ expect(isRetargetingAllowed()).toBe(false)
46
46
  })
47
47
 
48
48
  it('Should return true if config object is allow_retargeting_pixels is true', () => {
49
49
  vi.mocked(hasConsentedTo).mockImplementation(() => true)
50
50
  window.PlayPilotLinkInjections.config = { allow_retargeting_pixels: true }
51
51
 
52
- expect(isPixelAllowed()).toBe(true)
52
+ expect(isRetargetingAllowed()).toBe(true)
53
53
  })
54
54
 
55
55
  it('Should return false if config object is allow_retargeting_pixels is true but hasConsentedTo is false', () => {
56
56
  vi.mocked(hasConsentedTo).mockImplementation(() => false)
57
57
  window.PlayPilotLinkInjections.config = { allow_retargeting_pixels: true }
58
58
 
59
- expect(isPixelAllowed()).toBe(false)
59
+ expect(isRetargetingAllowed()).toBe(false)
60
60
  })
61
61
 
62
62
  it('Should set user id on window', () => {
@@ -67,7 +67,7 @@ describe('pixel.ts', () => {
67
67
  // @ts-ignore
68
68
  expect(window[RETARGETING_USER_ID_KEY]).not.toBeTruthy()
69
69
 
70
- isPixelAllowed()
70
+ isRetargetingAllowed()
71
71
 
72
72
  // @ts-ignore
73
73
  expect(window[RETARGETING_USER_ID_KEY]).toBe('abc')
@@ -4,6 +4,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
4
4
  import ExploreHome from '../../../../../routes/components/Explore/Routes/ExploreHome.svelte'
5
5
  import { fetchTitles } from '$lib/api/titles'
6
6
  import { api } from '$lib/api/api'
7
+ import { mockIntersectionObserver } from '../../../../setup'
7
8
 
8
9
  vi.mock('$lib/api/titles', () => ({
9
10
  fetchTitles: vi.fn(),
@@ -16,6 +17,7 @@ vi.mock('$lib/api/api', () => ({
16
17
  describe('ExploreResults.svelte', () => {
17
18
  beforeEach(() => {
18
19
  vi.resetAllMocks()
20
+ mockIntersectionObserver()
19
21
  })
20
22
 
21
23
  it('Should fetch rails endpoint and titles for each rail', async () => {
@@ -15,8 +15,8 @@ vi.mock('$lib/tracking', () => ({
15
15
  track: vi.fn(),
16
16
  }))
17
17
 
18
- vi.mock('$lib/pixel', () => ({
19
- isPixelAllowed: vi.fn(),
18
+ vi.mock('$lib/retargeting', () => ({
19
+ isRetargetingAllowed: vi.fn(),
20
20
  }))
21
21
 
22
22
  vi.mock('$lib/api/participants', () => ({
@@ -15,8 +15,8 @@ vi.mock('$lib/tracking', () => ({
15
15
  track: vi.fn(),
16
16
  }))
17
17
 
18
- vi.mock('$lib/pixel', () => ({
19
- isPixelAllowed: vi.fn(),
18
+ vi.mock('$lib/retargeting', () => ({
19
+ isRetargetingAllowed: vi.fn(),
20
20
  }))
21
21
 
22
22
  vi.mock('$lib/api/participants', () => ({
@@ -8,8 +8,8 @@ vi.mock('$lib/tracking', () => ({
8
8
  track: vi.fn(),
9
9
  }))
10
10
 
11
- vi.mock('$lib/pixel', () => ({
12
- isPixelAllowed: vi.fn(),
11
+ vi.mock('$lib/retargeting', () => ({
12
+ isRetargetingAllowed: vi.fn(),
13
13
  }))
14
14
 
15
15
  vi.mock('$lib/consent', () => ({
@@ -11,8 +11,8 @@ vi.mock('$lib/tracking', () => ({
11
11
  track: vi.fn(),
12
12
  }))
13
13
 
14
- vi.mock('$lib/pixel', () => ({
15
- isPixelAllowed: vi.fn(),
14
+ vi.mock('$lib/retargeting', () => ({
15
+ isRetargetingAllowed: vi.fn(),
16
16
  }))
17
17
 
18
18
  vi.mock('svelte', async (importActual) => ({
@@ -11,8 +11,8 @@ vi.mock('$lib/tracking', () => ({
11
11
  track: vi.fn(),
12
12
  }))
13
13
 
14
- vi.mock('$lib/pixel', () => ({
15
- isPixelAllowed: vi.fn(),
14
+ vi.mock('$lib/retargeting', () => ({
15
+ isRetargetingAllowed: vi.fn(),
16
16
  }))
17
17
 
18
18
  vi.mock('$lib/api/participants', () => ({
@@ -1,108 +1,108 @@
1
- import { cleanup } from '@testing-library/svelte'
2
- import { afterEach, beforeAll, beforeEach, vi } from 'vitest'
3
- import { fakeFetch } from './helpers'
4
-
5
- vi.mock('svelte/transition')
6
-
7
- // https://github.com/jsdom/jsdom/issues/3429#issuecomment-1936128876
8
- const mockAnimations = () => {
9
- Element.prototype.animate ??= vi.fn().mockReturnValue({
10
- onfinish: null,
11
- finished: Promise.resolve(),
12
- cancel: vi.fn(),
13
- startTime: null,
14
- currentTime: null,
15
- })
16
-
17
- Element.prototype.getAnimations ??= vi.fn().mockReturnValue([])
18
- }
19
-
20
- const mockLocalStorage = () => {
21
- /** @type {Record<string, string>} */
22
- let store = {}
23
-
24
- // @ts-ignore
25
- ;(window).localStorage = {
26
- getItem: function (key) {
27
- return store[key] || null
28
- },
29
- setItem: function (key, value) {
30
- store[key] = value.toString()
31
- },
32
- removeItem: function (key) {
33
- delete store[key]
34
- },
35
- clear: function () {
36
- store = {}
37
- },
38
- }
39
- }
40
-
41
- const mockSessionStorage = () => {
42
- /** @type {Record<string, string>} */
43
- let store = {}
44
-
45
- // @ts-ignore
46
- ;(window).sessionStorage = {
47
- getItem: function (key) {
48
- return store[key] || null
49
- },
50
- setItem: function (key, value) {
51
- store[key] = value.toString()
52
- },
53
- removeItem: function (key) {
54
- delete store[key]
55
- },
56
- clear: function () {
57
- store = {}
58
- },
59
- }
60
- }
61
-
62
- const mockIntersectionObserver = () => {
63
- // @ts-ignore
64
- global.IntersectionObserver = vi.fn(() => ({
65
- disconnect: vi.fn(),
66
- observe: vi.fn(),
67
- unobserve: vi.fn(),
68
- }))
69
- }
70
-
71
- beforeAll(() => {
72
- fakeFetch()
73
- mockLocalStorage()
74
- mockSessionStorage()
75
- mockIntersectionObserver()
76
- })
77
-
78
- beforeEach(() => {
79
- // @ts-ignore
80
- window.PlayPilotLinkInjections = { token: 'some-token', require_consent: false }
81
-
82
- // Enable all consent
83
- // @ts-ignore
84
- window.__tcfapi = (command, _version, callback) => {
85
- if (command !== 'addEventListener') return
86
-
87
- setTimeout(() => callback({
88
- purpose: { consents: { 1: true, 2: true, 7: true, 8: true, 9: true, 10: true } },
89
- eventStatus: 'tcloaded',
90
- }, true), 0)
91
-
92
- return 1
93
- }
94
-
95
- // Reset cookies
96
- document.cookie.split(';').forEach((cookie) => document.cookie = cookie.replace(/^ +/, '').replace(/=.*/, '=;'))
97
-
98
- window.HTMLElement.prototype.scrollIntoView = vi.fn()
99
-
100
- localStorage.clear()
101
- sessionStorage.clear()
102
-
103
- mockAnimations()
104
- })
105
-
106
- afterEach(() => {
107
- cleanup()
108
- })
1
+ import { cleanup } from '@testing-library/svelte'
2
+ import { afterEach, beforeAll, beforeEach, vi } from 'vitest'
3
+ import { fakeFetch } from './helpers'
4
+
5
+ vi.mock('svelte/transition')
6
+
7
+ // https://github.com/jsdom/jsdom/issues/3429#issuecomment-1936128876
8
+ const mockAnimations = () => {
9
+ Element.prototype.animate ??= vi.fn().mockReturnValue({
10
+ onfinish: null,
11
+ finished: Promise.resolve(),
12
+ cancel: vi.fn(),
13
+ startTime: null,
14
+ currentTime: null,
15
+ })
16
+
17
+ Element.prototype.getAnimations ??= vi.fn().mockReturnValue([])
18
+ }
19
+
20
+ const mockLocalStorage = () => {
21
+ /** @type {Record<string, string>} */
22
+ let store = {}
23
+
24
+ // @ts-ignore
25
+ ;(window).localStorage = {
26
+ getItem: function (key) {
27
+ return store[key] || null
28
+ },
29
+ setItem: function (key, value) {
30
+ store[key] = value.toString()
31
+ },
32
+ removeItem: function (key) {
33
+ delete store[key]
34
+ },
35
+ clear: function () {
36
+ store = {}
37
+ },
38
+ }
39
+ }
40
+
41
+ const mockSessionStorage = () => {
42
+ /** @type {Record<string, string>} */
43
+ let store = {}
44
+
45
+ // @ts-ignore
46
+ ;(window).sessionStorage = {
47
+ getItem: function (key) {
48
+ return store[key] || null
49
+ },
50
+ setItem: function (key, value) {
51
+ store[key] = value.toString()
52
+ },
53
+ removeItem: function (key) {
54
+ delete store[key]
55
+ },
56
+ clear: function () {
57
+ store = {}
58
+ },
59
+ }
60
+ }
61
+
62
+ export const mockIntersectionObserver = () => {
63
+ // @ts-ignore
64
+ global.IntersectionObserver = vi.fn((callback) => ({
65
+ disconnect: vi.fn(),
66
+ observe: vi.fn(() => callback([{ isIntersecting: true }])),
67
+ unobserve: vi.fn(),
68
+ }))
69
+ }
70
+
71
+ beforeAll(() => {
72
+ fakeFetch()
73
+ mockLocalStorage()
74
+ mockSessionStorage()
75
+ mockIntersectionObserver()
76
+ })
77
+
78
+ beforeEach(() => {
79
+ // @ts-ignore
80
+ window.PlayPilotLinkInjections = { token: 'some-token', require_consent: false }
81
+
82
+ // Enable all consent
83
+ // @ts-ignore
84
+ window.__tcfapi = (command, _version, callback) => {
85
+ if (command !== 'addEventListener') return
86
+
87
+ setTimeout(() => callback({
88
+ purpose: { consents: { 1: true, 2: true, 7: true, 8: true, 9: true, 10: true } },
89
+ eventStatus: 'tcloaded',
90
+ }, true), 0)
91
+
92
+ return 1
93
+ }
94
+
95
+ // Reset cookies
96
+ document.cookie.split(';').forEach((cookie) => document.cookie = cookie.replace(/^ +/, '').replace(/=.*/, '=;'))
97
+
98
+ window.HTMLElement.prototype.scrollIntoView = vi.fn()
99
+
100
+ localStorage.clear()
101
+ sessionStorage.clear()
102
+
103
+ mockAnimations()
104
+ })
105
+
106
+ afterEach(() => {
107
+ cleanup()
108
+ })