@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.
Files changed (2) hide show
  1. package/package.json +2 -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.2",
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.2"
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
+ })