Skip to content

Commit 0fdf170

Browse files
authored
Process signals that occur before init (#1116)
1 parent a9251f0 commit 0fdf170

File tree

11 files changed

+111
-19
lines changed

11 files changed

+111
-19
lines changed

.changeset/pretty-clouds-occur.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@segment/analytics-signals': patch
3+
---
4+
5+
Process signals that occur before analytics init

packages/signals/signals-example/src/lib/analytics.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22
// You only want to instantiate SignalsPlugin in a browser context, otherwise you'll get an error.
33

44
import { AnalyticsBrowser } from '@segment/analytics-next'
5-
import {
6-
SignalsPlugin,
7-
ProcessSignal,
8-
} from '@segment/analytics-signals'
5+
import { SignalsPlugin, ProcessSignal } from '@segment/analytics-signals'
96

107
export const analytics = new AnalyticsBrowser()
118
if (!process.env.WRITEKEY) {
@@ -49,7 +46,6 @@ export const loadAnalytics = () =>
4946
...(isStage ? { cdnURL: 'https://cdn.segment.build' } : {}),
5047
},
5148
{
52-
initialPageview: true,
5349
...(isStage
5450
? {
5551
integrations: {

packages/signals/signals-integration-tests/src/helpers/base-page-object.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,14 @@ export class BasePage {
2929
this.edgeFn = edgeFn
3030
await this.setupMockedRoutes()
3131
await this.page.goto(this.url)
32-
// expect analytics to be loaded
33-
await Promise.all([
32+
}
33+
34+
/**
35+
* Wait for analytics and signals to be initialized
36+
* Signals can be captured before this, so it's useful to have this method
37+
*/
38+
async waitForAnalyticsInit() {
39+
return Promise.all([
3440
this.waitForCDNSettingsResponse(),
3541
this.waitForEdgeFunctionResponse(),
3642
])
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import type { AnalyticsBrowser } from '@segment/analytics-next'
2+
import type { SignalsPlugin } from '@segment/analytics-signals'
23

34
declare global {
45
interface Window {
56
analytics: AnalyticsBrowser
7+
signalsPlugin: SignalsPlugin
68
}
79
}

packages/signals/signals-integration-tests/src/tests/signals-vanilla/all-segment-events.test.ts

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const indexPage = new IndexPage()
1010

1111
const normalizeSnapshotEvent = (el: SegmentEvent) => {
1212
return {
13-
type: el.properties?.type,
13+
type: el.type,
1414
event: el.event,
1515
userId: el.userId,
1616
groupId: el.groupId,
@@ -38,21 +38,60 @@ test('Segment events', async ({ page }) => {
3838
const basicEdgeFn = `
3939
// this is a process signal function
4040
const processSignal = (signal) => {
41-
analytics.identify('john', { found: true })
42-
analytics.group('foo', { hello: 'world' })
43-
analytics.alias('john', 'johnsmith')
44-
analytics.track('a track call', {foo: 'bar'})
45-
analytics.page('Retail Page', 'Home', { url: 'http://my-home.com', title: 'Some Title' });
41+
if (signal.type === 'interaction' && signal.data.eventType === 'click') {
42+
analytics.identify('john', { found: true })
43+
analytics.group('foo', { hello: 'world' })
44+
analytics.alias('john', 'johnsmith')
45+
analytics.track('a track call', {foo: 'bar'})
46+
analytics.page('Retail Page', 'Home', { url: 'http://my-home.com', title: 'Some Title' });
47+
}
4648
}`
4749

4850
await indexPage.load(page, basicEdgeFn)
51+
await indexPage.clickButton()
4952
await Promise.all([
50-
indexPage.clickButton(),
5153
indexPage.waitForSignalsApiFlush(),
5254
indexPage.waitForTrackingApiFlush(),
5355
])
5456

5557
const trackingApiReqs = indexPage.trackingApiReqs.map(normalizeSnapshotEvent)
56-
5758
expect(trackingApiReqs).toEqual(snapshot)
5859
})
60+
61+
test('Should dispatch events from signals that occurred before analytics was instantiated', async ({
62+
page,
63+
}) => {
64+
const edgeFn = `
65+
const processSignal = (signal) => {
66+
if (signal.type === 'navigation' && signal.data.action === 'pageLoad') {
67+
analytics.page('dispatched from signals - navigation')
68+
}
69+
if (signal.type === 'userDefined') {
70+
analytics.track('dispatched from signals - userDefined')
71+
}
72+
}`
73+
74+
await indexPage.load(page, edgeFn)
75+
76+
// add a user defined signal before analytics is instantiated
77+
void indexPage.addUserDefinedSignal()
78+
79+
await indexPage.waitForAnalyticsInit()
80+
81+
await Promise.all([
82+
indexPage.waitForSignalsApiFlush(),
83+
indexPage.waitForTrackingApiFlush(),
84+
])
85+
const trackingApiReqs = indexPage.trackingApiReqs
86+
expect(trackingApiReqs).toHaveLength(2)
87+
88+
const pageEvents = trackingApiReqs.find((el) => el.type === 'page')!
89+
expect(pageEvents).toBeTruthy()
90+
expect(pageEvents.name).toEqual('dispatched from signals - navigation')
91+
92+
const userDefinedEvents = trackingApiReqs.find((el) => el.type === 'track')!
93+
expect(userDefinedEvents).toBeTruthy()
94+
expect(userDefinedEvents.event).toEqual(
95+
'dispatched from signals - userDefined'
96+
)
97+
})

packages/signals/signals-integration-tests/src/tests/signals-vanilla/basic.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const basicEdgeFn = `
1515

1616
test.beforeEach(async ({ page }) => {
1717
await indexPage.load(page, basicEdgeFn)
18+
await indexPage.waitForAnalyticsInit()
1819
})
1920

2021
test('network signals', async () => {

packages/signals/signals-integration-tests/src/tests/signals-vanilla/index-page.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,25 @@ export class IndexPage extends BasePage {
1414
return promiseTimeout(p, 2000, 'analytics.on("page") did not resolve')
1515
}
1616

17+
async makeAnalyticsTrackCall(): Promise<unknown> {
18+
const p = this.page.evaluate(() => {
19+
void window.analytics.track('some event')
20+
return new Promise((resolve) => window.analytics.on('track', resolve))
21+
})
22+
return promiseTimeout(p, 2000, 'analytics.on("track") did not resolve')
23+
}
24+
25+
addUserDefinedSignal() {
26+
return this.page.evaluate(() => {
27+
window.signalsPlugin.addSignal({
28+
type: 'userDefined',
29+
data: {
30+
foo: 'bar',
31+
},
32+
})
33+
})
34+
}
35+
1736
async mockRandomJSONApi() {
1837
await this.page.route('http://localhost:5432/api/foo', (route) => {
1938
return route.fulfill({

packages/signals/signals-integration-tests/src/tests/signals-vanilla/signals-bundle.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ const signalsPlugin = new SignalsPlugin({
88
disableSignalsRedaction: true,
99
})
1010

11+
;(window as any).signalsPlugin = signalsPlugin
12+
1113
analytics.load({
1214
writeKey: '<SOME_WRITE_KEY>',
1315
plugins: [signalsPlugin],

packages/signals/signals/src/core/processor/processor.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,12 @@ export class SignalEventProcessor {
1212

1313
async process(signal: Signal, signals: Signal[]) {
1414
const analyticsMethodCalls = await this.sandbox.process(signal, signals)
15-
logger.debug('New signal processed. Analytics method calls:', {
16-
methodArgs: analyticsMethodCalls,
17-
})
1815

1916
for (const methodName in analyticsMethodCalls) {
2017
const name = methodName as MethodName
2118
const eventsCollection = analyticsMethodCalls[name]
2219
eventsCollection.forEach((args) => {
20+
logger.debug(`analytics.${name}(...) called with args`, args)
2321
// @ts-ignore
2422
this.analytics[name](...args)
2523
})

packages/signals/signals/src/core/processor/sandbox.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,6 @@ export class Sandbox {
221221
await this.jsSandbox.run(code, scope)
222222

223223
const calls = analytics.getCalls()
224-
logger.debug('analytics calls', calls)
225224
return calls
226225
}
227226
}

0 commit comments

Comments
 (0)