@owlmeans/web-gtm 0.1.18-rc.2 → 0.1.18-rc.4
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 +2 -2
- package/tests/head.spec.ts +65 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/web-gtm",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@owlmeans/consent": "^0.1.18-rc.
|
|
25
|
+
"@owlmeans/consent": "^0.1.18-rc.3"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@owlmeans/dep-config": "workspace:*",
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
import { CONSENT_KEY } from '@owlmeans/consent'
|
|
3
|
+
import { gtmHeadScript, gtmNoscriptFrame } from '../src/index.js'
|
|
4
|
+
|
|
5
|
+
const ID = 'GTM-TESTID1'
|
|
6
|
+
|
|
7
|
+
describe('@owlmeans/web-gtm — the head snippet', () => {
|
|
8
|
+
test('the consent defaults are declared BEFORE the container is requested', async () => {
|
|
9
|
+
// The entire reason this package exists. Consent Mode decides what a tag may do from the state
|
|
10
|
+
// present when the container loads, so a `consent/default` that arrives after `gtm.js` leaves
|
|
11
|
+
// the page unconfigured for the window that matters — and nothing reports it. Asserted on
|
|
12
|
+
// offsets rather than on presence, because both strings are always present and only the order
|
|
13
|
+
// has ever been wrong.
|
|
14
|
+
const script = gtmHeadScript({ id: ID })
|
|
15
|
+
|
|
16
|
+
const defaults = script.indexOf("'consent','default'")
|
|
17
|
+
const container = script.indexOf('gtm.js')
|
|
18
|
+
|
|
19
|
+
expect(defaults).toBeGreaterThanOrEqual(0)
|
|
20
|
+
expect(container).toBeGreaterThanOrEqual(0)
|
|
21
|
+
expect(defaults).toBeLessThan(container)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('it reads a stored decision, so a returning visitor is not treated as denied', async () => {
|
|
25
|
+
const script = gtmHeadScript({ id: ID })
|
|
26
|
+
|
|
27
|
+
expect(script).toContain(JSON.stringify(CONSENT_KEY))
|
|
28
|
+
expect(script).toContain("'consent','update'")
|
|
29
|
+
// And the read happens before the container too — a decision applied afterwards is a decision
|
|
30
|
+
// the first tag never saw.
|
|
31
|
+
expect(script.indexOf("'consent','update'")).toBeLessThan(script.indexOf('gtm.js'))
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('the container id and queue name are injected as data, never interpolated raw', async () => {
|
|
35
|
+
// These come from configuration, and configuration reaches this function as a string. JSON
|
|
36
|
+
// encoding is what keeps a stray quote from closing the literal and turning the rest of an id
|
|
37
|
+
// into executable script — the value still appears verbatim, and that is fine; what matters is
|
|
38
|
+
// that a quote inside it is ESCAPED rather than terminating the string.
|
|
39
|
+
const script = gtmHeadScript({ id: `${ID}"+alert(1)+"`, dataLayerName: 'owlLayer' })
|
|
40
|
+
|
|
41
|
+
expect(script).toContain(JSON.stringify(`${ID}"+alert(1)+"`))
|
|
42
|
+
expect(script).toContain(JSON.stringify('owlLayer'))
|
|
43
|
+
// The escaped form is what makes it inert; the bare form would have closed the literal.
|
|
44
|
+
expect(script).toContain('\\"+alert(1)+\\"')
|
|
45
|
+
expect(script).not.toContain(`"${ID}"+alert(1)+""`)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('a custom queue name is passed to the container', async () => {
|
|
49
|
+
expect(gtmHeadScript({ id: ID, dataLayerName: 'owlLayer' })).toContain("l!='dataLayer'")
|
|
50
|
+
expect(gtmHeadScript({ id: ID })).toContain(JSON.stringify('dataLayer'))
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
describe('@owlmeans/web-gtm — the noscript frame', () => {
|
|
55
|
+
test('it names the container and stays invisible', async () => {
|
|
56
|
+
const frame = gtmNoscriptFrame({ id: ID })
|
|
57
|
+
|
|
58
|
+
expect(frame).toContain(`id=${ID}`)
|
|
59
|
+
expect(frame).toContain('display:none')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('an id is URL-encoded, so it cannot break out of the attribute', async () => {
|
|
63
|
+
expect(gtmNoscriptFrame({ id: 'a"b' })).not.toContain('a"b')
|
|
64
|
+
})
|
|
65
|
+
})
|