@financial-times/cp-content-pipeline-ui 6.12.0 → 6.13.0-beta.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/lib/client.d.ts +1 -0
- package/lib/client.js +3 -1
- package/lib/client.js.map +1 -1
- package/lib/components/Body/index.test.js +1 -0
- package/lib/components/Body/index.test.js.map +1 -1
- package/lib/components/Flourish/index.js +1 -1
- package/lib/components/Flourish/index.js.map +1 -1
- package/lib/components/ImageSet/index.d.ts +1 -1
- package/lib/components/ImageSet/index.js +10 -2
- package/lib/components/ImageSet/index.js.map +1 -1
- package/lib/components/LiveBlogWrapper/index.js +1 -1
- package/lib/components/LiveBlogWrapper/index.js.map +1 -1
- package/lib/components/Topper/Picture.js +2 -2
- package/lib/components/Topper/Picture.js.map +1 -1
- package/lib/components/Topper/client/flourish-tracking.d.ts +14 -0
- package/lib/components/Topper/client/flourish-tracking.js +69 -0
- package/lib/components/Topper/client/flourish-tracking.js.map +1 -0
- package/lib/components/Topper/client/index.d.ts +2 -0
- package/lib/components/Topper/client/index.js +6 -0
- package/lib/components/Topper/client/index.js.map +1 -0
- package/lib/components/Topper/test/client/flourish-tracking.spec.d.ts +1 -0
- package/lib/components/Topper/test/client/flourish-tracking.spec.js +117 -0
- package/lib/components/Topper/test/client/flourish-tracking.spec.js.map +1 -0
- package/package.json +1 -1
- package/src/client.ts +1 -0
- package/src/components/Body/index.test.tsx +1 -0
- package/src/components/Flourish/index.tsx +5 -0
- package/src/components/Flourish/test/__snapshots__/snapshot.spec.tsx.snap +18 -0
- package/src/components/ImageSet/index.tsx +21 -11
- package/src/components/LiveBlogWrapper/index.tsx +1 -1
- package/src/components/Topper/Picture.tsx +2 -2
- package/src/components/Topper/client/flourish-tracking.ts +83 -0
- package/src/components/Topper/client/index.ts +3 -0
- package/src/components/Topper/test/client/flourish-tracking.spec.ts +135 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
class FlourishTopperTracker {
|
|
2
|
+
private startTime: number
|
|
3
|
+
private totalVisibleTime: number
|
|
4
|
+
private timeElapsedSeconds: number | null
|
|
5
|
+
private component: Element | null
|
|
6
|
+
private id: string | null
|
|
7
|
+
private observer: IntersectionObserver | null
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
this.startTime = 0
|
|
11
|
+
this.totalVisibleTime = 0
|
|
12
|
+
this.timeElapsedSeconds = null
|
|
13
|
+
this.component = document.querySelector(
|
|
14
|
+
'[data-component-type="flourish-topper"]'
|
|
15
|
+
)
|
|
16
|
+
this.id = this.component?.getAttribute('data-component-id') || null
|
|
17
|
+
this.observer = null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
init(): void {
|
|
21
|
+
if (!window.IntersectionObserver || !this.component) {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (this.component) {
|
|
26
|
+
this.dispatchEvent('mount')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.observer = new IntersectionObserver(this.onChange.bind(this), {
|
|
30
|
+
threshold: [1.0],
|
|
31
|
+
})
|
|
32
|
+
this.observer.observe(this.component)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private dispatchEvent(action: string): void {
|
|
36
|
+
let component: object = {
|
|
37
|
+
name: 'flourish-topper',
|
|
38
|
+
id: this.id,
|
|
39
|
+
}
|
|
40
|
+
if (this.timeElapsedSeconds) {
|
|
41
|
+
component = { ...component, timeElapsedSeconds: this.timeElapsedSeconds }
|
|
42
|
+
}
|
|
43
|
+
const event = new CustomEvent('oTracking.event', {
|
|
44
|
+
detail: {
|
|
45
|
+
category: 'component',
|
|
46
|
+
action: action,
|
|
47
|
+
component,
|
|
48
|
+
},
|
|
49
|
+
bubbles: true,
|
|
50
|
+
})
|
|
51
|
+
document.body.dispatchEvent(event)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private onChange(changes: IntersectionObserverEntry[]): void {
|
|
55
|
+
changes.forEach((change) => {
|
|
56
|
+
if (change.target !== this.component) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
if (change.isIntersecting || change.intersectionRatio >= 1) {
|
|
60
|
+
this.dispatchEvent('view')
|
|
61
|
+
this.startTime = performance.now()
|
|
62
|
+
}
|
|
63
|
+
if (!change.isIntersecting || change.intersectionRatio === 0) {
|
|
64
|
+
this.totalVisibleTime = performance.now() - this.startTime
|
|
65
|
+
this.timeElapsedSeconds = parseFloat(
|
|
66
|
+
(this.totalVisibleTime / 1000).toFixed(2)
|
|
67
|
+
)
|
|
68
|
+
this.dispatchEvent('stop-view')
|
|
69
|
+
this.totalVisibleTime = 0
|
|
70
|
+
this.timeElapsedSeconds = null
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
disconnect(): void {
|
|
76
|
+
if (this.observer && this.component) {
|
|
77
|
+
this.observer.unobserve(this.component)
|
|
78
|
+
this.observer.disconnect()
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { FlourishTopperTracker }
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { FlourishTopperTracker } from '../../client'
|
|
2
|
+
|
|
3
|
+
// const CustomEventMock = jest.fn()
|
|
4
|
+
// global.CustomEvent = CustomEventMock
|
|
5
|
+
|
|
6
|
+
describe('FlourishTopperTracker', () => {
|
|
7
|
+
let mockIntersectionObserver: jest.Mock
|
|
8
|
+
let mockObserve: jest.Mock
|
|
9
|
+
let mockUnobserve: jest.Mock
|
|
10
|
+
let mockDisconnect: jest.Mock
|
|
11
|
+
let mockComponent: HTMLElement
|
|
12
|
+
let dispatchEventSpy: jest.SpyInstance
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
mockObserve = jest.fn()
|
|
16
|
+
mockUnobserve = jest.fn()
|
|
17
|
+
mockDisconnect = jest.fn()
|
|
18
|
+
|
|
19
|
+
mockIntersectionObserver = jest.fn(() => {
|
|
20
|
+
return {
|
|
21
|
+
observe: mockObserve,
|
|
22
|
+
unobserve: mockUnobserve,
|
|
23
|
+
disconnect: mockDisconnect,
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
window.IntersectionObserver = mockIntersectionObserver
|
|
28
|
+
|
|
29
|
+
mockComponent = document.createElement('div')
|
|
30
|
+
mockComponent.setAttribute('data-component-type', 'flourish-topper')
|
|
31
|
+
mockComponent.setAttribute('data-component-id', 'test-id')
|
|
32
|
+
document.body.appendChild(mockComponent)
|
|
33
|
+
|
|
34
|
+
jest.spyOn(document, 'querySelector').mockReturnValue(mockComponent)
|
|
35
|
+
jest
|
|
36
|
+
.spyOn(performance, 'now')
|
|
37
|
+
.mockImplementationOnce(() => 1)
|
|
38
|
+
.mockImplementationOnce(() => 12344)
|
|
39
|
+
dispatchEventSpy = jest.spyOn(document.body, 'dispatchEvent')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
jest.clearAllMocks()
|
|
44
|
+
document.body.removeChild(mockComponent)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('should initialise and observe the component', () => {
|
|
48
|
+
const tracker = new FlourishTopperTracker()
|
|
49
|
+
tracker.init()
|
|
50
|
+
|
|
51
|
+
expect(mockIntersectionObserver).toHaveBeenCalled()
|
|
52
|
+
expect(mockObserve).toHaveBeenCalledWith(mockComponent)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('should dispatch a mount event on intialisation', () => {
|
|
56
|
+
const tracker = new FlourishTopperTracker()
|
|
57
|
+
tracker.init()
|
|
58
|
+
|
|
59
|
+
const mountEvent = dispatchEventSpy.mock.calls[0][0] as CustomEvent
|
|
60
|
+
expect(mountEvent.type).toBe('oTracking.event')
|
|
61
|
+
expect(mountEvent.detail).toEqual({
|
|
62
|
+
category: 'component',
|
|
63
|
+
action: 'mount',
|
|
64
|
+
component: {
|
|
65
|
+
name: 'flourish-topper',
|
|
66
|
+
id: 'test-id',
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('should handle component visibility changes', () => {
|
|
72
|
+
const tracker = new FlourishTopperTracker()
|
|
73
|
+
tracker.init()
|
|
74
|
+
|
|
75
|
+
const mockChanges: IntersectionObserverEntry[] = [
|
|
76
|
+
{
|
|
77
|
+
target: mockComponent,
|
|
78
|
+
isIntersecting: true,
|
|
79
|
+
intersectionRatio: 1.0,
|
|
80
|
+
boundingClientRect: {} as DOMRectReadOnly,
|
|
81
|
+
intersectionRect: {} as DOMRectReadOnly,
|
|
82
|
+
rootBounds: null,
|
|
83
|
+
time: 1,
|
|
84
|
+
},
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
tracker['onChange'](mockChanges)
|
|
88
|
+
|
|
89
|
+
const viewEvent = dispatchEventSpy.mock.calls[1][0] as CustomEvent
|
|
90
|
+
expect(viewEvent.type).toBe('oTracking.event')
|
|
91
|
+
expect(viewEvent.detail).toEqual({
|
|
92
|
+
category: 'component',
|
|
93
|
+
action: 'view',
|
|
94
|
+
component: {
|
|
95
|
+
name: 'flourish-topper',
|
|
96
|
+
id: 'test-id',
|
|
97
|
+
},
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const mockChangesAfter: IntersectionObserverEntry[] = [
|
|
101
|
+
{
|
|
102
|
+
target: mockComponent,
|
|
103
|
+
isIntersecting: false,
|
|
104
|
+
intersectionRatio: 0.0,
|
|
105
|
+
boundingClientRect: {} as DOMRectReadOnly,
|
|
106
|
+
intersectionRect: {} as DOMRectReadOnly,
|
|
107
|
+
rootBounds: null,
|
|
108
|
+
time: 12.3444,
|
|
109
|
+
},
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
tracker['onChange'](mockChangesAfter)
|
|
113
|
+
|
|
114
|
+
const stopViewEvent = dispatchEventSpy.mock.calls[2][0] as CustomEvent
|
|
115
|
+
expect(stopViewEvent.type).toBe('oTracking.event')
|
|
116
|
+
expect(stopViewEvent.detail).toEqual({
|
|
117
|
+
category: 'component',
|
|
118
|
+
action: 'stop-view',
|
|
119
|
+
component: {
|
|
120
|
+
name: 'flourish-topper',
|
|
121
|
+
id: 'test-id',
|
|
122
|
+
timeElapsedSeconds: 12.34,
|
|
123
|
+
},
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('should disconnect the observer', () => {
|
|
128
|
+
const tracker = new FlourishTopperTracker()
|
|
129
|
+
tracker.init()
|
|
130
|
+
tracker.disconnect()
|
|
131
|
+
|
|
132
|
+
expect(mockUnobserve).toHaveBeenCalledWith(mockComponent)
|
|
133
|
+
expect(mockDisconnect).toHaveBeenCalled()
|
|
134
|
+
})
|
|
135
|
+
})
|