Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/pink-ladybugs-impress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@segment/analytics-signals': minor
'@segment/analytics-signals-runtime': minor
---

Add page data to web signals
15 changes: 15 additions & 0 deletions packages/signals/signals-integration-tests/src/helpers/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { PageData } from '@segment/analytics-signals-runtime'

const pageData: PageData = {
hash: '',
hostname: 'localhost',
path: '/src/tests/signals-vanilla/index.html',
referrer: '',
search: '',
title: '',
url: 'http://localhost:5432/src/tests/signals-vanilla/index.html',
}

export const commonSignalData = {
page: pageData,
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { test, expect } from '@playwright/test'
import { commonSignalData } from '../../helpers/fixtures'
import { IndexPage } from './index-page'

const basicEdgeFn = `
Expand Down Expand Up @@ -57,6 +58,7 @@ test('network signals xhr', async () => {
)
expect(responses).toHaveLength(1)
expect(responses[0].properties!.data.data).toEqual({ someResponse: 'yep' })
expect(responses[0].properties!.data.page).toEqual(commonSignalData.page)
})

test('instrumentation signals', async () => {
Expand Down Expand Up @@ -113,6 +115,7 @@ test('interaction signals', async () => {
type: 'submit',
value: '',
},
page: commonSignalData.page,
}

expect(interactionSignals[0]).toMatchObject({
Expand Down Expand Up @@ -182,6 +185,7 @@ test('navigation signals', async ({ page }) => {
hash: '#foo',
search: '',
title: '',
page: expect.any(Object),
},
})
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { test, expect } from '@playwright/test'
import { commonSignalData } from '../../helpers/fixtures'
import { IndexPage } from './index-page'

const basicEdgeFn = `const processSignal = (signal) => {}`
Expand Down Expand Up @@ -32,6 +33,7 @@ test.describe('network signals - fetch', () => {
data: null,
method: 'POST',
url: 'http://localhost/upload',
...commonSignalData,
})
})

Expand Down Expand Up @@ -61,6 +63,7 @@ test.describe('network signals - fetch', () => {
action: 'request',
url: 'http://localhost/test',
data: { key: 'value' },
...commonSignalData,
})
})

Expand Down Expand Up @@ -90,6 +93,7 @@ test.describe('network signals - fetch', () => {
action: 'request',
url: 'http://localhost/test',
data: 'hello world',
...commonSignalData,
})
})

Expand All @@ -104,6 +108,7 @@ test.describe('network signals - fetch', () => {
method: 'POST',
body: JSON.stringify({ key: 'value' }),
contentType: 'application/json',
...commonSignalData,
}
)

Expand All @@ -124,6 +129,7 @@ test.describe('network signals - fetch', () => {
url: 'http://localhost/test',
method: 'POST',
data: { key: 'value' },
...commonSignalData,
})

const responses = networkEvents.filter(
Expand All @@ -137,6 +143,7 @@ test.describe('network signals - fetch', () => {
data: { foo: 'test' },
status: 200,
ok: true,
...commonSignalData,
})
})

Expand Down Expand Up @@ -165,6 +172,7 @@ test.describe('network signals - fetch', () => {
action: 'request',
url: `${indexPage.origin()}/test`,
data: { key: 'value' },
...commonSignalData,
})

const responses = networkEvents.filter(
Expand All @@ -175,6 +183,7 @@ test.describe('network signals - fetch', () => {
action: 'response',
url: `${indexPage.origin()}/test`,
data: { foo: 'test' },
...commonSignalData,
})
})

Expand Down Expand Up @@ -214,6 +223,7 @@ test.describe('network signals - fetch', () => {
data: { errorMsg: 'foo' },
status: 400,
ok: false,
page: expect.any(Object),
})
expect(responses).toHaveLength(1)
})
Expand Down Expand Up @@ -253,6 +263,7 @@ test.describe('network signals - fetch', () => {
data: 'foo',
status: 400,
ok: false,
...commonSignalData,
})
expect(responses).toHaveLength(1)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { InstrumentationSignal, InteractionSignal, Signal } from '../index'
import {
mockInstrumentationSignal,
mockInteractionSignal,
mockPageData,
} from '../test-helpers/mocks/mock-signal-types-web'

import { WebSignalsRuntime } from '../web/web-signals-runtime'
Expand All @@ -17,6 +18,7 @@ describe(WebSignalsRuntime, () => {
signal3 = {
...mockInteractionSignal,
data: {
page: mockPageData,
eventType: 'change',
target: {} as any,
change: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,24 @@ import {
InstrumentationSignal,
UserDefinedSignal,
NetworkSignal,
PageData,
} from '../../web/web-signals-types'
// Mock data for testing

export const mockPageData: PageData = {
url: 'https://www.segment.com/docs/connections/sources/catalog/libraries/website/javascript/',
path: '/docs/connections/sources/catalog/libraries/website/javascript/',
search: '',
hostname: 'www.segment.com',
hash: '',
referrer: '',
title: 'Segment - Documentation',
}

export const mockInteractionSignal: InteractionSignal = {
type: 'interaction',
data: {
page: mockPageData,
eventType: 'click',
target: {
id: 'button1',
Expand All @@ -22,6 +35,7 @@ export const mockInteractionSignal: InteractionSignal = {
export const mockNavigationSignal: NavigationSignal = {
type: 'navigation',
data: {
page: mockPageData,
action: 'urlChange',
url: 'https://example.com',
hash: '#section1',
Expand All @@ -33,6 +47,7 @@ export const mockNavigationSignal: NavigationSignal = {
export const mockInstrumentationSignal: InstrumentationSignal = {
type: 'instrumentation',
data: {
page: mockPageData,
rawEvent: { type: 'customEvent', detail: 'example' },
},
metadata: { timestamp: Date.now() },
Expand All @@ -41,6 +56,7 @@ export const mockInstrumentationSignal: InstrumentationSignal = {
export const mockNetworkSignal: NetworkSignal = {
type: 'network',
data: {
page: mockPageData,
action: 'request',
contentType: 'application/json',
url: 'https://api.example.com/data',
Expand All @@ -53,6 +69,7 @@ export const mockNetworkSignal: NetworkSignal = {
export const mockUserDefinedSignal: UserDefinedSignal = {
type: 'userDefined',
data: {
page: mockPageData,
customField: 'customValue',
},
metadata: { timestamp: Date.now() },
Expand Down
48 changes: 47 additions & 1 deletion packages/signals/signals-runtime/src/web/web-signals-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,55 @@ import { BaseSignal, JSONValue } from '../shared/shared-types'

export type SignalTypes = Signal['type']

export interface PageData {
/**
* The full URL of the page
* If there is a canonical URL, this should be the canonical URL
* @example https://www.segment.com/docs/connections/sources/catalog/libraries/website/javascript/
*/
url: string
/**
* The path of the page
* @example /docs/connections/sources/catalog/libraries/website/javascript/
*/
path: string
/**
* The search parameters of the page
* @example ?utm_source=google
*/
search: string
/**
* The hostname of the page
* @example www.segment.com
*/
hostname: string
/**
* The hash of the page
* @example #hash
*/
hash: string
/**
* The referrer of the page
* @example https://www.google.com/
*/
referrer: string
/**
* The title of the page
* @example Segment - Documentation
*/
title: string
}

/**
* The base data that all web signal data must have
*/
interface BaseWebData {
page: PageData
}

export interface RawSignal<T extends SignalTypes, Data> extends BaseSignal {
type: T
data: Data
data: Data & BaseWebData
metadata?: Record<string, any>
}
export type InteractionData = ClickData | SubmitData | ChangeData
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,20 @@ describe(AnalyticsService, () => {
middleware({ payload: { obj: mockEvent }, next: jest.fn() })

expect(mockSignalEmitter.emit).toHaveBeenCalledTimes(1)
expect(mockSignalEmitter.emit.mock.calls[0]).toMatchInlineSnapshot(`
[
{
"data": {
"rawEvent": {
"context": {
"foo": 123,
},
"type": "track",
const call = mockSignalEmitter.emit.mock.calls[0][0]
delete call.data.page
expect(call).toMatchInlineSnapshot(`
{
"data": {
"rawEvent": {
"context": {
"foo": 123,
},
"type": "track",
},
"type": "instrumentation",
},
]
"type": "instrumentation",
}
`)
})
it('should not emit signals if the event is a Signal event', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { createSuccess } from '@segment/analytics-next/src/test-helpers/factories'
import unfetch from 'unfetch'
import {
createInstrumentationSignal,
createNetworkSignal,
} from '../../../../types/factories'
import { SignalsIngestClient } from '../signals-ingest-client'

jest.mock('unfetch')
Expand All @@ -18,14 +22,11 @@ describe(SignalsIngestClient, () => {

it('makes an instrumentation track call via the analytics api', async () => {
expect(client).toBeTruthy()
const ctx = await client.send({
const signal = createInstrumentationSignal({
type: 'instrumentation',
data: {
rawEvent: {
foo: 'bar',
},
},
foo: 'bar',
})
const ctx = await client.send(signal)

expect(ctx!.event.type).toEqual('track')
expect(ctx!.event.properties).toEqual({
Expand All @@ -40,19 +41,17 @@ describe(SignalsIngestClient, () => {
})
it('makes a network track call via the analytics api', async () => {
expect(client).toBeTruthy()
const ctx = await client.send({
type: 'network',
const signal = createNetworkSignal({
contentType: 'application/json',
action: 'request',
data: {
contentType: 'application/json',
action: 'request',
data: {
hello: 'how are you',
},
method: 'POST',
url: 'http://foo.com',
hello: 'how are you',
},
method: 'POST',
url: 'http://foo.com',
})

const ctx = await client.send(signal)
expect(ctx!.event.type).toEqual('track')
expect(ctx!.event.properties!.type).toBe('network')
expect(ctx!.event.properties!.data).toMatchInlineSnapshot(`
Expand All @@ -63,6 +62,15 @@ describe(SignalsIngestClient, () => {
"hello": "XXX",
},
"method": "POST",
"page": {
"hash": "",
"hostname": "localhost",
"path": "/",
"referrer": "",
"search": "",
"title": "",
"url": "http://localhost/",
},
"url": "http://foo.com",
}
`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe(redactSignalData, () => {
})

it('should return the signal as is if the type is "userDefined"', () => {
const signal = { type: 'userDefined', data: { value: 'secret' } } as const
const signal = factories.createUserDefinedSignal({ value: 'secret' })
expect(redactSignalData(signal)).toEqual(signal)
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const redactSignalData = (signalArg: Signal): Signal => {
}
}
} else if (signal.type === 'network') {
signal.data = redactJsonValues(signal.data, 2)
signal.data.data = redactJsonValues(signal.data.data)
}
return signal
}
Expand Down
Loading