@playpilot/tpi 5.9.2 → 5.10.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/link-injections.js +10 -10
- package/events.md +1 -0
- package/package.json +1 -1
- package/src/lib/actions/middlemouse.ts +18 -0
- package/src/lib/constants.ts +1 -0
- package/src/lib/enums/SplitTest.ts +0 -8
- package/src/lib/linkInjection.ts +2 -1
- package/src/lib/tracking.ts +9 -1
- package/src/lib/types/global.d.ts +1 -0
- package/src/main.ts +54 -26
- package/src/routes/+layout.svelte +0 -4
- package/src/routes/+page.svelte +3 -4
- package/src/routes/components/Ads/Display.svelte +2 -1
- package/src/routes/components/Ads/TopScroll.svelte +6 -4
- package/src/routes/components/Debugger.svelte +111 -0
- package/src/routes/components/Modal.svelte +2 -1
- package/src/tests/lib/tracking.test.js +22 -11
- package/src/tests/routes/components/Ads/Display.test.js +6 -1
- package/src/tests/routes/components/Ads/TopScroll.test.js +6 -1
- package/src/tests/routes/components/Debugger.test.js +54 -0
package/events.md
CHANGED
|
@@ -7,6 +7,7 @@ All events share a common payload:
|
|
|
7
7
|
- `url`: The URL of the related article. This is a URL with only the protocol, base url, and pathname. No parameters are included
|
|
8
8
|
- `organization_sid`: The sid for the related organization
|
|
9
9
|
- `domain_sid`: The sid for the related domain
|
|
10
|
+
- `device`: Basic device info containing the screen type, size, touch, and orientation
|
|
10
11
|
|
|
11
12
|
Events related to titles share an additional set of data (referred to below as `Title`):
|
|
12
13
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function middlemouse(node: HTMLElement, options: { onclick: (event: MouseEvent) => void }) {
|
|
2
|
+
let { onclick } = options
|
|
3
|
+
|
|
4
|
+
function mouseup(event: MouseEvent): MouseEvent | null {
|
|
5
|
+
if (event.button !== 1) return null
|
|
6
|
+
|
|
7
|
+
onclick(event)
|
|
8
|
+
return event
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
node.addEventListener('mouseup', mouseup)
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
destroy() {
|
|
15
|
+
node.removeEventListener('mouseup', mouseup)
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/lib/constants.ts
CHANGED
|
@@ -3,3 +3,4 @@ export const apiBaseUrl = 'https://partner-api.playpilot.tech/1.0.0'
|
|
|
3
3
|
export const imageBaseUrl = 'https://img-external.playpilot.tech'
|
|
4
4
|
|
|
5
5
|
export const imagePlaceholderDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFQAAAB+CAMAAACNgsajAAAAb1BMVEU1Q2fI1N5YZoNVYoFndI9qd5JBT3FFU3S8yNS3xNC4xNFBTnDG0t2lscJJV3e9ytaptcWToLOOm6/BzdiZprh3hJ1aaIWJlatte5VPXHx7iJ9zgZlfbYk3RWmNmq5jcY1XZIO2wtCjsMB+i6I9S25IprTeAAABqUlEQVRo3u3W2ZKCMBCF4T5ExRmRVXBfZnn/Z5wKiU5pz1AJ7ZXV/x03HxVCB0jTNE3TNE3TNO0l2rbPNxcFdk8334AINTUD5eSaWbPoQs0qw0CVN98BzNNgE4NVv+ZHsJliuNVt7UgotATAafp/5mZiG4waAB0N5k0kUeg0wMykKDfLvRTl5pxyCFFupjQVo9ykiRTlphzl5nNQNu8C9Hv2lylDT0W2NMyUoeXdLC68KUNLuM7O9HskQ0uLLAEUR2aOQjfORE5LzHP2PMehxpl2k6otM8eh2aQGkBlieyRBYbs3y5Rk6IPZn8mT65XJR6LcROGErwaoxqLm4XvkiTVsy1FoYe5n06zcjazp1Wk0umHz3k9BT6+bXjXR6PnRtKpr755PfRjx4WPz7tXW/26gGYnOvOmrM7xtiK4qYtDOrpGZtnR7JFcSi+Z1XZt7k5d4NCZmcrWxqMzkbRgqN+nAULHpx1RiylFvftJwlxjUz2bWdpPB7NnSxZih5RFrD20Vai4izGOgeenPukMSUE6hte5denI7NMyU1xrSNE3TNE3TNE17hX4ADHsS0j0OCOoAAAAASUVORK5CYII='
|
|
6
|
+
export const mobileBreakpoint = 600
|
package/src/lib/linkInjection.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { isHoldingSpecialKey } from './event'
|
|
|
8
8
|
import { playFallbackViewTransition } from './viewTransition'
|
|
9
9
|
import { prefersReducedMotion } from 'svelte/motion'
|
|
10
10
|
import { getNumberOfOccurrencesInArray } from './array'
|
|
11
|
+
import { mobileBreakpoint } from './constants'
|
|
11
12
|
|
|
12
13
|
const keyDataAttribute = 'data-playpilot-injection-key'
|
|
13
14
|
const keySelector = `[${keyDataAttribute}]`
|
|
@@ -348,7 +349,7 @@ function addLinkInjectionEventListeners(injections: LinkInjection[]): void {
|
|
|
348
349
|
playFallbackViewTransition(() => {
|
|
349
350
|
destroyLinkPopover(false)
|
|
350
351
|
openLinkModal(event, injection)
|
|
351
|
-
}, !prefersReducedMotion.current && window.innerWidth >=
|
|
352
|
+
}, !prefersReducedMotion.current && window.innerWidth >= mobileBreakpoint && !window.matchMedia("(pointer: coarse)").matches)
|
|
352
353
|
})
|
|
353
354
|
|
|
354
355
|
window.addEventListener('mousemove', (event) => {
|
package/src/lib/tracking.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mobileBreakpoint } from "./constants"
|
|
1
2
|
import type { TitleData } from "./types/title"
|
|
2
3
|
import { getFullUrlPath } from "./url"
|
|
3
4
|
|
|
@@ -10,7 +11,7 @@ const baseUrl = 'https://insights.playpilot.net'
|
|
|
10
11
|
* @param [title] Title related to the event
|
|
11
12
|
* @param [payload] Any data that will be included with the event
|
|
12
13
|
*/
|
|
13
|
-
export async function track(event: string, title: TitleData | null = null, payload: Record<string,
|
|
14
|
+
export async function track(event: string, title: TitleData | null = null, payload: Record<string, any> = {}): Promise<void> {
|
|
14
15
|
const headers = new Headers({ 'Content-Type': 'application/json' })
|
|
15
16
|
|
|
16
17
|
if (title) {
|
|
@@ -26,6 +27,13 @@ export async function track(event: string, title: TitleData | null = null, paylo
|
|
|
26
27
|
payload.url = getFullUrlPath()
|
|
27
28
|
payload.organization_sid = window.PlayPilotLinkInjections?.organization_sid
|
|
28
29
|
payload.domain_sid = window.PlayPilotLinkInjections?.domain_sid
|
|
30
|
+
payload.device = {
|
|
31
|
+
type: window.innerWidth > mobileBreakpoint ? 'desktop' : 'mobile',
|
|
32
|
+
width: window.innerWidth,
|
|
33
|
+
height: window.innerHeight,
|
|
34
|
+
touch: window.matchMedia('(pointer: coarse)').matches,
|
|
35
|
+
orientation: screen.orientation?.type || 'undefined', // It would be excluded from the payload if it was `undefined`, we still want the string if it is actually undefined
|
|
36
|
+
}
|
|
29
37
|
|
|
30
38
|
fetch(baseUrl, {
|
|
31
39
|
headers,
|
package/src/main.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { mount } from 'svelte'
|
|
|
2
2
|
import App from './routes/+page.svelte'
|
|
3
3
|
import { clearLinkInjections, getLinkInjectionElements, getLinkInjectionsParentElement, getPageText } from '$lib/linkInjection'
|
|
4
4
|
import { getPageMetaData } from '$lib/meta'
|
|
5
|
+
import type { Campaign } from '$lib/types/campaign'
|
|
5
6
|
|
|
6
7
|
window.PlayPilotLinkInjections = {
|
|
7
8
|
token: '',
|
|
@@ -59,40 +60,67 @@ window.PlayPilotLinkInjections = {
|
|
|
59
60
|
const parentElement = getLinkInjectionsParentElement()
|
|
60
61
|
const elements = getLinkInjectionElements(parentElement)
|
|
61
62
|
|
|
62
|
-
console.
|
|
63
|
-
console.
|
|
64
|
-
|
|
65
|
-
console.groupEnd()
|
|
63
|
+
console.groupCollapsed('Config')
|
|
64
|
+
console.table(Object.entries(this))
|
|
65
|
+
console.groupEnd()
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
console.groupCollapsed('Elements')
|
|
68
|
+
console.log('Parent element', parentElement)
|
|
69
|
+
console.log('Valid elements', elements)
|
|
70
|
+
console.groupEnd()
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
console.groupCollapsed('Last fetch')
|
|
73
|
+
console.log(this.last_successful_fetch)
|
|
74
|
+
console.groupEnd()
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
console.groupCollapsed('Meta')
|
|
77
|
+
console.log(getPageMetaData())
|
|
78
|
+
console.groupEnd()
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
console.groupCollapsed('Page text')
|
|
81
|
+
console.log(getPageText(elements))
|
|
82
|
+
console.groupEnd()
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
console.groupCollapsed('Evaluated injections')
|
|
85
|
+
console.log(this.evaluated_link_injections)
|
|
86
|
+
console.groupEnd()
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
console.groupCollapsed('Tracked events')
|
|
89
|
+
console.log(this.tracked_events)
|
|
90
|
+
console.groupEnd()
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
console.groupEnd()
|
|
92
|
+
console.groupCollapsed('Split tests')
|
|
93
|
+
console.log(this.split_test_identifiers)
|
|
95
94
|
console.groupEnd()
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
mockAd(override = {}): void {
|
|
98
|
+
/** @ts-ignore We're not including every field here, that's ok. */
|
|
99
|
+
const campaign: Campaign = {
|
|
100
|
+
campaign_format: 'card',
|
|
101
|
+
campaign_type: 'image',
|
|
102
|
+
campaign_name: 'some_campaign',
|
|
103
|
+
content: {
|
|
104
|
+
header: 'Some content header',
|
|
105
|
+
header_logo: 'https://picsum.photos/seed/picsum/40/40',
|
|
106
|
+
header_logo_uuid: '',
|
|
107
|
+
subheader: 'Some content subheader',
|
|
108
|
+
image: 'https://picsum.photos/seed/picsum/640/360',
|
|
109
|
+
image_uuid: '',
|
|
110
|
+
video: null,
|
|
111
|
+
format: null,
|
|
112
|
+
},
|
|
113
|
+
cta: {
|
|
114
|
+
header: 'Some cta header',
|
|
115
|
+
subheader: 'Some cta subheader',
|
|
116
|
+
url: 'https://google.com/',
|
|
117
|
+
image: null,
|
|
118
|
+
image_uuid: null
|
|
119
|
+
},
|
|
120
|
+
disclaimer: 'Some disclaimer',
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.ads = [{ ...campaign, ...override }]
|
|
96
124
|
}
|
|
97
125
|
}
|
|
98
126
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { browser } from '$app/environment'
|
|
3
3
|
import { page } from '$app/state'
|
|
4
|
-
import { SplitTest } from '$lib/enums/SplitTest'
|
|
5
|
-
import { getSplitTestVariantIndex } from '$lib/splitTest'
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
6
|
* !! NOTE: This layout file is for development purposes only and will not be compiled with the final script.
|
|
@@ -80,8 +78,6 @@
|
|
|
80
78
|
|
|
81
79
|
{#if browser}
|
|
82
80
|
{@render children()}
|
|
83
|
-
|
|
84
|
-
Viewing with split test index: {getSplitTestVariantIndex(SplitTest.MultipleVariants)}
|
|
85
81
|
{/if}
|
|
86
82
|
{/key}
|
|
87
83
|
{/if}
|
package/src/routes/+page.svelte
CHANGED
|
@@ -7,13 +7,12 @@
|
|
|
7
7
|
import { isCrawler } from '$lib/crawler'
|
|
8
8
|
import { TrackingEvent } from '$lib/enums/TrackingEvent'
|
|
9
9
|
import { authorize, getAuthToken, isEditorialModeEnabled, removeAuthCookie, setEditorialParamInUrl } from '$lib/auth'
|
|
10
|
-
import { trackSplitTestView } from '$lib/splitTest'
|
|
11
|
-
import { SplitTest } from '$lib/enums/SplitTest'
|
|
12
10
|
import type { LinkInjectionResponse, LinkInjection, LinkInjectionTypes } from '$lib/types/injection'
|
|
13
11
|
import Editor from './components/Editorial/Editor.svelte'
|
|
14
12
|
import EditorTrigger from './components/Editorial/EditorTrigger.svelte'
|
|
15
13
|
import Alert from './components/Editorial/Alert.svelte'
|
|
16
14
|
import TrackingPixels from './components/TrackingPixels.svelte'
|
|
15
|
+
import Debugger from './components/Debugger.svelte'
|
|
17
16
|
import { fetchAds } from '$lib/ads'
|
|
18
17
|
|
|
19
18
|
let parentElement: HTMLElement | null = $state(null)
|
|
@@ -45,8 +44,6 @@
|
|
|
45
44
|
track(TrackingEvent.ArticlePageView)
|
|
46
45
|
|
|
47
46
|
if (aiInjections.length || manualInjections.length) window.PlayPilotLinkInjections.ads = await fetchAds()
|
|
48
|
-
|
|
49
|
-
trackSplitTestView(SplitTest.MultipleVariants)
|
|
50
47
|
})()
|
|
51
48
|
|
|
52
49
|
return () => clearLinkInjections()
|
|
@@ -202,6 +199,8 @@
|
|
|
202
199
|
{/if}
|
|
203
200
|
</div>
|
|
204
201
|
|
|
202
|
+
<Debugger />
|
|
203
|
+
|
|
205
204
|
{#if response?.pixels?.length}
|
|
206
205
|
<TrackingPixels pixels={response.pixels} />
|
|
207
206
|
{/if}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { middlemouse } from '$lib/actions/middlemouse'
|
|
2
3
|
import { TrackingEvent } from '$lib/enums/TrackingEvent'
|
|
3
4
|
import { track } from '$lib/tracking'
|
|
4
5
|
import type { Campaign } from '$lib/types/campaign'
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
}
|
|
23
24
|
</script>
|
|
24
25
|
|
|
25
|
-
<a {href} target="_blank" class="display" class:compact rel="sponsored" {onclick}>
|
|
26
|
+
<a {href} target="_blank" class="display" class:compact rel="sponsored" {onclick} use:middlemouse={{ onclick }}>
|
|
26
27
|
{#if disclaimer}
|
|
27
28
|
<div class="disclaimer">
|
|
28
29
|
{#if compact}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { middlemouse } from '$lib/actions/middlemouse'
|
|
2
3
|
import { ImageDimensions } from '$lib/enums/ImageDimensions'
|
|
3
4
|
import { SplitTest } from '$lib/enums/SplitTest'
|
|
4
5
|
import { TrackingEvent } from '$lib/enums/TrackingEvent'
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
let clientWidth = $state(0)
|
|
31
32
|
let tooltipVisible = $state(false)
|
|
32
33
|
|
|
33
|
-
function
|
|
34
|
+
function onclick(): void {
|
|
34
35
|
track(TrackingEvent.TopScrollClick, null, { campaign_name: campaign.campaign_name })
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -44,15 +45,16 @@
|
|
|
44
45
|
|
|
45
46
|
<a
|
|
46
47
|
{href}
|
|
48
|
+
{onclick}
|
|
49
|
+
use:middlemouse={{ onclick }}
|
|
50
|
+
bind:clientWidth
|
|
47
51
|
target="_blank"
|
|
48
52
|
class="top-scroll"
|
|
49
53
|
class:simple
|
|
50
54
|
class:inline
|
|
51
55
|
tabindex="-1"
|
|
52
|
-
onclick={trackClick}
|
|
53
56
|
rel="sponsored"
|
|
54
|
-
style:--width="{clientWidth}px"
|
|
55
|
-
bind:clientWidth>
|
|
57
|
+
style:--width="{clientWidth}px">
|
|
56
58
|
<div class="content">
|
|
57
59
|
{#if simple}
|
|
58
60
|
<img class="content-image" src={contentImage} alt={header} width="728" height="90" />
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onDestroy } from 'svelte'
|
|
3
|
+
|
|
4
|
+
const secrets = ['tpidebug', 'debugtpi']
|
|
5
|
+
const lastInputs: string[] = []
|
|
6
|
+
|
|
7
|
+
let data = $state(dataToReadable())
|
|
8
|
+
let shown = $state(false)
|
|
9
|
+
let interval: ReturnType<typeof setInterval> | null = null
|
|
10
|
+
|
|
11
|
+
onDestroy(() => {
|
|
12
|
+
if (interval) clearInterval(interval)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
function dataToReadable() {
|
|
16
|
+
const data = window.PlayPilotLinkInjections
|
|
17
|
+
|
|
18
|
+
const succesfulInjections = data.evaluated_link_injections?.filter(injection => !injection.failed) || []
|
|
19
|
+
const failedInjections = data.evaluated_link_injections?.filter(injection => injection.failed) || []
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
'Config': [
|
|
23
|
+
{ label: 'Domain', data: data.domain_sid },
|
|
24
|
+
{ label: 'Organization', data: data.organization_sid },
|
|
25
|
+
{ label: 'HTML selector', data: data.selector },
|
|
26
|
+
],
|
|
27
|
+
[`Succesful injections (${succesfulInjections.length})`]: succesfulInjections.map(injection => ({ label: injection.title, data: injection.sentence })),
|
|
28
|
+
[`Failed injections (${failedInjections.length})`]: failedInjections.map(injection => ({ label: injection.title, data: injection.failed_message })),
|
|
29
|
+
[`Fetched ads (${data.ads?.length || 0})`]: data.ads?.map(ad => ({ label: ad.campaign_name, data: ad })),
|
|
30
|
+
[`Tracking events (${data.tracked_events?.length || 0})`]: data.tracked_events?.map(event => ({ label: event.event, data: event.payload })),
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Keep track of all last inputs. If the last inputs match the "secret" key we show the debugger and start setting data
|
|
35
|
+
function onkeydown(event: KeyboardEvent): void {
|
|
36
|
+
const key = event.key
|
|
37
|
+
|
|
38
|
+
lastInputs.push(key)
|
|
39
|
+
|
|
40
|
+
// Check all secrets. Both "tpidebug" and "debugtpi" are accepted because remembering is hard.
|
|
41
|
+
// It's checked by comparing the last inputs to each secret.
|
|
42
|
+
shown = secrets.some(secret => lastInputs.slice(lastInputs.length - secret.length, lastInputs.length).join('') === secret)
|
|
43
|
+
|
|
44
|
+
interval = setInterval(() => data = dataToReadable(), 200)
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<svelte:window {onkeydown} />
|
|
49
|
+
|
|
50
|
+
{#if shown}
|
|
51
|
+
<div class="debugger">
|
|
52
|
+
<strong>TPI Debugger</strong>
|
|
53
|
+
|
|
54
|
+
<hr />
|
|
55
|
+
|
|
56
|
+
{#each Object.entries(data) as [key, value]}
|
|
57
|
+
<details>
|
|
58
|
+
<summary>{key}</summary>
|
|
59
|
+
|
|
60
|
+
{#if value?.length}
|
|
61
|
+
{#if Array.isArray(value)}
|
|
62
|
+
{#each value as { label, data }}
|
|
63
|
+
<div class="item">
|
|
64
|
+
<span class="label">{label}</span>:
|
|
65
|
+
<span class="data">{JSON.stringify(data)}</span>
|
|
66
|
+
</div>
|
|
67
|
+
{/each}
|
|
68
|
+
{/if}
|
|
69
|
+
{:else}
|
|
70
|
+
No data
|
|
71
|
+
{/if}
|
|
72
|
+
</details>
|
|
73
|
+
{/each}
|
|
74
|
+
</div>
|
|
75
|
+
{/if}
|
|
76
|
+
|
|
77
|
+
<style lang="scss">
|
|
78
|
+
summary {
|
|
79
|
+
color: var(--playpilot-primary);
|
|
80
|
+
font-weight: bold;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
hr {
|
|
84
|
+
border-color: var(--playpilot-primary);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.debugger {
|
|
88
|
+
z-index: 2147483647; // As high as she goes
|
|
89
|
+
position: fixed;
|
|
90
|
+
top: 0;
|
|
91
|
+
left: 0;
|
|
92
|
+
max-width: 70dvw;
|
|
93
|
+
max-height: 50dvh;
|
|
94
|
+
padding: margin(1);
|
|
95
|
+
border: 1px solid var(--playpilot-primary);
|
|
96
|
+
background: black;
|
|
97
|
+
overflow: auto;
|
|
98
|
+
color: white;
|
|
99
|
+
font-family: "Consolas", monospace;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.item {
|
|
103
|
+
white-space: nowrap;
|
|
104
|
+
overflow-x: auto;
|
|
105
|
+
scrollbar-width: thin;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.data {
|
|
109
|
+
color: gray;
|
|
110
|
+
}
|
|
111
|
+
</style>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { prefersReducedMotion } from 'svelte/motion'
|
|
8
8
|
import { isInSplitTestVariant } from '$lib/splitTest'
|
|
9
9
|
import { SplitTest } from '$lib/enums/SplitTest'
|
|
10
|
+
import { mobileBreakpoint } from '$lib/constants'
|
|
10
11
|
|
|
11
12
|
interface Props {
|
|
12
13
|
children: Snippet
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
let dialogElement: HTMLElement | null = $state(null)
|
|
26
27
|
let dialogOffset: number = $state(0)
|
|
27
28
|
|
|
28
|
-
const isMobile = $derived(windowWidth <
|
|
29
|
+
const isMobile = $derived(windowWidth < mobileBreakpoint)
|
|
29
30
|
|
|
30
31
|
$effect(() => { if (windowWidth) dialogOffset = dialogElement?.offsetTop || 0 })
|
|
31
32
|
$effect(() => { setTimeout(() => dialogOffset = dialogElement?.offsetTop || 0) }) // Set after the dialog has shown to get the proper height
|
|
@@ -137,20 +137,31 @@ describe('$lib/tracking', () => {
|
|
|
137
137
|
)
|
|
138
138
|
})
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
setTrackingSids({ domainSid: 'some-domain', organizationSid: 'some-organization' })
|
|
140
|
+
it('Should include device information', () => {
|
|
141
|
+
track('Some event')
|
|
143
142
|
|
|
144
|
-
|
|
145
|
-
expect
|
|
146
|
-
|
|
143
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
144
|
+
expect.any(String),
|
|
145
|
+
expect.objectContaining({
|
|
146
|
+
body: expect.stringContaining('"device":{"type":"desktop","width":1024,"height":768,"touch":false,"orientation":"undefined"}'),
|
|
147
|
+
}),
|
|
148
|
+
)
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
describe('setTrackingSids', () => {
|
|
153
|
+
it('Should set stores equal to the given values', () => {
|
|
154
|
+
setTrackingSids({ domainSid: 'some-domain', organizationSid: 'some-organization' })
|
|
155
|
+
|
|
156
|
+
expect(window.PlayPilotLinkInjections.domain_sid).toBe('some-domain')
|
|
157
|
+
expect(window.PlayPilotLinkInjections.organization_sid).toBe('some-organization')
|
|
158
|
+
})
|
|
147
159
|
|
|
148
|
-
|
|
149
|
-
|
|
160
|
+
it('Should set stores to null if invalid values are given', () => {
|
|
161
|
+
setTrackingSids({ domainSid: '', organizationSid: undefined })
|
|
150
162
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
})
|
|
163
|
+
expect(window.PlayPilotLinkInjections.domain_sid).toBe(null)
|
|
164
|
+
expect(window.PlayPilotLinkInjections.organization_sid).toBe(null)
|
|
154
165
|
})
|
|
155
166
|
})
|
|
156
167
|
})
|
|
@@ -59,9 +59,14 @@ describe('Display.svelte', () => {
|
|
|
59
59
|
/** @ts-ignore */
|
|
60
60
|
const { getByRole } = render(Display, { campaign })
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
vi.resetAllMocks()
|
|
63
63
|
|
|
64
|
+
await fireEvent.click(getByRole('link'))
|
|
64
65
|
expect(track).toHaveBeenCalledWith(TrackingEvent.DisplayAdClick, null, { campaign_name: campaign.campaign_name })
|
|
66
|
+
expect(track).toHaveBeenCalledTimes(1)
|
|
67
|
+
|
|
68
|
+
await fireEvent.mouseUp(getByRole('link'), { button: 1 })
|
|
69
|
+
expect(track).toHaveBeenCalledTimes(2)
|
|
65
70
|
})
|
|
66
71
|
|
|
67
72
|
it('Should render link without any content by default', () => {
|
|
@@ -92,9 +92,14 @@ describe('TopScroll.svelte', () => {
|
|
|
92
92
|
/** @ts-ignore */
|
|
93
93
|
const { getByRole } = render(TopScroll, { campaign })
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
vi.resetAllMocks()
|
|
96
96
|
|
|
97
|
+
await fireEvent.click(getByRole('link'))
|
|
97
98
|
expect(track).toHaveBeenCalledWith(TrackingEvent.TopScrollClick, null, { campaign_name: campaign.campaign_name })
|
|
99
|
+
expect(track).toHaveBeenCalledTimes(1)
|
|
100
|
+
|
|
101
|
+
await fireEvent.mouseUp(getByRole('link'), { button: 1 })
|
|
102
|
+
expect(track).toHaveBeenCalledTimes(2)
|
|
98
103
|
})
|
|
99
104
|
|
|
100
105
|
it('Should render as simple variant when content format is large', async () => {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/svelte'
|
|
2
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import Debugger from '../../../routes/components/Debugger.svelte'
|
|
5
|
+
|
|
6
|
+
describe('Debugger.svelte', () => {
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
localStorage.clear()
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('Should show debugger after entering correct input', async () => {
|
|
12
|
+
const { getByText } = render(Debugger)
|
|
13
|
+
|
|
14
|
+
const keys = ['t', 'p', 'i', 'd', 'e', 'b', 'u', 'g']
|
|
15
|
+
for (const key of keys) {
|
|
16
|
+
await fireEvent.keyDown(window, { key })
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
expect(getByText('TPI Debugger')).toBeTruthy()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('Should show debugger after entering other correct input', async () => {
|
|
23
|
+
const { getByText } = render(Debugger)
|
|
24
|
+
|
|
25
|
+
const keys = ['d', 'e', 'b', 'u', 'g', 't', 'p', 'i']
|
|
26
|
+
for (const key of keys) {
|
|
27
|
+
await fireEvent.keyDown(window, { key })
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
expect(getByText('TPI Debugger')).toBeTruthy()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('Should not show debugger after entering incorrect input', async () => {
|
|
34
|
+
const { queryByText } = render(Debugger)
|
|
35
|
+
|
|
36
|
+
const keys = ['n', 'o', 't', 'd', 'e', 'b', 'u', 'g']
|
|
37
|
+
for (const key of keys) {
|
|
38
|
+
await fireEvent.keyDown(window, { key })
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
expect(queryByText('TPI Debugger')).not.toBeTruthy()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('Should show debugger after entering correct input after first enter incorrect keys', async () => {
|
|
45
|
+
const { getByText } = render(Debugger)
|
|
46
|
+
|
|
47
|
+
const keys = ['a', 'b', 'c', 't', 'p', 'i', 'd', 'e', 'b', 'u', 'g']
|
|
48
|
+
for (const key of keys) {
|
|
49
|
+
await fireEvent.keyDown(window, { key })
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
expect(getByText('TPI Debugger')).toBeTruthy()
|
|
53
|
+
})
|
|
54
|
+
})
|