@playpilot/tpi 7.0.0-beta.7 → 7.0.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/README.md +21 -4
- package/dist/editorial.mount.js +8 -8
- package/dist/link-injections.js +2 -2
- package/dist/mount.js +6 -6
- package/package.json +1 -1
- package/src/lib/api/ads.ts +1 -0
- package/src/lib/api/auth.ts +1 -1
- package/src/lib/tracking.ts +1 -0
- package/src/lib/types/config.d.ts +6 -0
- package/src/lib/types/script.d.ts +4 -0
- package/src/main.ts +7 -2
- package/src/routes/+page.svelte +2 -0
- package/src/routes/components/Debugger.svelte +6 -0
- package/src/routes/components/Explore/ExploreCallToAction.svelte +0 -3
- package/src/routes/components/ListTitle.svelte +11 -2
- package/src/routes/components/Title.svelte +6 -2
- package/src/tests/lib/api/ads.test.js +8 -1
- package/src/tests/lib/tracking.test.js +32 -1
- package/src/tests/main.test.js +115 -20
- package/src/tests/mount.test.js +63 -0
- package/src/tests/routes/+page.test.js +33 -0
- package/src/tests/routes/components/ListTitle.test.js +11 -0
- package/src/tests/routes/components/Title.test.js +24 -0
- package/vite.config.js +22 -24
package/package.json
CHANGED
package/src/lib/api/ads.ts
CHANGED
|
@@ -30,6 +30,7 @@ export async function fetchAds(): Promise<Campaign[]> {
|
|
|
30
30
|
*/
|
|
31
31
|
export function getFirstAdOfType(format: CampaignFormat): Campaign | null {
|
|
32
32
|
if (!hasConsentedTo('ads')) return null
|
|
33
|
+
if (window.PlayPilotLinkInjections.no_affiliate) return null
|
|
33
34
|
|
|
34
35
|
return (window.PlayPilotLinkInjections?.ads || []).find(i => i.campaign_format === format) || null
|
|
35
36
|
}
|
package/src/lib/api/auth.ts
CHANGED
|
@@ -5,7 +5,7 @@ const cookieName = 'EncryptedToken'
|
|
|
5
5
|
const urlParam = 'articleReplacementEditToken'
|
|
6
6
|
const editorialParam = 'playpilot-editorial-mode'
|
|
7
7
|
|
|
8
|
-
export async function authorize({ href, throwError }: { href?: string, throwError?: boolean } = {
|
|
8
|
+
export async function authorize({ href = window.location.href, throwError = false }: { href?: string, throwError?: boolean } = {}): Promise<boolean> {
|
|
9
9
|
try {
|
|
10
10
|
const apiToken = getApiToken()
|
|
11
11
|
if (!apiToken) throw new Error('No token was provided')
|
package/src/lib/tracking.ts
CHANGED
|
@@ -37,6 +37,7 @@ export async function track(event: string, title: TitleData | null = null, paylo
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
payload.version = __SCRIPT_VERSION__
|
|
40
|
+
payload.time_since_initialize = window.PlayPilotLinkInjections?.time_at_initialize ? Date.now() - window.PlayPilotLinkInjections.time_at_initialize : 0
|
|
40
41
|
payload.url = getFullUrlPath()
|
|
41
42
|
payload.organization_sid = window.PlayPilotLinkInjections?.organization_sid || 'undefined'
|
|
42
43
|
payload.domain_sid = window.PlayPilotLinkInjections?.domain_sid || 'undefined'
|
|
@@ -44,6 +44,12 @@ export type ConfigResponse = {
|
|
|
44
44
|
*/
|
|
45
45
|
playlinks_disclaimer_text?: string
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Some partners may want to display titles without affiliate links, which currently comes down to no playlinks.
|
|
49
|
+
* This can also be set via the config on the script itself.
|
|
50
|
+
*/
|
|
51
|
+
no_affiliate?: boolean
|
|
52
|
+
|
|
47
53
|
/**
|
|
48
54
|
* Whether or not we can insert retargeting pixels. Not all third parties allow this and it is disabled by default
|
|
49
55
|
*/
|
|
@@ -34,6 +34,8 @@ export type ScriptConfig = {
|
|
|
34
34
|
initial_link_injections_promise?: Promise<LinkInjectionResponse> | null
|
|
35
35
|
// By default the script requires consent from the user through tcfapi. Can be disabled using this setting.
|
|
36
36
|
require_consent?: boolean
|
|
37
|
+
// Some partners may want to display titles without affiliate links, which currently comes down to no playlinks.
|
|
38
|
+
no_affiliate?: boolean
|
|
37
39
|
// Used to check if a user has consented via tcfapi to various consent categories.
|
|
38
40
|
consents?: ConsentOptions
|
|
39
41
|
// The config response from the api, saved to the window object to be used without having to pass the response around.
|
|
@@ -42,4 +44,6 @@ export type ScriptConfig = {
|
|
|
42
44
|
ads?: Campaign[]
|
|
43
45
|
// The region the user is in, either fetched from an external service or based on the default region in the config object
|
|
44
46
|
region?: string | null
|
|
47
|
+
// The time at which the script was initialized
|
|
48
|
+
time_at_initialize?: number
|
|
45
49
|
}
|
package/src/main.ts
CHANGED
|
@@ -22,8 +22,10 @@ window.PlayPilotLinkInjections = {
|
|
|
22
22
|
split_test_identifiers: {},
|
|
23
23
|
evaluated_link_injections: [],
|
|
24
24
|
initial_link_injections_promise: null,
|
|
25
|
+
time_at_initialize: 0,
|
|
25
26
|
ads: [],
|
|
26
27
|
require_consent: true,
|
|
28
|
+
no_affiliate: false,
|
|
27
29
|
consents: {
|
|
28
30
|
ads: false,
|
|
29
31
|
pixels: false,
|
|
@@ -34,7 +36,7 @@ window.PlayPilotLinkInjections = {
|
|
|
34
36
|
config: {},
|
|
35
37
|
app: null,
|
|
36
38
|
|
|
37
|
-
async initialize(options = { token: '', selector: '', after_article_selector: '', after_article_insert_position: '', language: null, region: null, organization_sid: null, domain_sid: null, editorial_token: '', require_consent: true }): Promise<void> {
|
|
39
|
+
async initialize(options = { token: '', selector: '', after_article_selector: '', after_article_insert_position: '', language: null, region: null, organization_sid: null, domain_sid: null, editorial_token: '', require_consent: true, no_affiliate: false }): Promise<void> {
|
|
38
40
|
if (!options.token) {
|
|
39
41
|
console.error('An API token is required.')
|
|
40
42
|
return
|
|
@@ -51,6 +53,8 @@ window.PlayPilotLinkInjections = {
|
|
|
51
53
|
this.organization_sid = options.organization_sid
|
|
52
54
|
this.domain_sid = options.domain_sid
|
|
53
55
|
this.require_consent = options.require_consent
|
|
56
|
+
this.no_affiliate = options.no_affiliate
|
|
57
|
+
this.time_at_initialize = Date.now()
|
|
54
58
|
|
|
55
59
|
if (this.require_consent === false) {
|
|
56
60
|
setConsent({
|
|
@@ -82,12 +86,13 @@ window.PlayPilotLinkInjections = {
|
|
|
82
86
|
|
|
83
87
|
const script = document.createElement('script')
|
|
84
88
|
|
|
89
|
+
script.id = 'playpilot-mount'
|
|
85
90
|
script.src = `https://cdn.jsdelivr.net/npm/@playpilot/tpi@${__SCRIPT_VERSION__}/dist/${shouldLoadEditorial ? 'editorial.' : ''}mount.js`
|
|
86
91
|
// script.src = './dist/mount.js' // Use me during development of this script
|
|
87
92
|
|
|
88
93
|
script.onload = () => window.PlayPilotMount?.mount()
|
|
89
94
|
|
|
90
|
-
document.body.
|
|
95
|
+
document.body.appendChild(script)
|
|
91
96
|
},
|
|
92
97
|
}
|
|
93
98
|
|
package/src/routes/+page.svelte
CHANGED
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
track(TrackingEvent.ArticlePageView)
|
|
59
59
|
|
|
60
60
|
if (!aiInjections.length && !manualInjections.length) return
|
|
61
|
+
if (window.PlayPilotLinkInjections.no_affiliate) return
|
|
61
62
|
|
|
62
63
|
window.PlayPilotLinkInjections.ads = await fetchAds()
|
|
63
64
|
}
|
|
@@ -77,6 +78,7 @@
|
|
|
77
78
|
|
|
78
79
|
if (config?.custom_style) insertCustomStyle(config.custom_style || '')
|
|
79
80
|
if (config?.explore_navigation_selector) insertExploreIntoNavigation()
|
|
81
|
+
if (config?.no_affiliate) window.PlayPilotLinkInjections.no_affiliate = true
|
|
80
82
|
|
|
81
83
|
isUrlExcluded = isUrlExcludedViaConfig(config)
|
|
82
84
|
if (isUrlExcluded) return
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { SplitTest } from '$lib/enums/SplitTest'
|
|
3
|
+
import { getPageTextAndElements } from '$lib/injectionElements'
|
|
3
4
|
import { getFullUrlPath } from '$lib/url'
|
|
4
5
|
import { onDestroy } from 'svelte'
|
|
5
6
|
|
|
@@ -160,6 +161,11 @@
|
|
|
160
161
|
|
|
161
162
|
<hr />
|
|
162
163
|
|
|
164
|
+
<button onclick={() => console.log(getPageTextAndElements(window.PlayPilotLinkInjections.config))}>Output elements in console</button>
|
|
165
|
+
<button onclick={() => console.log(getPageTextAndElements(window.PlayPilotLinkInjections.config).pageText)}>Output text in console</button>
|
|
166
|
+
|
|
167
|
+
<hr />
|
|
168
|
+
|
|
163
169
|
<button onclick={onrerender}>Re-inject</button>
|
|
164
170
|
|
|
165
171
|
{#if isUsingBetaScript}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import IconArrow from '../Icons/IconArrow.svelte'
|
|
3
|
-
import ImageTitlesList from '$lib/images/titles-list.webp'
|
|
4
3
|
import { openModal } from '$lib/modal'
|
|
5
4
|
</script>
|
|
6
5
|
|
|
7
6
|
<button class="call-to-action" onclick={() => openModal({ type: 'explore' })}>
|
|
8
|
-
<img src={ImageTitlesList} alt="" width="70" height="57" />
|
|
9
|
-
|
|
10
7
|
<div>
|
|
11
8
|
<strong>Looking for something else?</strong>
|
|
12
9
|
<div>Use our streamingguide</div>
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const { title, onclick = () => null }: Props = $props()
|
|
14
|
+
|
|
15
|
+
const noAffiliate = !!window.PlayPilotLinkInjections?.no_affiliate
|
|
14
16
|
</script>
|
|
15
17
|
|
|
16
18
|
<button class="title" {onclick} data-testid="title">
|
|
@@ -35,11 +37,13 @@
|
|
|
35
37
|
{/if}
|
|
36
38
|
</div>
|
|
37
39
|
|
|
38
|
-
<div class="description">
|
|
40
|
+
<div class="description" class:large={noAffiliate}>
|
|
39
41
|
{title.description}
|
|
40
42
|
</div>
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
{#if !noAffiliate}
|
|
45
|
+
<PlaylinksCompact playlinks={title.providers} />
|
|
46
|
+
{/if}
|
|
43
47
|
</div>
|
|
44
48
|
|
|
45
49
|
<div class="action">
|
|
@@ -129,6 +133,11 @@
|
|
|
129
133
|
-webkit-box-orient: vertical;
|
|
130
134
|
font-size: theme(detail-font-size-small, font-size-small);
|
|
131
135
|
color: theme(list-item-description-text-color, text-color);
|
|
136
|
+
|
|
137
|
+
&.large {
|
|
138
|
+
line-clamp: 2;
|
|
139
|
+
-webkit-line-clamp: 2;
|
|
140
|
+
}
|
|
132
141
|
}
|
|
133
142
|
|
|
134
143
|
.action {
|
|
@@ -24,9 +24,11 @@
|
|
|
24
24
|
|
|
25
25
|
const { title, small = false }: Props = $props()
|
|
26
26
|
|
|
27
|
+
const noAffiliate = !!window.PlayPilotLinkInjections?.no_affiliate
|
|
28
|
+
|
|
27
29
|
setContext('title', title)
|
|
28
30
|
|
|
29
|
-
const showDescription = $derived(!small && title.description)
|
|
31
|
+
const showDescription = $derived((!small || noAffiliate) && title.description)
|
|
30
32
|
|
|
31
33
|
let posterLoaded = $state(false)
|
|
32
34
|
let backgroundLoaded = $state(false)
|
|
@@ -71,7 +73,9 @@
|
|
|
71
73
|
<Description text={title.description!} blurb={title.blurb} onclick={() => track(TrackingEvent.ExpandTitleDescription, title)} />
|
|
72
74
|
{/if}
|
|
73
75
|
|
|
74
|
-
|
|
76
|
+
{#if !noAffiliate}
|
|
77
|
+
<Playlinks playlinks={title.providers} {title} />
|
|
78
|
+
{/if}
|
|
75
79
|
|
|
76
80
|
<ParticipantsRail {title} />
|
|
77
81
|
<SimilarRail {title} />
|
|
@@ -81,7 +81,7 @@ describe('$lib/api/ads', () => {
|
|
|
81
81
|
expect(getFirstAdOfType('top_scroll')).toBe(null)
|
|
82
82
|
})
|
|
83
83
|
|
|
84
|
-
it('Should not return ads if valid ad was given but user did not consent to ads',
|
|
84
|
+
it('Should not return ads if valid ad was given but user did not consent to ads', () => {
|
|
85
85
|
vi.mocked(hasConsentedTo).mockImplementation(() => false)
|
|
86
86
|
|
|
87
87
|
// @ts-ignore
|
|
@@ -89,5 +89,12 @@ describe('$lib/api/ads', () => {
|
|
|
89
89
|
|
|
90
90
|
expect(getFirstAdOfType('top_scroll')).toBe(null)
|
|
91
91
|
})
|
|
92
|
+
|
|
93
|
+
it('Should not return ads even if given if no_affiliate is true', () => {
|
|
94
|
+
// @ts-ignore
|
|
95
|
+
window.PlayPilotLinkInjections = { ads: [{ campaign_format: 'top_scroll' }], no_affiliate: true }
|
|
96
|
+
|
|
97
|
+
expect(getFirstAdOfType('top_scroll')).toBe(null)
|
|
98
|
+
})
|
|
92
99
|
})
|
|
93
100
|
})
|
|
@@ -21,6 +21,7 @@ describe('$lib/tracking', () => {
|
|
|
21
21
|
window.PlayPilotLinkInjections = {}
|
|
22
22
|
|
|
23
23
|
vi.resetAllMocks()
|
|
24
|
+
vi.useRealTimers()
|
|
24
25
|
|
|
25
26
|
fakeFetch()
|
|
26
27
|
vi.mocked(hasConsentedTo).mockImplementation(() => true)
|
|
@@ -72,7 +73,7 @@ describe('$lib/tracking', () => {
|
|
|
72
73
|
expect(global.fetch).toHaveBeenCalledWith(
|
|
73
74
|
expect.any(String),
|
|
74
75
|
expect.objectContaining({
|
|
75
|
-
|
|
76
|
+
|
|
76
77
|
body: expect.stringContaining(`"version":"${__SCRIPT_VERSION__}"`),
|
|
77
78
|
}),
|
|
78
79
|
)
|
|
@@ -175,6 +176,36 @@ describe('$lib/tracking', () => {
|
|
|
175
176
|
|
|
176
177
|
expect(global.fetch).not.toHaveBeenCalled()
|
|
177
178
|
})
|
|
179
|
+
|
|
180
|
+
it('Should include time_since_initialize', async () => {
|
|
181
|
+
vi.useFakeTimers()
|
|
182
|
+
|
|
183
|
+
window.PlayPilotLinkInjections.time_at_initialize = Date.now()
|
|
184
|
+
|
|
185
|
+
vi.advanceTimersByTime(150)
|
|
186
|
+
|
|
187
|
+
track('Some Event')
|
|
188
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
189
|
+
expect.any(String),
|
|
190
|
+
expect.objectContaining({
|
|
191
|
+
body: expect.stringContaining('"time_since_initialize":150'),
|
|
192
|
+
}),
|
|
193
|
+
)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('Should include time_since_initialize set to 0 if window object was not present', async () => {
|
|
197
|
+
vi.useFakeTimers()
|
|
198
|
+
|
|
199
|
+
vi.advanceTimersByTime(150)
|
|
200
|
+
|
|
201
|
+
track('Some Event')
|
|
202
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
203
|
+
expect.any(String),
|
|
204
|
+
expect.objectContaining({
|
|
205
|
+
body: expect.stringContaining('"time_since_initialize":0'),
|
|
206
|
+
}),
|
|
207
|
+
)
|
|
208
|
+
})
|
|
178
209
|
})
|
|
179
210
|
|
|
180
211
|
describe('setTrackingSids', () => {
|
package/src/tests/main.test.js
CHANGED
|
@@ -1,48 +1,143 @@
|
|
|
1
1
|
import { setConsent } from '$lib/consent'
|
|
2
2
|
import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import { fakeFetch } from './helpers'
|
|
4
|
+
import { fetchConfig } from '$lib/api/config'
|
|
5
|
+
import { waitFor } from '@testing-library/svelte'
|
|
6
|
+
import { isUrlExcludedViaConfig } from '$lib/url'
|
|
7
|
+
import { pollLinkInjections } from '$lib/api/externalPages'
|
|
8
|
+
import { getAuthToken, isEditorialModeEnabled } from '$lib/api/auth'
|
|
3
9
|
|
|
4
10
|
vi.mock('$lib/consent', () => ({
|
|
5
11
|
setConsent: vi.fn(),
|
|
6
12
|
hasConsentedTo: vi.fn(),
|
|
7
13
|
}))
|
|
8
14
|
|
|
15
|
+
vi.mock('$lib/api/config', () => ({
|
|
16
|
+
fetchConfig: vi.fn(),
|
|
17
|
+
}))
|
|
18
|
+
|
|
19
|
+
vi.mock('$lib/api/externalPages', () => ({
|
|
20
|
+
pollLinkInjections: vi.fn(),
|
|
21
|
+
}))
|
|
22
|
+
|
|
23
|
+
vi.mock('$lib/url', () => ({
|
|
24
|
+
isUrlExcludedViaConfig: vi.fn(),
|
|
25
|
+
}))
|
|
26
|
+
|
|
27
|
+
vi.mock('$lib/api/auth', () => ({
|
|
28
|
+
getAuthToken: vi.fn(),
|
|
29
|
+
isEditorialModeEnabled: vi.fn(),
|
|
30
|
+
}))
|
|
31
|
+
|
|
9
32
|
describe('main.ts', () => {
|
|
10
|
-
beforeEach(() => {
|
|
33
|
+
beforeEach(async () => {
|
|
34
|
+
document.body.innerHTML = ''
|
|
35
|
+
|
|
36
|
+
fakeFetch()
|
|
37
|
+
|
|
11
38
|
vi.resetModules()
|
|
12
39
|
vi.resetAllMocks()
|
|
40
|
+
|
|
41
|
+
await import('../main')
|
|
13
42
|
})
|
|
14
43
|
|
|
15
44
|
afterAll(() => {
|
|
16
45
|
vi.resetModules()
|
|
17
46
|
})
|
|
18
47
|
|
|
19
|
-
|
|
20
|
-
|
|
48
|
+
describe('initialize', () => {
|
|
49
|
+
it('Should not call setConsent when only a token is passed', () => {
|
|
50
|
+
window.PlayPilotLinkInjections.initialize({ token: 'a' })
|
|
51
|
+
|
|
52
|
+
expect(setConsent).not.toHaveBeenCalled()
|
|
53
|
+
|
|
54
|
+
expect(window.PlayPilotLinkInjections.consents).toEqual({
|
|
55
|
+
ads: false,
|
|
56
|
+
pixels: false,
|
|
57
|
+
tracking: false,
|
|
58
|
+
split_tests: false,
|
|
59
|
+
affiliate: false,
|
|
60
|
+
})
|
|
61
|
+
})
|
|
21
62
|
|
|
22
|
-
|
|
63
|
+
it('Should call setConsent when require_consent is false', () => {
|
|
64
|
+
window.PlayPilotLinkInjections.initialize({ token: 'a', require_consent: false })
|
|
23
65
|
|
|
24
|
-
|
|
66
|
+
expect(setConsent).toHaveBeenCalledWith({
|
|
67
|
+
ads: true,
|
|
68
|
+
pixels: true,
|
|
69
|
+
tracking: true,
|
|
70
|
+
split_tests: true,
|
|
71
|
+
affiliate: true,
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('Should call config object and set the result to the window object', async () => {
|
|
76
|
+
vi.mocked(fetchConfig).mockResolvedValue({ html_selector: 'some_value' })
|
|
77
|
+
|
|
78
|
+
window.PlayPilotLinkInjections.initialize({ token: 'a' })
|
|
25
79
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
80
|
+
expect(fetchConfig).toHaveBeenCalled()
|
|
81
|
+
|
|
82
|
+
await waitFor(() => {
|
|
83
|
+
expect(window.PlayPilotLinkInjections.config).toEqual({ html_selector: 'some_value' })
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('Should not call pollLinkInjections if config object excludes page', async () => {
|
|
88
|
+
vi.mocked(isUrlExcludedViaConfig).mockReturnValue(true)
|
|
89
|
+
|
|
90
|
+
window.PlayPilotLinkInjections.initialize({ token: 'a' })
|
|
91
|
+
|
|
92
|
+
expect(fetchConfig).toHaveBeenCalled()
|
|
93
|
+
|
|
94
|
+
await new Promise(res => setTimeout(res))
|
|
95
|
+
|
|
96
|
+
expect(pollLinkInjections).not.toHaveBeenCalled()
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('Should call pollLinkInjections if config object does not page', async () => {
|
|
100
|
+
vi.mocked(isUrlExcludedViaConfig).mockReturnValue(false)
|
|
101
|
+
|
|
102
|
+
window.PlayPilotLinkInjections.initialize({ token: 'a' })
|
|
103
|
+
|
|
104
|
+
expect(fetchConfig).toHaveBeenCalled()
|
|
105
|
+
|
|
106
|
+
await new Promise(res => setTimeout(res))
|
|
107
|
+
|
|
108
|
+
expect(pollLinkInjections).toHaveBeenCalled()
|
|
32
109
|
})
|
|
33
110
|
})
|
|
34
111
|
|
|
35
|
-
|
|
36
|
-
|
|
112
|
+
describe('mount', () => {
|
|
113
|
+
it('Should insert script tag', () => {
|
|
114
|
+
window.PlayPilotLinkInjections.mount()
|
|
115
|
+
|
|
116
|
+
expect(document.querySelector('script#playpilot-mount')).toBeTruthy()
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('Should insert script tag with editorial mode if editiorial mode is enabled', () => {
|
|
120
|
+
vi.mocked(isEditorialModeEnabled).mockReturnValueOnce(true)
|
|
121
|
+
|
|
122
|
+
window.PlayPilotLinkInjections.mount()
|
|
123
|
+
expect(/** @type {HTMLScriptElement} */(document.querySelector('script#playpilot-mount')).src).toContain('editorial.mount.js')
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('Should insert script tag with editorial mode if editiorial mode is disabled but auth token is present', () => {
|
|
127
|
+
vi.mocked(isEditorialModeEnabled).mockReturnValueOnce(false)
|
|
128
|
+
vi.mocked(getAuthToken).mockReturnValueOnce('abc')
|
|
129
|
+
|
|
130
|
+
window.PlayPilotLinkInjections.mount()
|
|
131
|
+
expect(/** @type {HTMLScriptElement} */(document.querySelector('script#playpilot-mount')).src).toContain('editorial.mount.js')
|
|
132
|
+
})
|
|
37
133
|
|
|
38
|
-
|
|
134
|
+
it('Should insert script tag without editorial mode if editiorial mode is disabled but auth token is present', () => {
|
|
135
|
+
vi.mocked(isEditorialModeEnabled).mockReturnValueOnce(false)
|
|
136
|
+
vi.mocked(getAuthToken).mockReturnValueOnce('')
|
|
39
137
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
tracking: true,
|
|
44
|
-
split_tests: true,
|
|
45
|
-
affiliate: true,
|
|
138
|
+
window.PlayPilotLinkInjections.mount()
|
|
139
|
+
expect(/** @type {HTMLScriptElement} */(document.querySelector('script#playpilot-mount')).src).not.toContain('editorial.mount.js')
|
|
140
|
+
expect(/** @type {HTMLScriptElement} */(document.querySelector('script#playpilot-mount')).src).toContain('mount.js')
|
|
46
141
|
})
|
|
47
142
|
})
|
|
48
143
|
})
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { fakeFetch } from './helpers'
|
|
3
|
+
import { clearLinkInjections } from '$lib/injection'
|
|
4
|
+
import { mount } from 'svelte'
|
|
5
|
+
|
|
6
|
+
vi.mock('$lib/injection', () => ({
|
|
7
|
+
clearLinkInjections: vi.fn(),
|
|
8
|
+
}))
|
|
9
|
+
|
|
10
|
+
vi.mock('svelte', () => ({
|
|
11
|
+
mount: vi.fn(),
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
describe('mount.ts', () => {
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
window.PlayPilotLinkInjections = {}
|
|
18
|
+
document.body.innerHTML = ''
|
|
19
|
+
|
|
20
|
+
fakeFetch()
|
|
21
|
+
|
|
22
|
+
vi.resetModules()
|
|
23
|
+
vi.resetAllMocks()
|
|
24
|
+
|
|
25
|
+
await import('../mount')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('mount', () => {
|
|
29
|
+
it('Should mount app', () => {
|
|
30
|
+
window.PlayPilotMount.mount()
|
|
31
|
+
|
|
32
|
+
expect(mount).toHaveBeenCalledWith(expect.any(Function), { target: expect.any(HTMLElement) })
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('Should assign app to window PlayPilotLinkInjections object', () => {
|
|
36
|
+
vi.mocked(mount).mockReturnValueOnce({ some_key: 'Some value' })
|
|
37
|
+
|
|
38
|
+
window.PlayPilotMount.mount()
|
|
39
|
+
|
|
40
|
+
expect(window.PlayPilotLinkInjections.app).toEqual({ some_key: 'Some value' })
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('destroy', () => {
|
|
45
|
+
it('Should call clearLinkInjections and remove link injections element', () => {
|
|
46
|
+
document.body.innerHTML = '<div id="playpilot-link-injection"></div>'
|
|
47
|
+
|
|
48
|
+
window.PlayPilotMount.destroy()
|
|
49
|
+
|
|
50
|
+
expect(document.body.innerHTML).toBe('')
|
|
51
|
+
expect(clearLinkInjections).toHaveBeenCalled()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('Should clear app on window PlayPilotLinkInjections object', () => {
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
window.PlayPilotLinkInjections = { app: {} }
|
|
57
|
+
|
|
58
|
+
window.PlayPilotMount.destroy()
|
|
59
|
+
|
|
60
|
+
expect(window.PlayPilotLinkInjections.app).toBe(null)
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
})
|
|
@@ -475,6 +475,19 @@ describe('$routes/+page.svelte', () => {
|
|
|
475
475
|
expect(fetchAds).not.toHaveBeenCalled()
|
|
476
476
|
})
|
|
477
477
|
|
|
478
|
+
it('Should not fetch ads if no_affilite is true', async () => {
|
|
479
|
+
// @ts-ignore
|
|
480
|
+
vi.mocked(pollLinkInjections).mockResolvedValueOnce({ ai_injections: [{}], manual_injections: [{}] })
|
|
481
|
+
// @ts-ignore
|
|
482
|
+
window.PlayPilotLinkInjections = { no_affiliate: true }
|
|
483
|
+
|
|
484
|
+
render(page)
|
|
485
|
+
|
|
486
|
+
await new Promise(res => setTimeout(res, 100)) // Await possible fetches
|
|
487
|
+
|
|
488
|
+
expect(fetchAds).not.toHaveBeenCalled()
|
|
489
|
+
})
|
|
490
|
+
|
|
478
491
|
describe('Config', () => {
|
|
479
492
|
describe('exclude_urls_pattern', () => {
|
|
480
493
|
it('Should not inject if config exclude_urls_pattern matches current url', async () => {
|
|
@@ -633,5 +646,25 @@ describe('$routes/+page.svelte', () => {
|
|
|
633
646
|
expect(document.querySelector('#playpilot-custom-style')).not.toBeTruthy()
|
|
634
647
|
})
|
|
635
648
|
})
|
|
649
|
+
|
|
650
|
+
describe('no_affiliate', () => {
|
|
651
|
+
it('Should not set window object if value is not given', async () => {
|
|
652
|
+
vi.mocked(fetchConfig).mockResolvedValueOnce({})
|
|
653
|
+
|
|
654
|
+
render(page)
|
|
655
|
+
|
|
656
|
+
await new Promise(res => setTimeout(res, 100)) // Await all fetches
|
|
657
|
+
expect(window.PlayPilotLinkInjections.no_affiliate).not.toBe(true)
|
|
658
|
+
})
|
|
659
|
+
|
|
660
|
+
it('Should set window object if value is true', async () => {
|
|
661
|
+
vi.mocked(fetchConfig).mockResolvedValueOnce({ no_affiliate: true })
|
|
662
|
+
|
|
663
|
+
render(page)
|
|
664
|
+
|
|
665
|
+
await new Promise(res => setTimeout(res, 100)) // Await all fetches
|
|
666
|
+
expect(window.PlayPilotLinkInjections.no_affiliate).toBe(true)
|
|
667
|
+
})
|
|
668
|
+
})
|
|
636
669
|
})
|
|
637
670
|
})
|
|
@@ -15,6 +15,8 @@ vi.mock('svelte', async (importActual) => ({
|
|
|
15
15
|
|
|
16
16
|
describe('ListTitle.svelte', () => {
|
|
17
17
|
beforeEach(() => {
|
|
18
|
+
// @ts-ignore
|
|
19
|
+
window.PlayPilotLinkInjections = {}
|
|
18
20
|
vi.resetAllMocks()
|
|
19
21
|
})
|
|
20
22
|
|
|
@@ -80,5 +82,14 @@ describe('ListTitle.svelte', () => {
|
|
|
80
82
|
|
|
81
83
|
expect(onclick).not.toHaveBeenCalled()
|
|
82
84
|
})
|
|
85
|
+
|
|
86
|
+
it('Should not render playlinks if no_affiliate is given in window object', () => {
|
|
87
|
+
window.PlayPilotLinkInjections.no_affiliate = true
|
|
88
|
+
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
const { container } = render(ListTitle, { title: { ...title, providers: playlinks } })
|
|
91
|
+
|
|
92
|
+
expect(container.querySelectorAll('.playlink')).toHaveLength(0)
|
|
93
|
+
})
|
|
83
94
|
})
|
|
84
95
|
})
|
|
@@ -26,6 +26,8 @@ vi.mock('svelte', async (importActual) => ({
|
|
|
26
26
|
|
|
27
27
|
describe('Title.svelte', () => {
|
|
28
28
|
beforeEach(() => {
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
window.PlayPilotLinkInjections = {}
|
|
29
31
|
vi.resetAllMocks()
|
|
30
32
|
})
|
|
31
33
|
|
|
@@ -104,4 +106,26 @@ describe('Title.svelte', () => {
|
|
|
104
106
|
|
|
105
107
|
expect(queryByText('Watch trailer')).not.toBeTruthy()
|
|
106
108
|
})
|
|
109
|
+
|
|
110
|
+
it('Should render playlinks by default', () => {
|
|
111
|
+
const { getByText } = render(Title, { title })
|
|
112
|
+
|
|
113
|
+
expect(getByText('Where to stream online')).toBeTruthy()
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('Should not render playlinks if no_affiliate is true on config', () => {
|
|
117
|
+
window.PlayPilotLinkInjections.no_affiliate = true
|
|
118
|
+
|
|
119
|
+
const { queryByText } = render(Title, { title })
|
|
120
|
+
|
|
121
|
+
expect(queryByText('Where to stream online')).not.toBeTruthy()
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('Should render description if no_affiliate is true even if small is true', () => {
|
|
125
|
+
window.PlayPilotLinkInjections.no_affiliate = true
|
|
126
|
+
|
|
127
|
+
const { getByText } = render(Title, { title: { ...title, description: 'Some description' }, small: true })
|
|
128
|
+
|
|
129
|
+
expect(getByText('Some description')).toBeTruthy()
|
|
130
|
+
})
|
|
107
131
|
})
|