Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
3 changes: 2 additions & 1 deletion packages/core/src/flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
export const FLAGS = {
ACTIONS_GOOGLE_EC_AUDIENCE_MEMBERSHIP: 'actions-google-ec-audience-membership',
ACTIONS_BRAZE_COHORTS_AUDIENCE_MEMBERSHIP: 'actions-braze-cohorts-audience-membership',
ACTIONS_LINKEDIN_AUDIENCES_AUDIENCE_MEMBERSHIP: 'actions-linkedin-audiences-audience-membership'
ACTIONS_LINKEDIN_AUDIENCES_AUDIENCE_MEMBERSHIP: 'actions-linkedin-audiences-audience-membership',
ACTIONS_TIKTOK_AUDIENCES_AUDIENCE_MEMBERSHIP: 'actions-tiktok-audiences-audience-membership'
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ export function getIDSchema(payload: GenericPayload): string[] {
return id_schema
}

const isHashedInformation = (information: string): boolean => new RegExp(/[0-9abcdef]{64}/gi).test(information)
export const isHashedInformation = (information: string): boolean => new RegExp(/[0-9abcdef]{64}/gi).test(information)
Comment thread
joe-ayoub-segment marked this conversation as resolved.

const hash = (value: string): string => {
export const hash = (value: string): string => {
return processHashing(value, 'sha256', 'hex')
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import addToAudience from './addToAudience'

import removeFromAudience from './removeFromAudience'

import syncAudience from './syncAudience'

const destination: AudienceDestinationDefinition<Settings, AudienceSettings> = {
name: 'TikTok Audiences',
slug: 'actions-tiktok-audiences',
Expand Down Expand Up @@ -160,6 +162,7 @@ const destination: AudienceDestinationDefinition<Settings, AudienceSettings> = {
}
},
actions: {
syncAudience,
addToAudience,
removeFromAudience,
addUser,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
import nock from 'nock'
import { createTestEvent, createTestIntegration } from '@segment/actions-core'
import Destination from '../../index'
import { BASE_URL } from '../../constants'
import { TIKTOK_AUDIENCES_API_VERSION } from '../../versioning-info'

const testDestination = createTestIntegration(Destination)

interface AuthTokens {
accessToken: string
refreshToken: string
}

const auth: AuthTokens = {
accessToken: 'test',
refreshToken: 'test'
}

const EXTERNAL_AUDIENCE_ID = '12345'
const ADVERTISER_ID = '123' // References audienceSettings.advertiserId
const ADVERTISING_ID = '4242' // References device.advertisingId
const ID_TYPE = 'EMAIL_SHA256' // References audienceSettings.idType

const event = createTestEvent({
event: 'Audience Entered',
type: 'track',
properties: {},
context: {
device: {
advertisingId: ADVERTISING_ID
},
traits: {
email: '[email protected]',
phone: '1234567890'
},
personas: {
audience_settings: {
advertiserId: ADVERTISER_ID,
idType: ID_TYPE
},
external_audience_id: EXTERNAL_AUDIENCE_ID
}
}
})

const updateUsersRequestBody = {
id_schema: ['EMAIL_SHA256', 'PHONE_SHA256', 'IDFA_SHA256'],
advertiser_ids: [ADVERTISER_ID],
action: 'add',
batch_data: [
[
{
id: '584c4423c421df49955759498a71495aba49b8780eb9387dff333b6f0982c777',
audience_ids: [EXTERNAL_AUDIENCE_ID]
},
{
id: 'c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646',
audience_ids: [EXTERNAL_AUDIENCE_ID]
},
{
id: '0315b4020af3eccab7706679580ac87a710d82970733b8719e70af9b57e7b9e6',
audience_ids: [EXTERNAL_AUDIENCE_ID]
}
]
]
}

describe('TiktokAudiences.addToAudience', () => {
it('should succeed if audience id is valid', async () => {
nock(`${BASE_URL}${TIKTOK_AUDIENCES_API_VERSION}`).post('/segment/mapping/', updateUsersRequestBody).reply(200)

const r = await testDestination.testAction('addToAudience', {
auth,
Comment thread
joe-ayoub-segment marked this conversation as resolved.
Outdated
event,
settings: {},
useDefaultMappings: true,
Comment thread
joe-ayoub-segment marked this conversation as resolved.
Outdated
mapping: {
send_advertising_id: true
}
})

expect(r[0].status).toEqual(200)
expect(r[0].options.body).toMatchInlineSnapshot(
`"{\\"advertiser_ids\\":[\\"123\\"],\\"action\\":\\"add\\",\\"id_schema\\":[\\"EMAIL_SHA256\\",\\"PHONE_SHA256\\",\\"IDFA_SHA256\\"],\\"batch_data\\":[[{\\"id\\":\\"584c4423c421df49955759498a71495aba49b8780eb9387dff333b6f0982c777\\",\\"audience_ids\\":[\\"12345\\"]},{\\"id\\":\\"c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646\\",\\"audience_ids\\":[\\"12345\\"]},{\\"id\\":\\"0315b4020af3eccab7706679580ac87a710d82970733b8719e70af9b57e7b9e6\\",\\"audience_ids\\":[\\"12345\\"]}]]}"`
)
})

it('should normalize and hash emails correctly', async () => {
nock(`${BASE_URL}${TIKTOK_AUDIENCES_API_VERSION}`)
.post('/segment/mapping/', {
advertiser_ids: ['123'],
action: 'add',
id_schema: ['EMAIL_SHA256'],
batch_data: [
[
{
id: '584c4423c421df49955759498a71495aba49b8780eb9387dff333b6f0982c777',
audience_ids: [EXTERNAL_AUDIENCE_ID]
}
]
]
})
.reply(200)

const responses = await testDestination.testAction('addToAudience', {
event,
settings: {
advertiser_ids: ['123']
},
useDefaultMappings: true,
auth,
mapping: {
send_advertising_id: false,
send_phone: false
}
})

expect(responses[0].options.body).toMatchInlineSnapshot(
`"{\\"advertiser_ids\\":[\\"123\\"],\\"action\\":\\"add\\",\\"id_schema\\":[\\"EMAIL_SHA256\\"],\\"batch_data\\":[[{\\"id\\":\\"584c4423c421df49955759498a71495aba49b8780eb9387dff333b6f0982c777\\",\\"audience_ids\\":[\\"12345\\"]}]]}"`
)
})

it('should normalize and hash phone correctly', async () => {
nock(`${BASE_URL}${TIKTOK_AUDIENCES_API_VERSION}`)
.post('/segment/mapping/', {
advertiser_ids: ['123'],
action: 'add',
id_schema: ['PHONE_SHA256'],
batch_data: [
[
{
id: 'c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646',
audience_ids: [EXTERNAL_AUDIENCE_ID]
}
]
]
})
.reply(200)

const responses = await testDestination.testAction('addToAudience', {
event,
settings: {
advertiser_ids: ['123']
},
useDefaultMappings: true,
auth,
mapping: {
send_advertising_id: false,
send_email: false
}
})

expect(responses[0].options.body).toMatchInlineSnapshot(
`"{\\"advertiser_ids\\":[\\"123\\"],\\"action\\":\\"add\\",\\"id_schema\\":[\\"PHONE_SHA256\\"],\\"batch_data\\":[[{\\"id\\":\\"c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646\\",\\"audience_ids\\":[\\"12345\\"]}]]}"`
)
})

it('should fail if an audience id is invalid', async () => {
const anotherEvent = createTestEvent({
event: 'Audience Entered',
type: 'track',
properties: {
audience_key: 'personas_test_audience'
},
context: {
device: {
advertisingId: ADVERTISING_ID
},
traits: {
email: '[email protected]',
phone: '1234567890'
},
personas: {
audience_settings: {
advertiserId: ADVERTISER_ID,
idType: ID_TYPE
},
external_audience_id: 'THIS_ISNT_REAL'
}
}
})

nock(`${BASE_URL}${TIKTOK_AUDIENCES_API_VERSION}/segment/mapping/`)
.post(/.*/, {
id_schema: ['EMAIL_SHA256', 'PHONE_SHA256', 'IDFA_SHA256'],
advertiser_ids: [ADVERTISER_ID],
action: 'add',
batch_data: [
[
{
id: '584c4423c421df49955759498a71495aba49b8780eb9387dff333b6f0982c777',
audience_ids: ['THIS_ISNT_REAL']
},
{
id: 'c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646',
audience_ids: ['THIS_ISNT_REAL']
},
{
id: '0315b4020af3eccab7706679580ac87a710d82970733b8719e70af9b57e7b9e6',
audience_ids: ['THIS_ISNT_REAL']
}
]
]
})
.reply(400)

const r = await testDestination.testAction('addToAudience', {
event: anotherEvent,
settings: {
advertiser_ids: ['123']
},
useDefaultMappings: true,
auth,
mapping: {}
})

expect(r[0].status).toEqual(400)
})

it('should fail if all the send fields are false', async () => {
nock(`${BASE_URL}${TIKTOK_AUDIENCES_API_VERSION}/segment/mapping/`).post(/.*/, updateUsersRequestBody).reply(200)

await expect(
testDestination.testAction('addToAudience', {
event,
settings: {
advertiser_ids: ['123']
},
useDefaultMappings: true,
auth,
mapping: {
selected_advertiser_id: '123',
audience_id: '123456',
send_email: false,
send_advertising_id: false,
send_phone: false
}
})
).rejects.toThrow('At least one of `Send Email`, `Send Phone` or `Send Advertising ID` must be set to `true`.')
})
it('should fail if email and/or advertising_id is not in the payload', async () => {
nock(`${BASE_URL}${TIKTOK_AUDIENCES_API_VERSION}/segment/mapping/`).post(/.*/, updateUsersRequestBody).reply(400)

delete event?.context?.device
delete event?.context?.traits

await expect(
testDestination.testAction('addToAudience', {
event,
settings: {
advertiser_ids: ['123']
},
useDefaultMappings: true,
auth,
mapping: {
send_email: true,
send_advertising_id: true
}
})
).rejects.toThrowError('At least one of Email Id or Advertising ID must be provided.')
})
})
Loading
Loading