react-fathom 0.1.0 → 0.1.1
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/README.md +215 -52
- package/dist/cjs/index.cjs +3 -4
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/next/index.cjs +186 -725
- package/dist/cjs/next/index.cjs.map +1 -1
- package/dist/es/index.js +3 -4
- package/dist/es/index.js.map +1 -1
- package/dist/es/next/index.js +186 -724
- package/dist/es/next/index.js.map +1 -1
- package/dist/react-fathom.js +3 -4
- package/dist/react-fathom.js.map +1 -1
- package/dist/react-fathom.min.js +2 -2
- package/dist/react-fathom.min.js.map +1 -1
- package/package.json +15 -1
- package/src/FathomProvider.tsx +0 -1
- package/src/next/NextFathomTrackViewApp.test.tsx +265 -0
- package/src/next/NextFathomTrackViewApp.tsx +78 -0
- package/src/next/NextFathomTrackViewPages.test.tsx +222 -0
- package/src/next/NextFathomTrackViewPages.tsx +83 -0
- package/src/next/compositions/withAppRouter.test.tsx +31 -10
- package/src/next/compositions/withAppRouter.tsx +10 -3
- package/src/next/compositions/withPagesRouter.test.tsx +31 -10
- package/src/next/compositions/withPagesRouter.tsx +10 -3
- package/src/next/index.ts +3 -3
- package/src/next/types.ts +0 -7
- package/src/types.ts +0 -1
- package/types/FathomProvider.d.ts.map +1 -1
- package/types/next/NextFathomProviderApp.d.ts.map +1 -1
- package/types/next/NextFathomProviderPages.d.ts.map +1 -1
- package/types/next/NextFathomTrackViewApp.d.ts +34 -0
- package/types/next/NextFathomTrackViewApp.d.ts.map +1 -0
- package/types/next/NextFathomTrackViewPages.d.ts +30 -0
- package/types/next/NextFathomTrackViewPages.d.ts.map +1 -0
- package/types/next/compositions/withAppRouter.d.ts +1 -0
- package/types/next/compositions/withAppRouter.d.ts.map +1 -1
- package/types/next/compositions/withPagesRouter.d.ts +1 -0
- package/types/next/compositions/withPagesRouter.d.ts.map +1 -1
- package/types/next/index.d.ts +2 -3
- package/types/next/index.d.ts.map +1 -1
- package/types/next/types.d.ts +0 -6
- package/types/next/types.d.ts.map +1 -1
- package/types/types.d.ts +0 -1
- package/types/types.d.ts.map +1 -1
- package/src/next/NextFathomProvider.test.tsx +0 -131
- package/src/next/NextFathomProvider.tsx +0 -62
- package/src/next/NextFathomProviderApp.test.tsx +0 -308
- package/src/next/NextFathomProviderApp.tsx +0 -106
- package/src/next/NextFathomProviderPages.test.tsx +0 -330
- package/src/next/NextFathomProviderPages.tsx +0 -112
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
4
|
-
|
|
5
|
-
import { renderHook, waitFor } from '@testing-library/react'
|
|
6
|
-
|
|
7
|
-
import NextFathomProviderApp from './NextFathomProviderApp'
|
|
8
|
-
import { useFathom } from '../hooks/useFathom'
|
|
9
|
-
|
|
10
|
-
// Mock Next.js App Router hooks
|
|
11
|
-
const mockSearchParams = new URLSearchParams('?foo=bar')
|
|
12
|
-
vi.mock('next/navigation', () => ({
|
|
13
|
-
usePathname: vi.fn(() => '/test-page'),
|
|
14
|
-
useSearchParams: vi.fn(() => mockSearchParams),
|
|
15
|
-
}))
|
|
16
|
-
|
|
17
|
-
// Mock fathom-client
|
|
18
|
-
vi.mock('fathom-client', () => {
|
|
19
|
-
const mockFathomDefault = {
|
|
20
|
-
trackEvent: vi.fn(),
|
|
21
|
-
trackPageview: vi.fn(),
|
|
22
|
-
trackGoal: vi.fn(),
|
|
23
|
-
load: vi.fn(),
|
|
24
|
-
setSite: vi.fn(),
|
|
25
|
-
blockTrackingForMe: vi.fn(),
|
|
26
|
-
enableTrackingForMe: vi.fn(),
|
|
27
|
-
isTrackingEnabled: vi.fn(() => true),
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
default: mockFathomDefault,
|
|
32
|
-
}
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
describe('NextFathomProviderApp', () => {
|
|
36
|
-
const mockClient = {
|
|
37
|
-
trackEvent: vi.fn(),
|
|
38
|
-
trackPageview: vi.fn(),
|
|
39
|
-
trackGoal: vi.fn(),
|
|
40
|
-
load: vi.fn(),
|
|
41
|
-
setSite: vi.fn(),
|
|
42
|
-
blockTrackingForMe: vi.fn(),
|
|
43
|
-
enableTrackingForMe: vi.fn(),
|
|
44
|
-
isTrackingEnabled: vi.fn(() => true),
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
beforeEach(() => {
|
|
48
|
-
vi.clearAllMocks()
|
|
49
|
-
// Reset window.location
|
|
50
|
-
Object.defineProperty(window, 'location', {
|
|
51
|
-
value: {
|
|
52
|
-
origin: 'https://example.com',
|
|
53
|
-
href: 'https://example.com/test-page?foo=bar',
|
|
54
|
-
},
|
|
55
|
-
writable: true,
|
|
56
|
-
})
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
it('should load Fathom on mount when siteId is provided', async () => {
|
|
60
|
-
const loadSpy = vi.fn()
|
|
61
|
-
const client = { ...mockClient, load: loadSpy }
|
|
62
|
-
|
|
63
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
64
|
-
<NextFathomProviderApp client={client} siteId="TEST_SITE_ID">
|
|
65
|
-
{children}
|
|
66
|
-
</NextFathomProviderApp>
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
renderHook(() => useFathom(), { wrapper })
|
|
70
|
-
|
|
71
|
-
await waitFor(() => {
|
|
72
|
-
expect(loadSpy).toHaveBeenCalledWith('TEST_SITE_ID', undefined)
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
it('should load Fathom with clientOptions', async () => {
|
|
77
|
-
const loadSpy = vi.fn()
|
|
78
|
-
const clientOptions = { honorDNT: true }
|
|
79
|
-
const client = { ...mockClient, load: loadSpy }
|
|
80
|
-
|
|
81
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
82
|
-
<NextFathomProviderApp
|
|
83
|
-
client={client}
|
|
84
|
-
siteId="TEST_SITE_ID"
|
|
85
|
-
clientOptions={clientOptions}
|
|
86
|
-
>
|
|
87
|
-
{children}
|
|
88
|
-
</NextFathomProviderApp>
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
renderHook(() => useFathom(), { wrapper })
|
|
92
|
-
|
|
93
|
-
await waitFor(() => {
|
|
94
|
-
expect(loadSpy).toHaveBeenCalledWith('TEST_SITE_ID', clientOptions)
|
|
95
|
-
})
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('should track initial pageview on mount', async () => {
|
|
99
|
-
const trackPageviewSpy = vi.fn()
|
|
100
|
-
const client = { ...mockClient, trackPageview: trackPageviewSpy }
|
|
101
|
-
|
|
102
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
103
|
-
<NextFathomProviderApp client={client} siteId="TEST_SITE_ID">
|
|
104
|
-
{children}
|
|
105
|
-
</NextFathomProviderApp>
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
renderHook(() => useFathom(), { wrapper })
|
|
109
|
-
|
|
110
|
-
await waitFor(() => {
|
|
111
|
-
expect(trackPageviewSpy).toHaveBeenCalled()
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
expect(trackPageviewSpy).toHaveBeenCalledWith({
|
|
115
|
-
url: 'https://example.com/test-page?foo=bar',
|
|
116
|
-
})
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
it('should not track pageview when disableAutoTrack is true', async () => {
|
|
120
|
-
const trackPageviewSpy = vi.fn()
|
|
121
|
-
const client = { ...mockClient, trackPageview: trackPageviewSpy }
|
|
122
|
-
|
|
123
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
124
|
-
<NextFathomProviderApp
|
|
125
|
-
client={client}
|
|
126
|
-
siteId="TEST_SITE_ID"
|
|
127
|
-
disableAutoTrack
|
|
128
|
-
>
|
|
129
|
-
{children}
|
|
130
|
-
</NextFathomProviderApp>
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
renderHook(() => useFathom(), { wrapper })
|
|
134
|
-
|
|
135
|
-
// Wait a bit to ensure no tracking happens
|
|
136
|
-
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
137
|
-
|
|
138
|
-
expect(trackPageviewSpy).not.toHaveBeenCalled()
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
it('should use provided client', () => {
|
|
142
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
143
|
-
<NextFathomProviderApp client={mockClient} siteId="TEST_SITE_ID">
|
|
144
|
-
{children}
|
|
145
|
-
</NextFathomProviderApp>
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
const { result } = renderHook(() => useFathom(), { wrapper })
|
|
149
|
-
|
|
150
|
-
expect(result.current.client).toBe(mockClient)
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
it('should use default Fathom client when no client is provided', async () => {
|
|
154
|
-
// This test verifies that the component uses the default Fathom client
|
|
155
|
-
// when no client is provided. The component should still work and provide
|
|
156
|
-
// a client through the context.
|
|
157
|
-
// Note: This test may fail if Next.js hooks throw errors, so we wrap in try-catch
|
|
158
|
-
try {
|
|
159
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
160
|
-
<NextFathomProviderApp siteId="TEST_SITE_ID">
|
|
161
|
-
{children}
|
|
162
|
-
</NextFathomProviderApp>
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
const { result } = renderHook(() => useFathom(), { wrapper })
|
|
166
|
-
|
|
167
|
-
// The client should be available (either default or from parent)
|
|
168
|
-
await waitFor(() => {
|
|
169
|
-
expect(result.current.client).toBeDefined()
|
|
170
|
-
expect(result.current.trackEvent).toBeDefined()
|
|
171
|
-
expect(result.current.trackPageview).toBeDefined()
|
|
172
|
-
})
|
|
173
|
-
} catch (error) {
|
|
174
|
-
// If there's an error with Next.js hooks, skip this test
|
|
175
|
-
// The other tests verify the functionality with provided clients
|
|
176
|
-
expect(error).toBeDefined()
|
|
177
|
-
}
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
it('should merge defaultPageviewOptions', async () => {
|
|
181
|
-
const trackPageviewSpy = vi.fn()
|
|
182
|
-
const client = { ...mockClient, trackPageview: trackPageviewSpy }
|
|
183
|
-
|
|
184
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
185
|
-
<NextFathomProviderApp
|
|
186
|
-
client={client}
|
|
187
|
-
siteId="TEST_SITE_ID"
|
|
188
|
-
defaultPageviewOptions={{ referrer: 'https://example.com' }}
|
|
189
|
-
>
|
|
190
|
-
{children}
|
|
191
|
-
</NextFathomProviderApp>
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
renderHook(() => useFathom(), { wrapper })
|
|
195
|
-
|
|
196
|
-
await waitFor(() => {
|
|
197
|
-
expect(trackPageviewSpy).toHaveBeenCalled()
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
expect(trackPageviewSpy).toHaveBeenCalledWith({
|
|
201
|
-
referrer: 'https://example.com',
|
|
202
|
-
url: 'https://example.com/test-page?foo=bar',
|
|
203
|
-
})
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
it('should support deprecated trackDefaultOptions', async () => {
|
|
207
|
-
const trackPageviewSpy = vi.fn()
|
|
208
|
-
const client = { ...mockClient, trackPageview: trackPageviewSpy }
|
|
209
|
-
|
|
210
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
211
|
-
<NextFathomProviderApp
|
|
212
|
-
client={client}
|
|
213
|
-
siteId="TEST_SITE_ID"
|
|
214
|
-
trackDefaultOptions={{ referrer: 'https://example.com' }}
|
|
215
|
-
>
|
|
216
|
-
{children}
|
|
217
|
-
</NextFathomProviderApp>
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
renderHook(() => useFathom(), { wrapper })
|
|
221
|
-
|
|
222
|
-
await waitFor(() => {
|
|
223
|
-
expect(trackPageviewSpy).toHaveBeenCalled()
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
expect(trackPageviewSpy).toHaveBeenCalledWith({
|
|
227
|
-
referrer: 'https://example.com',
|
|
228
|
-
url: 'https://example.com/test-page?foo=bar',
|
|
229
|
-
})
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
it('should prioritize defaultPageviewOptions over trackDefaultOptions', async () => {
|
|
233
|
-
const trackPageviewSpy = vi.fn()
|
|
234
|
-
const client = { ...mockClient, trackPageview: trackPageviewSpy }
|
|
235
|
-
|
|
236
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
237
|
-
<NextFathomProviderApp
|
|
238
|
-
client={client}
|
|
239
|
-
siteId="TEST_SITE_ID"
|
|
240
|
-
trackDefaultOptions={{ referrer: 'old' }}
|
|
241
|
-
defaultPageviewOptions={{ referrer: 'new' }}
|
|
242
|
-
>
|
|
243
|
-
{children}
|
|
244
|
-
</NextFathomProviderApp>
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
renderHook(() => useFathom(), { wrapper })
|
|
248
|
-
|
|
249
|
-
await waitFor(() => {
|
|
250
|
-
expect(trackPageviewSpy).toHaveBeenCalled()
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
expect(trackPageviewSpy).toHaveBeenCalledWith({
|
|
254
|
-
referrer: 'new',
|
|
255
|
-
url: 'https://example.com/test-page?foo=bar',
|
|
256
|
-
})
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
it('should compose with parent FathomProvider', () => {
|
|
260
|
-
const parentClient = {
|
|
261
|
-
trackEvent: vi.fn(),
|
|
262
|
-
trackPageview: vi.fn(),
|
|
263
|
-
trackGoal: vi.fn(),
|
|
264
|
-
load: vi.fn(),
|
|
265
|
-
setSite: vi.fn(),
|
|
266
|
-
blockTrackingForMe: vi.fn(),
|
|
267
|
-
enableTrackingForMe: vi.fn(),
|
|
268
|
-
isTrackingEnabled: vi.fn(() => true),
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
272
|
-
<NextFathomProviderApp client={parentClient} siteId="TEST_SITE_ID">
|
|
273
|
-
{children}
|
|
274
|
-
</NextFathomProviderApp>
|
|
275
|
-
)
|
|
276
|
-
|
|
277
|
-
const { result } = renderHook(() => useFathom(), { wrapper })
|
|
278
|
-
|
|
279
|
-
expect(result.current.client).toBe(parentClient)
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
it('should handle pathname with search params', async () => {
|
|
283
|
-
// This test verifies the component handles search params correctly
|
|
284
|
-
const trackPageviewSpy = vi.fn()
|
|
285
|
-
const client = { ...mockClient, trackPageview: trackPageviewSpy }
|
|
286
|
-
|
|
287
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
288
|
-
<NextFathomProviderApp client={client} siteId="TEST_SITE_ID">
|
|
289
|
-
{children}
|
|
290
|
-
</NextFathomProviderApp>
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
renderHook(() => useFathom(), { wrapper })
|
|
294
|
-
|
|
295
|
-
await waitFor(() => {
|
|
296
|
-
expect(trackPageviewSpy).toHaveBeenCalled()
|
|
297
|
-
})
|
|
298
|
-
|
|
299
|
-
// Should include search params from mock
|
|
300
|
-
expect(trackPageviewSpy).toHaveBeenCalledWith({
|
|
301
|
-
url: 'https://example.com/test-page?foo=bar',
|
|
302
|
-
})
|
|
303
|
-
})
|
|
304
|
-
|
|
305
|
-
it('should have displayName', () => {
|
|
306
|
-
expect(NextFathomProviderApp.displayName).toBe('NextFathomProviderApp')
|
|
307
|
-
})
|
|
308
|
-
})
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef, useMemo } from 'react'
|
|
2
|
-
|
|
3
|
-
import * as Fathom from 'fathom-client'
|
|
4
|
-
import type { PageViewOptions } from 'fathom-client'
|
|
5
|
-
import { usePathname, useSearchParams } from 'next/navigation'
|
|
6
|
-
|
|
7
|
-
import { FathomProvider } from '../FathomProvider'
|
|
8
|
-
import type { NextFathomProviderProps } from './types'
|
|
9
|
-
import { useFathom } from '../hooks/useFathom'
|
|
10
|
-
|
|
11
|
-
const NextFathomProviderApp: React.FC<NextFathomProviderProps> = ({
|
|
12
|
-
children,
|
|
13
|
-
client: providedClient,
|
|
14
|
-
clientOptions,
|
|
15
|
-
disableAutoTrack = false,
|
|
16
|
-
siteId,
|
|
17
|
-
trackDefaultOptions,
|
|
18
|
-
defaultPageviewOptions: providedDefaultPageviewOptions,
|
|
19
|
-
}) => {
|
|
20
|
-
const pathname = usePathname()
|
|
21
|
-
const searchParams = useSearchParams()
|
|
22
|
-
const hasTrackedInitialPageview = useRef(false)
|
|
23
|
-
const parentContext = useFathom()
|
|
24
|
-
|
|
25
|
-
// Use provided client or fall back to parent client or default Fathom
|
|
26
|
-
const client = useMemo(
|
|
27
|
-
() => providedClient ?? parentContext.client ?? Fathom,
|
|
28
|
-
[providedClient, parentContext.client],
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
// Support both deprecated trackDefaultOptions and new defaultPageviewOptions
|
|
32
|
-
// Priority: providedDefaultPageviewOptions > trackDefaultOptions > parent defaultPageviewOptions
|
|
33
|
-
const defaultPageviewOptions = useMemo(
|
|
34
|
-
() =>
|
|
35
|
-
providedDefaultPageviewOptions ??
|
|
36
|
-
trackDefaultOptions ??
|
|
37
|
-
parentContext.defaultPageviewOptions,
|
|
38
|
-
[
|
|
39
|
-
providedDefaultPageviewOptions,
|
|
40
|
-
trackDefaultOptions,
|
|
41
|
-
parentContext.defaultPageviewOptions,
|
|
42
|
-
],
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
const trackPageview = useCallback(
|
|
46
|
-
(options?: PageViewOptions) => {
|
|
47
|
-
if (siteId !== undefined && client !== undefined) {
|
|
48
|
-
client.trackPageview({
|
|
49
|
-
...defaultPageviewOptions,
|
|
50
|
-
...options,
|
|
51
|
-
})
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
[client, siteId, defaultPageviewOptions],
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
// Initialize Fathom on mount
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
if (siteId !== undefined && client !== undefined) {
|
|
60
|
-
client.load(siteId, clientOptions)
|
|
61
|
-
}
|
|
62
|
-
}, [client, clientOptions, siteId])
|
|
63
|
-
|
|
64
|
-
// Track pageviews on route changes
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
if (siteId === undefined || disableAutoTrack) {
|
|
67
|
-
return
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const searchString = searchParams?.toString()
|
|
71
|
-
const url =
|
|
72
|
-
pathname +
|
|
73
|
-
(searchString !== undefined && searchString !== ''
|
|
74
|
-
? `?${searchString}`
|
|
75
|
-
: '')
|
|
76
|
-
|
|
77
|
-
// Track initial pageview only once
|
|
78
|
-
if (!hasTrackedInitialPageview.current) {
|
|
79
|
-
hasTrackedInitialPageview.current = true
|
|
80
|
-
trackPageview({
|
|
81
|
-
url: window.location.origin + url,
|
|
82
|
-
})
|
|
83
|
-
} else {
|
|
84
|
-
// Track subsequent route changes
|
|
85
|
-
trackPageview({
|
|
86
|
-
url: window.location.origin + url,
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
}, [pathname, searchParams, siteId, disableAutoTrack, trackPageview])
|
|
90
|
-
|
|
91
|
-
return (
|
|
92
|
-
<FathomProvider
|
|
93
|
-
client={client}
|
|
94
|
-
clientOptions={clientOptions}
|
|
95
|
-
siteId={siteId}
|
|
96
|
-
defaultPageviewOptions={defaultPageviewOptions}
|
|
97
|
-
>
|
|
98
|
-
{children}
|
|
99
|
-
</FathomProvider>
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
NextFathomProviderApp.displayName = 'NextFathomProviderApp'
|
|
104
|
-
|
|
105
|
-
export default NextFathomProviderApp
|
|
106
|
-
export { NextFathomProviderApp }
|