@crimson-education/browser-logger 5.0.1-beta.3 → 5.0.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.
Files changed (68) hide show
  1. package/README.md +127 -73
  2. package/lib/index.d.ts +1 -1
  3. package/lib/index.d.ts.map +1 -1
  4. package/lib/index.js +47 -19
  5. package/lib/index.js.map +1 -1
  6. package/lib/logger/consoleTransport.d.ts +1 -1
  7. package/lib/logger/consoleTransport.d.ts.map +1 -1
  8. package/lib/logger/consoleTransport.js +22 -16
  9. package/lib/logger/consoleTransport.js.map +1 -1
  10. package/lib/logger/datadogTransport.d.ts +1 -1
  11. package/lib/logger/datadogTransport.d.ts.map +1 -1
  12. package/lib/logger/datadogTransport.js +8 -4
  13. package/lib/logger/datadogTransport.js.map +1 -1
  14. package/lib/logger/index.js +49 -29
  15. package/lib/logger/index.js.map +1 -1
  16. package/lib/logger/index.test.js +18 -16
  17. package/lib/logger/index.test.js.map +1 -1
  18. package/lib/logger/utils.js +9 -4
  19. package/lib/logger/utils.js.map +1 -1
  20. package/lib/reporters/amplifyReporter.d.ts +86 -0
  21. package/lib/reporters/amplifyReporter.d.ts.map +1 -0
  22. package/lib/reporters/amplifyReporter.js +225 -0
  23. package/lib/reporters/amplifyReporter.js.map +1 -0
  24. package/lib/reporters/amplifyReporter.test.d.ts +2 -0
  25. package/lib/reporters/amplifyReporter.test.d.ts.map +1 -0
  26. package/lib/reporters/amplifyReporter.test.js +51 -0
  27. package/lib/reporters/amplifyReporter.test.js.map +1 -0
  28. package/lib/reporters/datadogReporter.d.ts +1 -13
  29. package/lib/reporters/datadogReporter.d.ts.map +1 -1
  30. package/lib/reporters/datadogReporter.js +49 -122
  31. package/lib/reporters/datadogReporter.js.map +1 -1
  32. package/lib/reporters/gtmReporter.d.ts +1 -1
  33. package/lib/reporters/gtmReporter.d.ts.map +1 -1
  34. package/lib/reporters/gtmReporter.js +5 -1
  35. package/lib/reporters/gtmReporter.js.map +1 -1
  36. package/lib/reporters/index.js +71 -46
  37. package/lib/reporters/index.js.map +1 -1
  38. package/lib/reporters/logReporter.js +34 -24
  39. package/lib/reporters/logReporter.js.map +1 -1
  40. package/lib/reporters/posthogReporter.d.ts +51 -0
  41. package/lib/reporters/posthogReporter.d.ts.map +1 -0
  42. package/lib/reporters/posthogReporter.js +254 -0
  43. package/lib/reporters/posthogReporter.js.map +1 -0
  44. package/lib/reporters/posthogReporter.test.d.ts +2 -0
  45. package/lib/reporters/posthogReporter.test.d.ts.map +1 -0
  46. package/lib/reporters/posthogReporter.test.js +197 -0
  47. package/lib/reporters/posthogReporter.test.js.map +1 -0
  48. package/lib/types/index.js +18 -2
  49. package/lib/types/index.js.map +1 -1
  50. package/lib/types/logger.d.ts +3 -3
  51. package/lib/types/logger.d.ts.map +1 -1
  52. package/lib/types/logger.js +5 -2
  53. package/lib/types/logger.js.map +1 -1
  54. package/lib/types/reporter.d.ts +20 -6
  55. package/lib/types/reporter.d.ts.map +1 -1
  56. package/lib/types/reporter.js +2 -1
  57. package/lib/utils.js +5 -1
  58. package/lib/utils.js.map +1 -1
  59. package/lib/utils.test.js +4 -2
  60. package/lib/utils.test.js.map +1 -1
  61. package/package.json +17 -11
  62. package/src/index.ts +11 -0
  63. package/src/reporters/amplifyReporter.test.ts +61 -0
  64. package/src/reporters/amplifyReporter.ts +344 -0
  65. package/src/reporters/datadogReporter.ts +22 -133
  66. package/src/reporters/posthogReporter.test.ts +244 -0
  67. package/src/reporters/posthogReporter.ts +374 -0
  68. package/src/types/reporter.ts +16 -0
@@ -15,95 +15,6 @@ import { datadogRum, DefaultPrivacyLevel, RumInitConfiguration } from '@datadog/
15
15
  import { logTransports } from '../logger';
16
16
  import { DatadogLogTransportConfig, datadogTransport } from '../logger/datadogTransport';
17
17
 
18
- // User frustration detection for Datadog Gen2
19
- class DatadogFrustrationDetector {
20
- private config: DatadogReporterConfig;
21
- private frustrationEvents: Array<{ type: string; timestamp: number }> = [];
22
- private readonly FRUSTRATION_THRESHOLD = 3; // Number of events to trigger frustration
23
- private readonly FRUSTRATION_WINDOW = 5000; // Time window in ms
24
-
25
- constructor(config: DatadogReporterConfig) {
26
- this.config = config;
27
- if (config.trackFrustrations) {
28
- this.setupFrustrationDetection();
29
- }
30
- }
31
-
32
- private setupFrustrationDetection() {
33
- // Track rapid clicks (potential frustration)
34
- let clickCount = 0;
35
- let lastClickTime = 0;
36
-
37
- document.addEventListener('click', () => {
38
- const now = Date.now();
39
- if (now - lastClickTime < 1000) {
40
- // Rapid clicks within 1 second
41
- clickCount++;
42
- if (clickCount >= 3) {
43
- this.recordFrustrationEvent('rapid_clicks');
44
- clickCount = 0;
45
- }
46
- } else {
47
- clickCount = 1;
48
- }
49
- lastClickTime = now;
50
- });
51
-
52
- // Track form errors (potential frustration)
53
- document.addEventListener('invalid', () => {
54
- this.recordFrustrationEvent('form_validation_error');
55
- });
56
-
57
- // Track 404 errors (potential frustration)
58
- window.addEventListener('error', (event) => {
59
- if (event.message.includes('404') || event.message.includes('Not Found')) {
60
- this.recordFrustrationEvent('page_not_found');
61
- }
62
- });
63
-
64
- // Track network errors (potential frustration)
65
- window.addEventListener('unhandledrejection', (event) => {
66
- if (event.reason && typeof event.reason === 'object' && 'status' in event.reason) {
67
- const status = (event.reason as any).status;
68
- if (status >= 400) {
69
- this.recordFrustrationEvent('network_error');
70
- }
71
- }
72
- });
73
- }
74
-
75
- private recordFrustrationEvent(type: string) {
76
- const now = Date.now();
77
- this.frustrationEvents.push({ type, timestamp: now });
78
-
79
- // Clean old events outside the window
80
- this.frustrationEvents = this.frustrationEvents.filter((event) => now - event.timestamp < this.FRUSTRATION_WINDOW);
81
-
82
- // Check if we have enough events to trigger frustration
83
- if (this.frustrationEvents.length >= this.FRUSTRATION_THRESHOLD) {
84
- this.triggerFrustrationDetection();
85
- }
86
- }
87
-
88
- private triggerFrustrationDetection() {
89
- const frustrationData = {
90
- frustrationType: 'user_frustration_detected',
91
- frustrationEvents: this.frustrationEvents.map((e) => e.type),
92
- frustrationCount: this.frustrationEvents.length,
93
- pageUrl: window.location.href,
94
- timestamp: new Date().toISOString(),
95
- };
96
-
97
- // Send frustration event to Datadog
98
- if (typeof datadogRum !== 'undefined') {
99
- datadogRum.addAction('User Frustration Detected', frustrationData);
100
- }
101
-
102
- // Clear events after reporting
103
- this.frustrationEvents = [];
104
- }
105
- }
106
-
107
18
  export interface DatadogReporterConfig extends ReporterConfigBase {
108
19
  /** The RUM application ID. */
109
20
  applicationId: string;
@@ -125,17 +36,11 @@ export interface DatadogReporterConfig extends ReporterConfigBase {
125
36
  * @deprecated Prefer using the dedicated `logSampleRate`, `rumSampleRate`, and `replaySampleRate` options.
126
37
  */
127
38
  sampleRate?: number;
128
-
129
- sessionSampleRate?: number;
130
- sessionReplaySampleRate?: number;
131
-
132
39
  /**
133
40
  * Sampling rate for browser log collection. Defaults to 100, meaning every log message is sent to Datadog.
134
41
  */
135
42
  logSampleRate?: number;
136
-
137
43
  /**
138
- * @deprecated Prefer using `sessionSampleRate`.
139
44
  * Sampling rate for RUM session collection. Defaults to 100, meaning every browser session is tracked.
140
45
  *
141
46
  * RUM can be used to track things like core web vitals.
@@ -143,9 +48,7 @@ export interface DatadogReporterConfig extends ReporterConfigBase {
143
48
  * @see https://www.datadoghq.com/product/real-user-monitoring/
144
49
  */
145
50
  rumSampleRate?: number;
146
-
147
51
  /**
148
- * @deprecated Prefer using `sessionReplaySampleRate`.
149
52
  * Applied after the RUM sample rate, and controls the percentage of sessions tracked as Browser RUM & Session Replay.
150
53
  * It defaults to 100, so every session is tracked as Browser RUM & Session Replay by default.
151
54
  *
@@ -157,21 +60,11 @@ export interface DatadogReporterConfig extends ReporterConfigBase {
157
60
  * Use a secure session cookie. This disables RUM events sent on insecure (non-HTTPS) connections.
158
61
  */
159
62
  useSecureSessionCookie?: boolean;
160
-
161
63
  /**
162
- * @deprecated Prefer using `usePartitionedCrossSiteSessionCookie`.
163
64
  * Use a secure cross-site session cookie.
164
65
  * This allows the RUM Browser SDK to run when the site is loaded from another one (iframe). Implies `useSecureSessionCookie`
165
66
  */
166
67
  useCrossSiteSessionCookie?: boolean;
167
-
168
- /**
169
- * Use a partitioned secure cross-site session cookie. This allows the RUM Browser SDK to run when the site is loaded from another one (iframe). Implies `useSecureSessionCookie`.
170
- * Important: If you are using the RUM and Logs Browser SDKs, this option must be configured with identical values
171
- * @default false
172
- */
173
- usePartitionedCrossSiteSessionCookie?: boolean;
174
-
175
68
  /**
176
69
  * Preserve the session across subdomains for the same site.
177
70
  */
@@ -224,8 +117,7 @@ export interface DatadogReporterConfig extends ReporterConfigBase {
224
117
  /**
225
118
  * A list of request origins used to inject tracing headers, to be able to connect RUM and backend tracing.
226
119
  */
227
- allowedTrackingOrigins?: (string | RegExp)[];
228
- allowedTracingUrls?: (string | RegExp)[];
120
+ allowedTracingOrigins?: (string | RegExp)[];
229
121
  /**
230
122
  * Enables action tracking for user interactions. This enables the Heatmap tab within Datadog
231
123
  */
@@ -248,23 +140,23 @@ export function datadogReporter(info: ServiceInfo, config: DatadogReporterConfig
248
140
  const enableLogTransport = config.logTransport !== false;
249
141
 
250
142
  // Only init datadog logs if something is using it.
251
- if (forwardErrorsToLogs === true || enableLogTransport === true) {
143
+ if (forwardErrorsToLogs !== true && enableLogTransport !== true) {
252
144
  datadogLogs.init({
253
- site: config.site as any,
145
+ site: config.site,
146
+ proxyUrl: config.proxyUrl,
254
147
  clientToken: config.clientToken,
255
148
  service: info.service,
256
149
  env: info.environment,
257
150
  version: config.version ?? info.version,
258
151
 
152
+ sampleRate: config.logSampleRate ?? config.sampleRate ?? 100,
259
153
  beforeSend: config.beforeLogsSend,
260
154
 
261
- usePartitionedCrossSiteSessionCookie: config.usePartitionedCrossSiteSessionCookie,
262
155
  useSecureSessionCookie: config.useSecureSessionCookie ?? !isLocalhost,
263
- // Note: useCrossSiteSessionCookie is not available in newer Datadog versions
156
+ useCrossSiteSessionCookie: config.useCrossSiteSessionCookie ?? false,
264
157
  trackSessionAcrossSubdomains: config.trackSessionAcrossSubdomains,
265
158
 
266
159
  forwardErrorsToLogs,
267
- allowedTrackingOrigins: config.allowedTrackingOrigins,
268
160
  });
269
161
  datadogLogs.logger.setHandler(HandlerType.http);
270
162
  }
@@ -276,37 +168,34 @@ export function datadogReporter(info: ServiceInfo, config: DatadogReporterConfig
276
168
 
277
169
  datadogRum.init({
278
170
  enableExperimentalFeatures: ['feature_flags'],
279
- site: config.site as any,
171
+ site: config.site,
172
+ proxyUrl: config.proxyUrl,
280
173
  clientToken: config.clientToken,
281
174
  applicationId: config.applicationId,
282
175
  service: info.service,
283
176
  env: info.environment,
284
177
  version: config.version ?? info.version,
285
178
 
286
- usePartitionedCrossSiteSessionCookie: config.usePartitionedCrossSiteSessionCookie,
287
- // Use correct Datadog v6 SDK options
288
- sessionSampleRate: config.sessionSampleRate ?? config.rumSampleRate ?? config.sampleRate ?? 100,
289
- sessionReplaySampleRate: config.sessionReplaySampleRate?? config.replaySampleRate ?? 100,
290
-
291
- // Track interactions (Note: trackFrustrations is not available in Datadog v6)
292
- trackUserInteractions: config.trackUserInteractions ?? config.trackInteractions ?? false,
179
+ sampleRate: config.rumSampleRate ?? config.sampleRate ?? 100,
180
+ replaySampleRate: config.replaySampleRate ?? 100,
293
181
 
294
182
  useSecureSessionCookie: config.useSecureSessionCookie ?? !isLocalhost,
295
- // Note: useCrossSiteSessionCookie is not available in newer Datadog versions
183
+ useCrossSiteSessionCookie: config.useCrossSiteSessionCookie ?? false,
296
184
  trackSessionAcrossSubdomains: config.trackSessionAcrossSubdomains,
185
+
186
+ trackInteractions: config.trackInteractions ?? false,
187
+ trackFrustrations: config.trackFrustrations ?? false,
297
188
  trackViewsManually: config.trackViewsManually ?? false,
298
189
  actionNameAttribute: config.actionNameAttribute ?? 'data-analytics-name',
299
190
  beforeSend: config.beforeSend,
300
191
 
301
192
  defaultPrivacyLevel: config.defaultPrivacyLevel ?? 'mask-user-input',
302
- allowedTracingUrls: config.allowedTracingUrls ?? config.allowedTrackingOrigins,
303
-
193
+ allowedTracingOrigins: config.allowedTracingOrigins,
194
+ trackUserInteractions: config.trackUserInteractions ?? false,
195
+
304
196
  excludedActivityUrls: config.excludedActivityUrls,
305
197
  });
306
198
 
307
- // Initialize frustration detector
308
- new DatadogFrustrationDetector(config);
309
-
310
199
  const reporter: IReporter = {
311
200
  trackEvent: function (event: ReporterEvent): void {
312
201
  datadogRum.addAction(event.message, {
@@ -325,16 +214,16 @@ export function datadogReporter(info: ServiceInfo, config: DatadogReporterConfig
325
214
  addMetadata: function (metadata: Metadata): void {
326
215
  for (const [key, value] of Object.entries(metadata)) {
327
216
  if (value !== null) {
328
- datadogRum.setGlobalContextProperty(key, value);
217
+ datadogRum.addRumGlobalContext(key, value);
329
218
 
330
219
  // Note, this will add duplicate context data in logs.
331
220
  // But this is valuable for logs ingested outside of the browser logger.
332
- datadogLogs.setGlobalContextProperty(key, value);
221
+ datadogLogs.addLoggerGlobalContext(key, value);
333
222
  } else {
334
- datadogRum.removeGlobalContextProperty(key);
223
+ datadogRum.removeRumGlobalContext(key);
335
224
 
336
225
  // But this is valuable for logs ingested outside of the browser logger.
337
- datadogLogs.removeGlobalContextProperty(key);
226
+ datadogLogs.removeLoggerGlobalContext(key);
338
227
  }
339
228
  }
340
229
  },
@@ -347,7 +236,7 @@ export function datadogReporter(info: ServiceInfo, config: DatadogReporterConfig
347
236
  name: user.name ?? user.email,
348
237
  });
349
238
  } else {
350
- datadogRum.setUser({});
239
+ datadogRum.removeUser();
351
240
  }
352
241
  },
353
242
  setRouteName: function (routeName: string): void {
@@ -0,0 +1,244 @@
1
+ jest.mock('posthog-js', () => ({
2
+ __esModule: true,
3
+ default: {
4
+ init: jest.fn(),
5
+ capture: jest.fn(),
6
+ captureException: jest.fn(),
7
+ getPageViewId: jest.fn(() => 'view-123'),
8
+ get_session_id: jest.fn(() => 'session-123'),
9
+ identify: jest.fn(),
10
+ register: jest.fn(),
11
+ reset: jest.fn(),
12
+ startSessionRecording: jest.fn(),
13
+ stopSessionRecording: jest.fn(),
14
+ unregister: jest.fn(),
15
+ },
16
+ }));
17
+
18
+ import posthog from 'posthog-js';
19
+ import { LogLevel } from '../types';
20
+ import { normalizeProperties, posthogReporter } from './posthogReporter';
21
+
22
+ const posthogMock = posthog as unknown as {
23
+ init: jest.Mock;
24
+ capture: jest.Mock;
25
+ captureException: jest.Mock;
26
+ getPageViewId: jest.Mock;
27
+ get_session_id: jest.Mock;
28
+ identify: jest.Mock;
29
+ register: jest.Mock;
30
+ reset: jest.Mock;
31
+ startSessionRecording: jest.Mock;
32
+ stopSessionRecording: jest.Mock;
33
+ unregister: jest.Mock;
34
+ };
35
+
36
+ describe('posthogReporter', () => {
37
+ beforeEach(() => {
38
+ jest.clearAllMocks();
39
+ });
40
+
41
+ it('normalizes metadata into PostHog-safe properties', () => {
42
+ const normalized = normalizeProperties({
43
+ a: 1,
44
+ b: true,
45
+ c: 'value',
46
+ d: undefined,
47
+ e: null,
48
+ f: new Date('2026-07-03T00:00:00.000Z'),
49
+ g: new Error('boom'),
50
+ h: {
51
+ nested: 'yes',
52
+ },
53
+ i: [1, undefined, 'x'],
54
+ });
55
+
56
+ expect(normalized).toEqual({
57
+ a: 1,
58
+ b: true,
59
+ c: 'value',
60
+ f: '2026-07-03T00:00:00.000Z',
61
+ g: {
62
+ message: 'boom',
63
+ name: 'Error',
64
+ stack: expect.any(String),
65
+ },
66
+ h: {
67
+ nested: 'yes',
68
+ },
69
+ i: [1, 'x'],
70
+ });
71
+ });
72
+
73
+ it('maps browser-logger APIs onto PostHog', () => {
74
+ const reporter = posthogReporter(
75
+ {
76
+ service: 'crimson-app-frontend',
77
+ application: 'crimson-app',
78
+ environment: 'production',
79
+ version: '1.2.3',
80
+ },
81
+ {
82
+ apiKey: 'ph_key',
83
+ apiHost: 'https://eu.i.posthog.com',
84
+ replaySampleRate: 0,
85
+ },
86
+ );
87
+
88
+ expect(posthogMock.init).toHaveBeenCalledWith(
89
+ 'ph_key',
90
+ expect.objectContaining({
91
+ api_host: 'https://eu.i.posthog.com',
92
+ before_send: expect.any(Function),
93
+ capture_pageview: 'history_change',
94
+ disable_session_recording: true,
95
+ person_profiles: 'identified_only',
96
+ }),
97
+ );
98
+
99
+ reporter.addMetadata({
100
+ namespace: 'production',
101
+ clearMe: null,
102
+ });
103
+ expect(posthogMock.unregister).toHaveBeenCalledWith('clearMe');
104
+ expect(posthogMock.register).toHaveBeenCalledWith({
105
+ namespace: 'production',
106
+ });
107
+
108
+ reporter.trackEvent({
109
+ message: 'message-sent',
110
+ level: LogLevel.Info,
111
+ metadata: {
112
+ userId: '123',
113
+ },
114
+ metrics: {
115
+ durationMs: 42,
116
+ },
117
+ });
118
+ expect(posthogMock.capture).toHaveBeenCalledWith('message-sent', {
119
+ message: 'message-sent',
120
+ level: LogLevel.Info,
121
+ userId: '123',
122
+ durationMs: 42,
123
+ });
124
+
125
+ reporter.setUser({
126
+ id: '123',
127
+ email: 'user@crimsoneducation.org',
128
+ name: 'Crimson User',
129
+ });
130
+ expect(posthogMock.identify).toHaveBeenCalledWith('123', {
131
+ email: 'user@crimsoneducation.org',
132
+ name: 'Crimson User',
133
+ });
134
+
135
+ reporter.reportError?.(new Error('broken'), {
136
+ routeName: 'messages',
137
+ });
138
+ expect(posthogMock.captureException).toHaveBeenCalledWith(
139
+ expect.any(Error),
140
+ expect.objectContaining({
141
+ message: 'broken',
142
+ routeName: 'messages',
143
+ }),
144
+ );
145
+
146
+ reporter.recordSession?.();
147
+ reporter.recordSessionStop?.();
148
+ expect(posthogMock.startSessionRecording).toHaveBeenCalledWith(true);
149
+ expect(posthogMock.stopSessionRecording).toHaveBeenCalled();
150
+ });
151
+
152
+ it('adds compatibility properties in before_send', () => {
153
+ const beforeSend = jest.fn((captureResult) => captureResult);
154
+
155
+ posthogReporter(
156
+ {
157
+ service: 'crimson-app-frontend',
158
+ application: 'crimson-app',
159
+ environment: 'production',
160
+ version: '1.2.3',
161
+ },
162
+ {
163
+ apiKey: 'ph_key',
164
+ apiHost: 'https://eu.i.posthog.com',
165
+ beforeSend,
166
+ },
167
+ );
168
+
169
+ const initConfig = posthogMock.init.mock.calls[0]?.[1];
170
+ const captureResult = initConfig.before_send({
171
+ uuid: 'event-uuid',
172
+ event: 'message-sent',
173
+ properties: {
174
+ $current_url: 'https://app.crimsoneducation.org/messages/1',
175
+ $browser: 'Chrome',
176
+ $device_type: 'Desktop',
177
+ $geoip_country_name: 'New Zealand',
178
+ },
179
+ });
180
+
181
+ expect(captureResult.properties).toEqual(
182
+ expect.objectContaining({
183
+ app_name: 'crimson-app',
184
+ domain: 'app.crimsoneducation.org',
185
+ event_type: 'message-sent',
186
+ url: 'https://app.crimsoneducation.org/messages/1',
187
+ url_path: '/messages/1',
188
+ browser: 'Chrome',
189
+ device: 'Desktop',
190
+ geo: 'New Zealand',
191
+ }),
192
+ );
193
+ expect(beforeSend).toHaveBeenCalledWith(captureResult);
194
+ });
195
+
196
+ it('preserves registered metadata when clearing the user', () => {
197
+ const reporter = posthogReporter(
198
+ {
199
+ service: 'student-center-frontend',
200
+ application: 'core-student-center',
201
+ environment: 'production',
202
+ version: '2.0.0',
203
+ },
204
+ {
205
+ apiKey: 'ph_key',
206
+ apiHost: 'https://eu.i.posthog.com',
207
+ },
208
+ );
209
+
210
+ reporter.addMetadata({
211
+ application: 'core-student-center',
212
+ namespace: 'production',
213
+ });
214
+
215
+ reporter.setUser(null);
216
+
217
+ expect(posthogMock.reset).toHaveBeenCalled();
218
+ expect(posthogMock.register).toHaveBeenLastCalledWith({
219
+ application: 'core-student-center',
220
+ namespace: 'production',
221
+ });
222
+ });
223
+
224
+ it('treats an empty user id as a cleared user', () => {
225
+ const reporter = posthogReporter(
226
+ {
227
+ service: 'new-roadmap',
228
+ environment: 'staging',
229
+ version: '1.0.0',
230
+ },
231
+ {
232
+ apiKey: 'ph_key',
233
+ apiHost: 'https://eu.i.posthog.com',
234
+ },
235
+ );
236
+
237
+ reporter.setUser({
238
+ id: '',
239
+ });
240
+
241
+ expect(posthogMock.reset).toHaveBeenCalled();
242
+ expect(posthogMock.identify).not.toHaveBeenCalled();
243
+ });
244
+ });