Skip to content

Commit 80e0d0a

Browse files
authored
Refactor inspector logic to use emitter (#718)
1 parent e16017d commit 80e0d0a

File tree

12 files changed

+97
-27
lines changed

12 files changed

+97
-27
lines changed

.changeset/fair-beans-pay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@segment/analytics-next': patch
3+
---
4+
5+
Refactor inspector to use emitter

.changeset/forty-fireants-smile.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@segment/analytics-core': patch
3+
---
4+
5+
Change emitter message to dispatch_start

packages/browser/src/browser/__tests__/analytics-pre-init.integration.test.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ describe('Pre-initialization', () => {
2727
const trackSpy = jest.spyOn(Analytics.prototype, 'track')
2828
const identifySpy = jest.spyOn(Analytics.prototype, 'identify')
2929
const onSpy = jest.spyOn(Analytics.prototype, 'on')
30+
const getOnSpyCalls = (event: string) =>
31+
onSpy.mock.calls.filter(([arg1]) => arg1 === event)
32+
3033
const readySpy = jest.spyOn(Analytics.prototype, 'ready')
3134
const browserLoadSpy = jest.spyOn(AnalyticsBrowser, 'load')
3235
const consoleErrorSpy = jest.spyOn(console, 'error')
@@ -236,11 +239,9 @@ describe('Pre-initialization', () => {
236239
expect(trackSpy).toBeCalledWith('bar')
237240
expect(trackSpy).toBeCalledTimes(2)
238241

239-
expect(identifySpy).toBeCalledWith()
240242
expect(identifySpy).toBeCalledTimes(1)
241243

242-
expect(onSpy).toBeCalledTimes(1)
243-
244+
expect(getOnSpyCalls('track').length).toBe(1)
244245
expect(onTrackCb).toBeCalledTimes(2) // gets called once for each track event
245246
expect(onTrackCb).toBeCalledWith('foo', {}, undefined)
246247
expect(onTrackCb).toBeCalledWith('bar', {}, undefined)
@@ -269,9 +270,10 @@ describe('Pre-initialization', () => {
269270
expect(identifySpy).toBeCalledWith()
270271
expect(identifySpy).toBeCalledTimes(1)
271272
expect(consoleErrorSpy).toBeCalledTimes(1)
273+
272274
expect(consoleErrorSpy).toBeCalledWith('identity rejection')
273275

274-
expect(onSpy).toBeCalledTimes(1)
276+
expect(getOnSpyCalls('track').length).toBe(1)
275277

276278
expect(onTrackCb).toBeCalledTimes(2) // gets called once for each track event
277279
expect(onTrackCb).toBeCalledWith('foo', {}, undefined)
@@ -288,7 +290,7 @@ describe('Pre-initialization', () => {
288290

289291
await ajsBrowser
290292
expect(onSpy).toBeCalledWith(...args)
291-
expect(onSpy).toHaveBeenCalledTimes(1)
293+
expect(getOnSpyCalls('track').length).toBe(1)
292294
})
293295

294296
test('If, before initialization .on("track") is called and then .track is called, the callback method should be called after analytics loads', async () => {
@@ -302,10 +304,10 @@ describe('Pre-initialization', () => {
302304
await Promise.all([analytics, trackCtxPromise])
303305

304306
expect(onSpy).toBeCalledWith('track', onFnCb)
305-
expect(onSpy).toHaveBeenCalledTimes(1)
307+
expect(getOnSpyCalls('track').length).toBe(1)
306308

307309
expect(onFnCb).toHaveBeenCalledWith('foo', { name: 123 }, undefined)
308-
expect(onFnCb).toHaveBeenCalledTimes(1)
310+
expect(onFnCb).toBeCalledTimes(1)
309311
})
310312

311313
test('If, before initialization, .ready is called, the callback method should be called after analytics loads', async () => {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { createSuccess } from '../../test-helpers/factories'
2+
import { AnalyticsBrowser } from '../..'
3+
4+
import unfetch from 'unfetch'
5+
jest.mock('unfetch')
6+
jest
7+
.mocked(unfetch)
8+
.mockImplementation(() => createSuccess({ integrations: {} }))
9+
10+
const writeKey = 'foo'
11+
12+
describe('Inspector', () => {
13+
const triggeredSpy = jest.fn()
14+
const attachedSpy = jest.fn()
15+
const deliveredSpy = jest.fn()
16+
beforeEach(() => {
17+
Object.assign((window.__SEGMENT_INSPECTOR__ ??= {}), {
18+
triggered: triggeredSpy,
19+
attach: attachedSpy,
20+
delivered: deliveredSpy,
21+
})
22+
})
23+
it('attaches to inspector', async () => {
24+
await AnalyticsBrowser.load({
25+
writeKey,
26+
})
27+
expect(attachedSpy).toBeCalledTimes(1)
28+
})
29+
30+
it('calls triggered and delivered when an event is sent', async () => {
31+
const [analytics] = await AnalyticsBrowser.load({
32+
writeKey,
33+
})
34+
expect(attachedSpy).toBeCalledTimes(1)
35+
expect(triggeredSpy).toBeCalledTimes(0)
36+
expect(deliveredSpy).toBeCalledTimes(0)
37+
38+
await analytics.track('foo', {})
39+
40+
expect(triggeredSpy.mock.lastCall[0].event.type).toBe('track')
41+
expect(triggeredSpy).toBeCalledTimes(1)
42+
expect(deliveredSpy).toBeCalledTimes(1)
43+
})
44+
})

packages/browser/src/browser/__tests__/standalone-analytics.test.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import unfetch from 'unfetch'
77
import { PersistedPriorityQueue } from '../../lib/priority-queue/persisted'
88
import { sleep } from '../../lib/sleep'
99
import * as Factory from '../../test-helpers/factories'
10+
import { EventQueue } from '@segment/analytics-core'
1011

1112
const track = jest.fn()
1213
const identify = jest.fn()
@@ -26,9 +27,7 @@ jest.mock('@/core/analytics', () => ({
2627
register,
2728
emit: jest.fn(),
2829
on,
29-
queue: {
30-
queue: new PersistedPriorityQueue(1, 'event-queue'),
31-
},
30+
queue: new EventQueue(new PersistedPriorityQueue(1, 'event-queue') as any),
3231
options,
3332
}),
3433
}))
@@ -237,8 +236,11 @@ describe('standalone bundle', () => {
237236

238237
await sleep(0)
239238

240-
expect(on).toHaveBeenCalledTimes(1)
241-
expect(on).toHaveBeenCalledWith('initialize', expect.any(Function))
239+
const initializeCalls = on.mock.calls.filter(
240+
([arg1]) => arg1 === 'initialize'
241+
)
242+
243+
expect(initializeCalls.length).toBe(1)
242244

243245
expect(operations).toEqual([
244246
// should run before any plugin is registered

packages/browser/src/browser/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import {
2323
flushOn,
2424
} from '../core/buffer'
2525
import { popSnippetWindowBuffer } from '../core/buffer/snippet'
26-
import { inspectorHost } from '../core/inspector'
2726
import { ClassicIntegrationSource } from '../plugins/ajs-destination/types'
27+
import { attachInspector } from '../core/inspector'
2828

2929
export interface LegacyIntegrationConfiguration {
3030
/* @deprecated - This does not indicate browser types anymore */
@@ -275,7 +275,7 @@ async function loadAnalytics(
275275
const opts: InitOptions = { retryQueue, ...options }
276276
const analytics = new Analytics(settings, opts)
277277

278-
inspectorHost.attach?.(analytics as any)
278+
attachInspector(analytics)
279279

280280
const plugins = settings.plugins ?? []
281281
const classicIntegrations = settings.classicIntegrations ?? []

packages/browser/src/core/analytics/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ import type {
4747
import { version } from '../../generated/version'
4848
import { PriorityQueue } from '../../lib/priority-queue'
4949
import { getGlobal } from '../../lib/get-global'
50-
import { inspectorHost } from '../inspector'
5150
import { AnalyticsClassic, AnalyticsCore } from './interfaces'
5251

5352
const deprecationWarning =
@@ -372,7 +371,7 @@ export class Analytics
372371
): Promise<DispatchedEvent> {
373372
const ctx = new Context(event)
374373

375-
inspectorHost.triggered?.(ctx as any)
374+
this.emit('dispatch_start', ctx)
376375

377376
if (isOffline() && !this.options.retryQueue) {
378377
return ctx

packages/browser/src/core/inspector/__tests__/index.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Analytics } from '../../analytics'
1+
import { attachInspector } from '..'
2+
import { Analytics } from '../../..'
23

34
let analytics: Analytics
45

@@ -13,6 +14,7 @@ describe('Inspector interface', () => {
1314
analytics = new Analytics({
1415
writeKey: 'abc',
1516
})
17+
attachInspector(analytics)
1618
})
1719

1820
it('notifies the connected inspector client about each event API call and delivery', async () => {

packages/browser/src/core/inspector/index.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { InspectBroker } from '@segment/inspector-webext'
22
import { getGlobal } from '../../lib/get-global'
3+
import type { Analytics } from '../analytics'
34

45
declare global {
56
interface Window {
@@ -12,6 +13,19 @@ const env = getGlobal()
1213
// The code below assumes the inspector extension will use Object.assign
1314
// to add the inspect interface on to this object reference (unless the
1415
// extension code ran first and has already set up the variable)
15-
export const inspectorHost: Partial<InspectBroker> = ((env as any)[
16+
const inspectorHost: Partial<InspectBroker> = ((env as any)[
1617
'__SEGMENT_INSPECTOR__'
1718
] ??= {})
19+
20+
export const attachInspector = (analytics: Analytics) => {
21+
inspectorHost.attach?.(analytics as any)
22+
23+
analytics.on('dispatch_start', (ctx) => inspectorHost.triggered?.(ctx))
24+
25+
analytics.queue.on('message_enriched', (ctx) => inspectorHost.enriched?.(ctx))
26+
27+
analytics.queue.on('message_delivered', (ctx) =>
28+
// FIXME: Resolve browsers destinations that the event was sent to
29+
inspectorHost.delivered?.(ctx, ['segment.io'])
30+
)
31+
}

packages/browser/src/core/queue/event-queue.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { Integrations, JSONObject } from '../events'
99
import { Plugin } from '../plugin'
1010
import { createTaskGroup, TaskGroup } from '../task/task-group'
1111
import { attempt, ensure } from './delivery'
12-
import { inspectorHost } from '../inspector'
1312
import { UniversalStorage } from '../user'
1413

1514
type PluginsByType = {
@@ -287,7 +286,7 @@ export class EventQueue extends Emitter {
287286
}
288287
}
289288

290-
inspectorHost.enriched?.(ctx as any)
289+
this.emit('message_enriched', ctx)
291290

292291
// Enrichment and before plugins can re-arrange the deny list dynamically
293292
// so we need to pluck them at the end
@@ -306,8 +305,7 @@ export class EventQueue extends Emitter {
306305

307306
ctx.stats.increment('message_delivered')
308307

309-
// FIXME: Resolve browsers destinations that the event was sent to
310-
inspectorHost.delivered?.(ctx as any, ['segment.io'])
308+
this.emit('message_delivered', ctx)
311309

312310
const afterCalls = after.map((after) => attempt(ctx, after))
313311
await Promise.all(afterCalls)

0 commit comments

Comments
 (0)