Skip to content

Commit 8ea03ca

Browse files
Ortto audiences (Engage) (#2927)
* Ortto audiences * Update packages/destination-actions/src/destinations/ortto-audiences/syncAudience/index.ts Co-authored-by: Joe Ayoub <[email protected]> * Update packages/destination-actions/src/destinations/ortto-audiences/syncAudience/index.ts Co-authored-by: Joe Ayoub <[email protected]> * Update packages/destination-actions/src/destinations/ortto-audiences/syncAudience/index.ts Co-authored-by: Joe Ayoub <[email protected]> * Update packages/destination-actions/src/destinations/ortto-audiences/syncAudience/index.ts Co-authored-by: Joe Ayoub <[email protected]> * Update packages/destination-actions/src/destinations/ortto-audiences/syncAudience/index.ts Co-authored-by: Joe Ayoub <[email protected]> * Fix missing scope --------- Co-authored-by: Joe Ayoub <[email protected]>
1 parent 4512d5f commit 8ea03ca

File tree

13 files changed

+1226
-0
lines changed

13 files changed

+1226
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Testing snapshot for actions-ortto-audiences destination: syncAudience action - all fields 1`] = `
4+
Array [
5+
Object {
6+
"anonymous_id": "rOxF$I97!M",
7+
"audience": Object {
8+
"id": "rOxF$I97!M",
9+
"mode": "remove",
10+
},
11+
"ip": "81.60.139.81",
12+
"location": Object {
13+
"city": "rOxF$I97!M",
14+
"country": "rOxF$I97!M",
15+
"post_code": "rOxF$I97!M",
16+
"state": "rOxF$I97!M",
17+
},
18+
"message_id": "rOxF$I97!M",
19+
"traits": Object {
20+
"testType": "rOxF$I97!M",
21+
},
22+
"user_id": "rOxF$I97!M",
23+
},
24+
]
25+
`;
26+
27+
exports[`Testing snapshot for actions-ortto-audiences destination: syncAudience action - required fields 1`] = `
28+
Array [
29+
Object {
30+
"anonymous_id": "rOxF$I97!M",
31+
"audience": Object {
32+
"id": "rOxF$I97!M",
33+
"mode": "remove",
34+
},
35+
"message_id": "rOxF$I97!M",
36+
"traits": Object {
37+
"testType": "rOxF$I97!M",
38+
},
39+
"user_id": "rOxF$I97!M",
40+
},
41+
]
42+
`;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import nock from 'nock'
2+
import { createTestIntegration, InvalidAuthenticationError } from '@segment/actions-core'
3+
import Definition from '../index'
4+
import { API_VERSION } from '../ortto-client'
5+
import { TEST_API_KEY } from '../types'
6+
7+
const testDestination = createTestIntegration(Definition)
8+
9+
describe('Ortto (audiences)', () => {
10+
describe('authentication', () => {
11+
it('should reject empty api keys', async () => {
12+
try {
13+
await testDestination.testAuthentication({ api_key: '' })
14+
} catch (err) {
15+
expect(err instanceof InvalidAuthenticationError)
16+
}
17+
})
18+
19+
it('should reject whitespace api keys', async () => {
20+
try {
21+
await testDestination.testAuthentication({ api_key: ' ' })
22+
} catch (err) {
23+
expect(err instanceof InvalidAuthenticationError)
24+
}
25+
})
26+
27+
it('should reject invalid api keys', async () => {
28+
try {
29+
await testDestination.testAuthentication({ api_key: 'invalid' })
30+
} catch (err) {
31+
expect(err instanceof InvalidAuthenticationError)
32+
}
33+
})
34+
35+
it('should accept valid api keys', async () => {
36+
nock('https://segment-action-api-au.ortto.app')
37+
.get(`/${API_VERSION}/me`)
38+
.matchHeader('authorization', `Bearer ${TEST_API_KEY}`)
39+
.reply(200, {})
40+
await expect(testDestination.testAuthentication({ api_key: TEST_API_KEY })).resolves.not.toThrowError()
41+
})
42+
})
43+
})
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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+
import { TEST_API_KEY } from '../types'
6+
7+
const testDestination = createTestIntegration(destination)
8+
const destinationSlug = 'actions-ortto-audiences'
9+
10+
describe(`Testing snapshot for ${destinationSlug} destination:`, () => {
11+
for (const actionSlug in destination.actions) {
12+
it(`${actionSlug} action - required fields`, async () => {
13+
const seedName = `${destinationSlug}#${actionSlug}`
14+
const action = destination.actions[actionSlug]
15+
const [eventData] = generateTestData(seedName, destination, action, true)
16+
17+
nock(/.*/).persist().get(/.*/).reply(200)
18+
nock(/.*/).persist().post(/.*/).reply(200)
19+
nock(/.*/).persist().put(/.*/).reply(200)
20+
21+
const event = createTestEvent({
22+
properties: eventData
23+
})
24+
25+
const responses = await testDestination.testAction(actionSlug, {
26+
event: event,
27+
mapping: event.properties,
28+
settings: { api_key: TEST_API_KEY },
29+
auth: undefined
30+
})
31+
32+
const request = responses[0].request
33+
const rawBody = await request.text()
34+
35+
try {
36+
const json = JSON.parse(rawBody)
37+
expect(json).toMatchSnapshot()
38+
return
39+
} catch (err) {
40+
expect(rawBody).toMatchSnapshot()
41+
}
42+
43+
expect(request.headers).toMatchSnapshot()
44+
})
45+
46+
it(`${actionSlug} action - all fields`, async () => {
47+
const seedName = `${destinationSlug}#${actionSlug}`
48+
const action = destination.actions[actionSlug]
49+
const [eventData] = generateTestData(seedName, destination, action, false)
50+
51+
nock(/.*/).persist().get(/.*/).reply(200)
52+
nock(/.*/).persist().post(/.*/).reply(200)
53+
nock(/.*/).persist().put(/.*/).reply(200)
54+
55+
const event = createTestEvent({
56+
properties: eventData
57+
})
58+
59+
const responses = await testDestination.testAction(actionSlug, {
60+
event: event,
61+
mapping: event.properties,
62+
settings: { api_key: TEST_API_KEY },
63+
auth: undefined
64+
})
65+
66+
const request = responses[0].request
67+
const rawBody = await request.text()
68+
69+
try {
70+
const json = JSON.parse(rawBody)
71+
expect(json).toMatchSnapshot()
72+
return
73+
} catch (err) {
74+
expect(rawBody).toMatchSnapshot()
75+
}
76+
})
77+
}
78+
})

packages/destination-actions/src/destinations/ortto-audiences/generated-types.ts

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import type { AudienceDestinationDefinition } from '@segment/actions-core'
2+
import type { Settings, AudienceSettings } from './generated-types'
3+
import OrttoClient from './ortto-client'
4+
5+
import syncAudience from './syncAudience'
6+
7+
const destination: AudienceDestinationDefinition<Settings, AudienceSettings> = {
8+
name: 'Ortto (Audiences)',
9+
slug: 'actions-ortto-audiences',
10+
mode: 'cloud',
11+
12+
authentication: {
13+
scheme: 'custom',
14+
fields: {
15+
api_key: {
16+
label: 'API Key',
17+
description: 'Ortto API key',
18+
type: 'password',
19+
required: true
20+
}
21+
},
22+
testAuthentication: async (request, { settings }) => {
23+
const client: OrttoClient = new OrttoClient(request)
24+
return await client.testAuth(settings)
25+
}
26+
},
27+
extendRequest({ settings }) {
28+
if (process?.env?.ORTTO_API_KEY) {
29+
settings.api_key = process?.env?.ORTTO_API_KEY
30+
}
31+
return {
32+
headers: {
33+
Authorization: `Bearer ${settings.api_key}`
34+
}
35+
}
36+
},
37+
audienceFields: {
38+
audienceName: {
39+
label: 'Audience Name',
40+
description: 'The name of the Audience in Ortto',
41+
type: 'string',
42+
required: true
43+
}
44+
},
45+
audienceConfig: {
46+
mode: {
47+
type: 'synced',
48+
full_audience_sync: false
49+
},
50+
createAudience: async (request, { settings, audienceName }) => {
51+
const client: OrttoClient = new OrttoClient(request)
52+
const audience = await client.createAudience(settings, audienceName)
53+
return {
54+
// Segment will save this externalId for subsequent calls
55+
externalId: audience.id
56+
}
57+
},
58+
getAudience: async (request, { settings, externalId }) => {
59+
const client: OrttoClient = new OrttoClient(request)
60+
const audience = await client.getAudience(settings, externalId)
61+
return {
62+
externalId: audience.id
63+
}
64+
}
65+
},
66+
actions: {
67+
syncAudience
68+
}
69+
}
70+
71+
export default destination

0 commit comments

Comments
 (0)