Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Expand Up @@ -27,11 +27,8 @@ export class IndexPage extends BasePage {
return this.page.evaluate(
(args) => {
window.signalsPlugin.addSignal({
type: 'userDefined',
data: {
foo: 'bar',
...args.data,
},
foo: 'bar',
...args.data,
})
},
{ data }
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
*/
export interface BaseWebData {
page: PageData
}

export interface RawSignal<T extends SignalTypes, Data> extends BaseSignal {
type: T
data: Data
data: BaseWebData & Data
metadata?: Record<string, any>
}
export type InteractionData = ClickData | SubmitData | ChangeData
Expand Down
11 changes: 7 additions & 4 deletions packages/signals/signals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,13 @@ analytics.load({
```ts
import { signalsPlugin } from './analytics' // assuming you exported your plugin instance.
signalsPlugin.addSignal({
type: 'userDefined',
data: { foo: 'bar' }
})
signalsPlugin.addSignal({ someData: 'foo' })

// emits a signal with the following shape
{
type: 'userDefined'
data: { someData: 'foo', ... }
}
```

### Debugging
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
Loading