@posthog/react 1.2.3 → 1.3.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/esm/index.js +68 -36
- package/dist/esm/index.js.map +1 -1
- package/dist/types/index.d.ts +19 -1
- package/dist/umd/index.js +70 -35
- package/dist/umd/index.js.map +1 -1
- package/package.json +5 -7
- package/src/components/PostHogCaptureOnViewed.tsx +126 -0
- package/src/components/PostHogFeature.tsx +8 -93
- package/src/components/__tests__/PostHogCaptureOnViewed.test.tsx +110 -0
- package/src/components/__tests__/{PostHogErrorBoundary.test.jsx → PostHogErrorBoundary.test.tsx} +16 -16
- package/src/components/__tests__/PostHogFeature.test.tsx +249 -0
- package/src/components/index.ts +1 -0
- package/src/components/internal/VisibilityAndClickTracker.tsx +49 -0
- package/src/components/internal/VisibilityAndClickTrackers.tsx +60 -0
- package/src/context/__tests__/{PostHogContext.test.jsx → PostHogContext.test.tsx} +16 -15
- package/src/context/__tests__/{PostHogProvider.test.jsx → PostHogProvider.test.tsx} +4 -4
- package/src/hooks/__tests__/{featureFlags.test.jsx → featureFlags.test.tsx} +35 -31
- package/src/hooks/__tests__/usePostHog.test.tsx +19 -0
- package/src/components/__tests__/PostHogFeature.test.jsx +0 -298
- package/src/hooks/__tests__/usePostHog.test.jsx +0 -23
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { renderHook } from '@testing-library/react-hooks'
|
|
3
|
+
import { PostHogProvider, PostHog } from '../../context'
|
|
4
|
+
import { usePostHog } from '..'
|
|
5
|
+
|
|
6
|
+
jest.useFakeTimers()
|
|
7
|
+
|
|
8
|
+
const posthog = { posthog_client: true } as unknown as PostHog
|
|
9
|
+
|
|
10
|
+
describe('usePostHog hook', () => {
|
|
11
|
+
it('should return the client', () => {
|
|
12
|
+
const { result } = renderHook(() => usePostHog(), {
|
|
13
|
+
wrapper: ({ children }: { children: React.ReactNode }) => (
|
|
14
|
+
<PostHogProvider client={posthog}>{children}</PostHogProvider>
|
|
15
|
+
),
|
|
16
|
+
})
|
|
17
|
+
expect(result.current).toEqual(posthog)
|
|
18
|
+
})
|
|
19
|
+
})
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
2
|
-
import { useState } from 'react'
|
|
3
|
-
import { render, screen, fireEvent } from '@testing-library/react'
|
|
4
|
-
import { PostHogProvider } from '../../context'
|
|
5
|
-
import { PostHogFeature } from '../'
|
|
6
|
-
import '@testing-library/jest-dom'
|
|
7
|
-
|
|
8
|
-
const FEATURE_FLAG_STATUS = {
|
|
9
|
-
multivariate_feature: 'string-value',
|
|
10
|
-
example_feature_payload: 'test',
|
|
11
|
-
test: true,
|
|
12
|
-
test_false: false,
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const FEATURE_FLAG_PAYLOADS = {
|
|
16
|
-
example_feature_payload: {
|
|
17
|
-
id: 1,
|
|
18
|
-
name: 'example_feature_1_payload',
|
|
19
|
-
key: 'example_feature_1_payload',
|
|
20
|
-
},
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
describe('PostHogFeature component', () => {
|
|
24
|
-
given('featureFlag', () => 'test')
|
|
25
|
-
given('matchValue', () => true)
|
|
26
|
-
given(
|
|
27
|
-
'render',
|
|
28
|
-
() => () =>
|
|
29
|
-
render(
|
|
30
|
-
<PostHogProvider client={given.posthog}>
|
|
31
|
-
<PostHogFeature flag={given.featureFlag} match={given.matchValue}>
|
|
32
|
-
<div data-testid="helloDiv">Hello</div>
|
|
33
|
-
</PostHogFeature>
|
|
34
|
-
</PostHogProvider>
|
|
35
|
-
)
|
|
36
|
-
)
|
|
37
|
-
given('posthog', () => ({
|
|
38
|
-
isFeatureEnabled: (flag) => !!FEATURE_FLAG_STATUS[flag],
|
|
39
|
-
getFeatureFlag: (flag) => FEATURE_FLAG_STATUS[flag],
|
|
40
|
-
getFeatureFlagPayload: (flag) => FEATURE_FLAG_PAYLOADS[flag],
|
|
41
|
-
onFeatureFlags: (callback) => {
|
|
42
|
-
const activeFlags = []
|
|
43
|
-
for (const flag in FEATURE_FLAG_STATUS) {
|
|
44
|
-
if (FEATURE_FLAG_STATUS[flag]) {
|
|
45
|
-
activeFlags.push(flag)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
callback(activeFlags)
|
|
49
|
-
return () => {}
|
|
50
|
-
},
|
|
51
|
-
capture: jest.fn(),
|
|
52
|
-
}))
|
|
53
|
-
|
|
54
|
-
beforeEach(() => {
|
|
55
|
-
// IntersectionObserver isn't available in test environment
|
|
56
|
-
const mockIntersectionObserver = jest.fn()
|
|
57
|
-
mockIntersectionObserver.mockReturnValue({
|
|
58
|
-
observe: () => null,
|
|
59
|
-
unobserve: () => null,
|
|
60
|
-
disconnect: () => null,
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
// eslint-disable-next-line compat/compat
|
|
64
|
-
window.IntersectionObserver = mockIntersectionObserver
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('should track interactions with the feature component', () => {
|
|
68
|
-
given.render()
|
|
69
|
-
|
|
70
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
71
|
-
expect(given.posthog.capture).toHaveBeenCalledWith('$feature_interaction', {
|
|
72
|
-
feature_flag: 'test',
|
|
73
|
-
$set: { '$feature_interaction/test': true },
|
|
74
|
-
})
|
|
75
|
-
expect(given.posthog.capture).toHaveBeenCalledTimes(1)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('should not fire for every interaction with the feature component', () => {
|
|
79
|
-
given.render()
|
|
80
|
-
|
|
81
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
82
|
-
expect(given.posthog.capture).toHaveBeenCalledWith('$feature_interaction', {
|
|
83
|
-
feature_flag: 'test',
|
|
84
|
-
$set: { '$feature_interaction/test': true },
|
|
85
|
-
})
|
|
86
|
-
expect(given.posthog.capture).toHaveBeenCalledTimes(1)
|
|
87
|
-
|
|
88
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
89
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
90
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
91
|
-
expect(given.posthog.capture).toHaveBeenCalledTimes(1)
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
it('should track an interaction with each child node of the feature component', () => {
|
|
95
|
-
given(
|
|
96
|
-
'render',
|
|
97
|
-
() => () =>
|
|
98
|
-
render(
|
|
99
|
-
<PostHogProvider client={given.posthog}>
|
|
100
|
-
<PostHogFeature flag={given.featureFlag} match={given.matchValue}>
|
|
101
|
-
<div data-testid="helloDiv">Hello</div>
|
|
102
|
-
<div data-testid="worldDiv">World!</div>
|
|
103
|
-
</PostHogFeature>
|
|
104
|
-
</PostHogProvider>
|
|
105
|
-
)
|
|
106
|
-
)
|
|
107
|
-
given.render()
|
|
108
|
-
|
|
109
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
110
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
111
|
-
fireEvent.click(screen.getByTestId('worldDiv'))
|
|
112
|
-
fireEvent.click(screen.getByTestId('worldDiv'))
|
|
113
|
-
fireEvent.click(screen.getByTestId('worldDiv'))
|
|
114
|
-
expect(given.posthog.capture).toHaveBeenCalledWith('$feature_interaction', {
|
|
115
|
-
feature_flag: 'test',
|
|
116
|
-
$set: { '$feature_interaction/test': true },
|
|
117
|
-
})
|
|
118
|
-
expect(given.posthog.capture).toHaveBeenCalledTimes(1)
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
it('should not fire events when interaction is disabled', () => {
|
|
122
|
-
given(
|
|
123
|
-
'render',
|
|
124
|
-
() => () =>
|
|
125
|
-
render(
|
|
126
|
-
<PostHogProvider client={given.posthog}>
|
|
127
|
-
<PostHogFeature flag={given.featureFlag} match={given.matchValue} trackInteraction={false}>
|
|
128
|
-
<div data-testid="helloDiv">Hello</div>
|
|
129
|
-
</PostHogFeature>
|
|
130
|
-
</PostHogProvider>
|
|
131
|
-
)
|
|
132
|
-
)
|
|
133
|
-
given.render()
|
|
134
|
-
|
|
135
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
136
|
-
expect(given.posthog.capture).not.toHaveBeenCalled()
|
|
137
|
-
|
|
138
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
139
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
140
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
141
|
-
expect(given.posthog.capture).not.toHaveBeenCalled()
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
it('should fire events when interaction is disabled but re-enabled after', () => {
|
|
145
|
-
const DynamicUpdateComponent = () => {
|
|
146
|
-
const [trackInteraction, setTrackInteraction] = useState(false)
|
|
147
|
-
|
|
148
|
-
return (
|
|
149
|
-
<>
|
|
150
|
-
<div
|
|
151
|
-
data-testid="clicker"
|
|
152
|
-
onClick={() => {
|
|
153
|
-
setTrackInteraction(true)
|
|
154
|
-
}}
|
|
155
|
-
>
|
|
156
|
-
Click me
|
|
157
|
-
</div>
|
|
158
|
-
<PostHogFeature
|
|
159
|
-
flag={given.featureFlag}
|
|
160
|
-
match={given.matchValue}
|
|
161
|
-
trackInteraction={trackInteraction}
|
|
162
|
-
>
|
|
163
|
-
<div data-testid="helloDiv">Hello</div>
|
|
164
|
-
</PostHogFeature>
|
|
165
|
-
</>
|
|
166
|
-
)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
given(
|
|
170
|
-
'render',
|
|
171
|
-
() => () =>
|
|
172
|
-
render(
|
|
173
|
-
<PostHogProvider client={given.posthog}>
|
|
174
|
-
<DynamicUpdateComponent />
|
|
175
|
-
</PostHogProvider>
|
|
176
|
-
)
|
|
177
|
-
)
|
|
178
|
-
given.render()
|
|
179
|
-
|
|
180
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
181
|
-
expect(given.posthog.capture).not.toHaveBeenCalled()
|
|
182
|
-
|
|
183
|
-
fireEvent.click(screen.getByTestId('clicker'))
|
|
184
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
185
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
186
|
-
expect(given.posthog.capture).toHaveBeenCalledWith('$feature_interaction', {
|
|
187
|
-
feature_flag: 'test',
|
|
188
|
-
$set: { '$feature_interaction/test': true },
|
|
189
|
-
})
|
|
190
|
-
expect(given.posthog.capture).toHaveBeenCalledTimes(1)
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
it('should not show the feature component if the flag is not enabled', () => {
|
|
194
|
-
given('featureFlag', () => 'test_false')
|
|
195
|
-
given.render()
|
|
196
|
-
|
|
197
|
-
expect(screen.queryByTestId('helloDiv')).not.toBeInTheDocument()
|
|
198
|
-
expect(given.posthog.capture).not.toHaveBeenCalled()
|
|
199
|
-
|
|
200
|
-
// check if any elements are found
|
|
201
|
-
const allTags = screen.queryAllByText(/.*/)
|
|
202
|
-
|
|
203
|
-
// Assert that no random elements are found
|
|
204
|
-
expect(allTags.length).toEqual(2)
|
|
205
|
-
expect(allTags[0].tagName).toEqual('BODY')
|
|
206
|
-
expect(allTags[1].tagName).toEqual('DIV')
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
it('should fallback when provided', () => {
|
|
210
|
-
given('featureFlag', () => 'test_false')
|
|
211
|
-
given(
|
|
212
|
-
'render',
|
|
213
|
-
() => () =>
|
|
214
|
-
render(
|
|
215
|
-
<PostHogProvider client={given.posthog}>
|
|
216
|
-
<PostHogFeature
|
|
217
|
-
flag={given.featureFlag}
|
|
218
|
-
match={given.matchValue}
|
|
219
|
-
fallback={<div data-testid="nope">Nope</div>}
|
|
220
|
-
>
|
|
221
|
-
<div data-testid="helloDiv">Hello</div>
|
|
222
|
-
</PostHogFeature>
|
|
223
|
-
</PostHogProvider>
|
|
224
|
-
)
|
|
225
|
-
)
|
|
226
|
-
given.render()
|
|
227
|
-
|
|
228
|
-
expect(screen.queryByTestId('helloDiv')).not.toBeInTheDocument()
|
|
229
|
-
expect(given.posthog.capture).not.toHaveBeenCalled()
|
|
230
|
-
|
|
231
|
-
fireEvent.click(screen.getByTestId('nope'))
|
|
232
|
-
expect(given.posthog.capture).not.toHaveBeenCalled()
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
it('should handle showing multivariate flags with bool match', () => {
|
|
236
|
-
given('featureFlag', () => 'multivariate_feature')
|
|
237
|
-
given('matchValue', () => true)
|
|
238
|
-
|
|
239
|
-
given.render()
|
|
240
|
-
|
|
241
|
-
expect(screen.queryByTestId('helloDiv')).not.toBeInTheDocument()
|
|
242
|
-
expect(given.posthog.capture).not.toHaveBeenCalled()
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
it('should handle showing multivariate flags with incorrect match', () => {
|
|
246
|
-
given('featureFlag', () => 'multivariate_feature')
|
|
247
|
-
given('matchValue', () => 'string-valueCXCC')
|
|
248
|
-
|
|
249
|
-
given.render()
|
|
250
|
-
|
|
251
|
-
expect(screen.queryByTestId('helloDiv')).not.toBeInTheDocument()
|
|
252
|
-
expect(given.posthog.capture).not.toHaveBeenCalled()
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
it('should handle showing multivariate flags', () => {
|
|
256
|
-
given('featureFlag', () => 'multivariate_feature')
|
|
257
|
-
given('matchValue', () => 'string-value')
|
|
258
|
-
|
|
259
|
-
given.render()
|
|
260
|
-
|
|
261
|
-
expect(screen.queryByTestId('helloDiv')).toBeInTheDocument()
|
|
262
|
-
expect(given.posthog.capture).not.toHaveBeenCalled()
|
|
263
|
-
|
|
264
|
-
fireEvent.click(screen.getByTestId('helloDiv'))
|
|
265
|
-
expect(given.posthog.capture).toHaveBeenCalledWith('$feature_interaction', {
|
|
266
|
-
feature_flag: 'multivariate_feature',
|
|
267
|
-
feature_flag_variant: 'string-value',
|
|
268
|
-
$set: { '$feature_interaction/multivariate_feature': 'string-value' },
|
|
269
|
-
})
|
|
270
|
-
expect(given.posthog.capture).toHaveBeenCalledTimes(1)
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
it('should handle payload flags', () => {
|
|
274
|
-
given('featureFlag', () => 'example_feature_payload')
|
|
275
|
-
given('matchValue', () => 'test')
|
|
276
|
-
given(
|
|
277
|
-
'render',
|
|
278
|
-
() => () =>
|
|
279
|
-
render(
|
|
280
|
-
<PostHogProvider client={given.posthog}>
|
|
281
|
-
<PostHogFeature flag={given.featureFlag} match={given.matchValue}>
|
|
282
|
-
{(payload) => {
|
|
283
|
-
return <div data-testid={`hi_${payload.name}`}>Hullo</div>
|
|
284
|
-
}}
|
|
285
|
-
</PostHogFeature>
|
|
286
|
-
</PostHogProvider>
|
|
287
|
-
)
|
|
288
|
-
)
|
|
289
|
-
|
|
290
|
-
given.render()
|
|
291
|
-
|
|
292
|
-
expect(screen.queryByTestId('hi_example_feature_1_payload')).toBeInTheDocument()
|
|
293
|
-
expect(given.posthog.capture).not.toHaveBeenCalled()
|
|
294
|
-
|
|
295
|
-
fireEvent.click(screen.getByTestId('hi_example_feature_1_payload'))
|
|
296
|
-
expect(given.posthog.capture).toHaveBeenCalledTimes(1)
|
|
297
|
-
})
|
|
298
|
-
})
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
2
|
-
import { renderHook } from '@testing-library/react-hooks'
|
|
3
|
-
import { PostHogProvider } from '../../context'
|
|
4
|
-
import { usePostHog } from '..'
|
|
5
|
-
|
|
6
|
-
jest.useFakeTimers()
|
|
7
|
-
|
|
8
|
-
const posthog = { posthog_client: true }
|
|
9
|
-
|
|
10
|
-
describe('usePostHog hook', () => {
|
|
11
|
-
given('renderProvider', () => ({ children }) => (
|
|
12
|
-
<PostHogProvider client={given.posthog}>{children}</PostHogProvider>
|
|
13
|
-
))
|
|
14
|
-
|
|
15
|
-
given('posthog', () => posthog)
|
|
16
|
-
|
|
17
|
-
it('should return the client', () => {
|
|
18
|
-
let { result } = renderHook(() => usePostHog(), {
|
|
19
|
-
wrapper: given.renderProvider,
|
|
20
|
-
})
|
|
21
|
-
expect(result.current).toEqual(posthog)
|
|
22
|
-
})
|
|
23
|
-
})
|