Skip to content

Commit 584c81a

Browse files
Supporting Group event in Userpilot cloud destination (#2838)
1 parent 3cd1798 commit 584c81a

File tree

8 files changed

+259
-1
lines changed

8 files changed

+259
-1
lines changed

packages/destination-actions/src/destinations/userpilot/__tests__/__snapshots__/snapshot.test.ts.snap

+17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`Testing snapshot for actions-userpilot destination: identifyCompany action - all fields 1`] = `
4+
Object {
5+
"company_id": "89X4YJ9nBQcMn%#",
6+
"metadata": Object {
7+
"created_at": "2021-02-01T00:00:00.000Z",
8+
"testType": "89X4YJ9nBQcMn%#",
9+
},
10+
}
11+
`;
12+
13+
exports[`Testing snapshot for actions-userpilot destination: identifyCompany action - required fields 1`] = `
14+
Object {
15+
"company_id": "89X4YJ9nBQcMn%#",
16+
"metadata": Object {},
17+
}
18+
`;
19+
320
exports[`Testing snapshot for actions-userpilot destination: identifyUser action - all fields 1`] = `
421
Object {
522
"metadata": Object {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Testing snapshot for Userpilot's identifyCompany destination action: all fields 1`] = `
4+
Object {
5+
"company_id": "%F6H5r8FNR",
6+
"metadata": Object {
7+
"created_at": "2021-02-01T00:00:00.000Z",
8+
"testType": "%F6H5r8FNR",
9+
},
10+
}
11+
`;
12+
13+
exports[`Testing snapshot for Userpilot's identifyCompany destination action: required fields 1`] = `
14+
Object {
15+
"company_id": "%F6H5r8FNR",
16+
"metadata": Object {},
17+
}
18+
`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import nock from 'nock'
2+
import { createTestEvent, createTestIntegration } from '@segment/actions-core'
3+
import Destination from '../../index'
4+
5+
const testDestination = createTestIntegration(Destination)
6+
7+
const companyId = 'fake-company-id'
8+
const apiKey = 'fake-api-key'
9+
const baseUrl = 'https://analytex.userpilot.io/'
10+
11+
describe('Userpilot.identifyCompany', () => {
12+
it('should call identifyCompany successfully', async () => {
13+
nock(baseUrl).post('/v1/companies/identify').reply(202, {})
14+
15+
const event = createTestEvent({
16+
groupId: companyId,
17+
traits: {
18+
name: 'Company Name',
19+
primary_email: '[email protected]',
20+
createdAt: '2021-01-01'
21+
}
22+
})
23+
24+
const responses = await testDestination.testAction('identifyCompany', {
25+
event,
26+
settings: {
27+
apiKey: apiKey,
28+
endpoint: baseUrl
29+
},
30+
mapping: {
31+
groupId: companyId,
32+
traits: {
33+
name: 'Company Name',
34+
primary_email: '[email protected]',
35+
createdAt: '2021-01-01'
36+
}
37+
}
38+
})
39+
40+
expect(responses.length).toBe(1)
41+
expect(responses[0].status).toBe(202)
42+
43+
expect(responses[0].options.body).toMatchInlineSnapshot(
44+
`"{\\"company_id\\":\\"fake-company-id\\",\\"metadata\\":{\\"name\\":\\"Company Name\\",\\"primary_email\\":\\"[email protected]\\"}}"`
45+
)
46+
47+
expect(nock.isDone()).toBe(true)
48+
})
49+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { createTestEvent, createTestIntegration } from '@segment/actions-core'
2+
import { generateTestData } from '../../../../lib/test-data'
3+
import destination from '../../index'
4+
import nock from 'nock'
5+
6+
const testDestination = createTestIntegration(destination)
7+
const actionSlug = 'identifyCompany'
8+
const destinationSlug = 'Userpilot'
9+
const seedName = `${destinationSlug}#${actionSlug}`
10+
11+
describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
12+
it('required fields', async () => {
13+
const action = destination.actions[actionSlug]
14+
const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
15+
16+
nock(/.*/).persist().get(/.*/).reply(200)
17+
nock(/.*/).persist().post(/.*/).reply(200)
18+
nock(/.*/).persist().put(/.*/).reply(200)
19+
20+
const event = createTestEvent({
21+
properties: eventData
22+
})
23+
24+
const responses = await testDestination.testAction(actionSlug, {
25+
event: event,
26+
mapping: event.properties,
27+
settings: settingsData,
28+
auth: undefined
29+
})
30+
31+
const request = responses[0].request
32+
const rawBody = await request.text()
33+
34+
try {
35+
const json = JSON.parse(rawBody)
36+
expect(json).toMatchSnapshot()
37+
return
38+
} catch (err) {
39+
expect(rawBody).toMatchSnapshot()
40+
}
41+
42+
expect(request.headers).toMatchSnapshot()
43+
})
44+
45+
it('all fields', async () => {
46+
const action = destination.actions[actionSlug]
47+
const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
48+
49+
nock(/.*/).persist().get(/.*/).reply(200)
50+
nock(/.*/).persist().post(/.*/).reply(200)
51+
nock(/.*/).persist().put(/.*/).reply(200)
52+
53+
const event = createTestEvent({
54+
properties: eventData
55+
})
56+
57+
const responses = await testDestination.testAction(actionSlug, {
58+
event: event,
59+
mapping: event.properties,
60+
settings: settingsData,
61+
auth: undefined
62+
})
63+
64+
const request = responses[0].request
65+
const rawBody = await request.text()
66+
67+
try {
68+
const json = JSON.parse(rawBody)
69+
expect(json).toMatchSnapshot()
70+
return
71+
} catch (err) {
72+
expect(rawBody).toMatchSnapshot()
73+
}
74+
})
75+
})

packages/destination-actions/src/destinations/userpilot/identifyCompany/generated-types.ts

+18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import type { ActionDefinition } from '@segment/actions-core'
2+
import type { Settings } from '../generated-types'
3+
import type { Payload } from './generated-types'
4+
5+
import { getCompanyIdentifyRequestParams } from '../request-utils'
6+
7+
const action: ActionDefinition<Settings, Payload> = {
8+
title: 'Identify Company',
9+
description:
10+
'Defines a company in Userpilot, you can visit [Userpilot docs](https://docs.userpilot.com/article/23-identify-users-track-custom-events) for more information.',
11+
defaultSubscription: 'type = "group"',
12+
fields: {
13+
groupId: {
14+
type: 'string',
15+
required: true,
16+
description: 'The ID of the company.',
17+
label: 'Company ID',
18+
default: {
19+
'@path': '$.groupId'
20+
}
21+
},
22+
createdAt: {
23+
type: 'datetime',
24+
required: false,
25+
description: 'The date the company profile was created at',
26+
label: 'Company Created At Date',
27+
default: {
28+
'@path': '$.traits.createdAt'
29+
}
30+
},
31+
traits: {
32+
type: 'object',
33+
required: false,
34+
description: 'Segment traits',
35+
label: 'Traits',
36+
default: {
37+
'@path': '$.traits'
38+
}
39+
}
40+
},
41+
perform: (request, { settings, payload }) => {
42+
const { traits, groupId, createdAt } = payload
43+
44+
traits?.createdAt && delete traits.createdAt
45+
46+
const { url, options } = getCompanyIdentifyRequestParams(settings, {
47+
traits: { ...traits, created_at: createdAt || traits?.created_at },
48+
groupId
49+
})
50+
51+
return request(url, options)
52+
}
53+
}
54+
55+
export default action

packages/destination-actions/src/destinations/userpilot/index.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { DestinationDefinition } from '@segment/actions-core'
2+
23
import { defaultValues } from '@segment/actions-core'
34

45
import type { Settings } from './generated-types'
@@ -9,6 +10,8 @@ import identifyUser from './identifyUser'
910

1011
import trackEvent from './trackEvent'
1112

13+
import identifyCompany from './identifyCompany'
14+
1215
const destination: DestinationDefinition<Settings> = {
1316
name: 'Userpilot Cloud (Actions)',
1417
slug: 'actions-userpilot-cloud',
@@ -21,6 +24,13 @@ const destination: DestinationDefinition<Settings> = {
2124
mapping: defaultValues(identifyUser.fields),
2225
type: 'automatic'
2326
},
27+
{
28+
name: 'Identify Company',
29+
subscribe: 'type = "group"',
30+
partnerAction: 'identifyCompany',
31+
mapping: defaultValues(identifyCompany.fields),
32+
type: 'automatic'
33+
},
2434
{
2535
name: 'Track Event',
2636
subscribe: 'type = "track"',
@@ -72,7 +82,8 @@ const destination: DestinationDefinition<Settings> = {
7282

7383
actions: {
7484
identifyUser,
75-
trackEvent
85+
trackEvent,
86+
identifyCompany
7687
}
7788
}
7889

packages/destination-actions/src/destinations/userpilot/request-utils.ts

+15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Settings } from './generated-types'
22
import type { Payload as IdentifyPayload } from './identifyUser/generated-types'
33
import type { Payload as TrackPayload } from './trackEvent/generated-types'
4+
import type { Payload as GroupPayload } from './identifyCompany/generated-types'
45

56
import { RequestOptions } from '@segment/actions-core'
67

@@ -45,6 +46,20 @@ export const getIdentifyRequestParams = (settings: Settings, payload: IdentifyPa
4546
}
4647
}
4748
}
49+
export const getCompanyIdentifyRequestParams = (settings: Settings, payload: GroupPayload): RequestParams => {
50+
const { traits, groupId } = payload
51+
52+
return {
53+
url: `${validateEndpoint(settings.endpoint)}v1/companies/identify`,
54+
options: {
55+
method: 'POST',
56+
json: {
57+
company_id: groupId,
58+
metadata: traits
59+
}
60+
}
61+
}
62+
}
4863

4964
export const getTrackEventParams = (settings: Settings, payload: TrackPayload): RequestParams => {
5065
const { userId, name, properties } = payload

0 commit comments

Comments
 (0)