Skip to content

Introduce 'Amazon Conversions Api' Destination #2941

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Testing snapshot for amazon-conversions-api destination: trackConversion action - all fields 1`] = `
Object {
"eventData": Array [
Object {
"clientDedupeId": "#A156k^d",
"consent": Object {
"amazonConsent": Object {},
"geo": Object {},
"gpp": "#A156k^d",
"tcf": "#A156k^d",
},
"countryCode": "#A156k^d",
"currencyCode": "CAD",
"customAttributes": Array [
Object {
"dataType": "STRING",
"name": "#A156k^d",
"value": "#A156k^d",
},
],
"dataProcessingOptions": Array [
"LIMITED_DATA_USE",
],
"eventActionSource": "ANDROID",
"eventType": "CHECKOUT",
"matchKeys": Array [
Object {
"type": "EMAIL",
"values": Array [
"e482c2ed6964c49a6ab0d8faae0df960efd587bbf35189b037d89a4ebd0aed68",
],
},
Object {
"type": "PHONE",
"values": Array [
"0fecf9247f3ddc84db8a804fa3065c013baf6b7c2458c2ba2bf56c2e1d42ddd4",
],
},
Object {
"type": "FIRST_NAME",
"values": Array [
"c6843db7a418d6520c030983486fa17bc1edb05f9b89ac1ea98ba94db044027d",
],
},
Object {
"type": "LAST_NAME",
"values": Array [
"c6843db7a418d6520c030983486fa17bc1edb05f9b89ac1ea98ba94db044027d",
],
},
Object {
"type": "ADDRESS",
"values": Array [
"c6843db7a418d6520c030983486fa17bc1edb05f9b89ac1ea98ba94db044027d",
],
},
Object {
"type": "CITY",
"values": Array [
"c6843db7a418d6520c030983486fa17bc1edb05f9b89ac1ea98ba94db044027d",
],
},
Object {
"type": "STATE",
"values": Array [
"c6843db7a418d6520c030983486fa17bc1edb05f9b89ac1ea98ba94db044027d",
],
},
Object {
"type": "POSTAL",
"values": Array [
"f16c098ecf8933107920a826a9f24e837f01a462fb8a35b6d7de827a3c711778",
],
},
Object {
"type": "MAID",
"values": Array [
"#A156k^d",
],
},
Object {
"type": "RAMP_ID",
"values": Array [
"#A156k^d",
],
},
Object {
"type": "MATCH_ID",
"values": Array [
"#A156k^d",
],
},
],
"name": "#A156k^d",
"timestamp": "#A156k^d",
"unitsSold": -5441374736351232,
"value": -54413747363512.32,
},
],
"ingestionMethod": "SERVER_TO_SERVER",
}
`;

exports[`Testing snapshot for amazon-conversions-api destination: trackConversion action - required fields 1`] = `
Object {
"eventData": Array [
Object {
"consent": Object {},
"countryCode": "#A156k^d",
"eventActionSource": "ANDROID",
"eventType": "CHECKOUT",
"matchKeys": Array [
Object {
"type": "MAID",
"values": Array [
"#A156k^d",
],
},
],
"name": "#A156k^d",
"timestamp": "#A156k^d",
},
],
"ingestionMethod": "SERVER_TO_SERVER",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Basic test to confirm destination structure
import Destination from '../index'
import type { DestinationDefinition } from '@segment/actions-core'

describe('Amazon Conversions API Destination', () => {
it('should be properly configured', () => {
// Test destination structure
expect(Destination).toHaveProperty('name', 'Amazon Conversions Api')
expect(Destination).toHaveProperty('slug', 'amazon-conversions-api')
expect(Destination).toHaveProperty('mode', 'cloud')

// Test authentication exists
expect(Destination).toHaveProperty('authentication')
expect(Destination.authentication).toHaveProperty('scheme', 'oauth2')

// Test actions exist
expect(Destination).toHaveProperty('actions')
expect(Destination.actions).toHaveProperty('trackConversion')
})

it('should have trackConversion action', () => {
expect(typeof Destination.actions.trackConversion).toBe('object')
expect(Destination.actions.trackConversion).toHaveProperty('title', 'Track Conversion')
expect(Destination.actions.trackConversion).toHaveProperty('perform')
expect(typeof Destination.actions.trackConversion.perform).toBe('function')
})

describe('Presets', () => {
it('should have presets defined', () => {
expect(Destination).toHaveProperty('presets')
const presets = (Destination as DestinationDefinition<any>).presets
expect(Array.isArray(presets)).toBe(true)
expect(presets?.length).toBeGreaterThan(0)
})

it('should have properly configured presets', () => {
// Get presets from destination
const presets = (Destination as DestinationDefinition<any>).presets || []

// Check some key presets exist
const addToCartPreset = presets.find(p => p.name === 'Add to Shopping Cart')
const pageViewPreset = presets.find(p => p.name === 'Page View')
const signUpPreset = presets.find(p => p.name === 'Sign Up')

expect(addToCartPreset).toBeDefined()
expect(pageViewPreset).toBeDefined()
expect(signUpPreset).toBeDefined()

// Check preset configurations
expect(addToCartPreset?.partnerAction).toBe('trackConversion')
expect(addToCartPreset?.mapping?.eventType).toBe('ADD_TO_SHOPPING_CART')
expect((addToCartPreset as any)?.subscribe).toBe('type = "track" AND event = "Product Added"')

expect(pageViewPreset?.partnerAction).toBe('trackConversion')
expect(pageViewPreset?.mapping?.eventType).toBe('PAGE_VIEW')
expect((pageViewPreset as any)?.subscribe).toBe('type = "page"')

expect(signUpPreset?.partnerAction).toBe('trackConversion')
expect(signUpPreset?.mapping?.eventType).toBe('SIGN_UP')
expect((signUpPreset as any)?.subscribe).toBe('type = "track" AND event = "Signed Up"')
})

it('should have presets for all supported event types', () => {
const presets = (Destination as DestinationDefinition<any>).presets || []

// Get all event types from the presets
const presetEventTypes = presets.map(p => p.mapping?.eventType)

// Check that all expected Amazon event types are covered
expect(presetEventTypes).toContain('ADD_TO_SHOPPING_CART')
expect(presetEventTypes).toContain('APPLICATION')
expect(presetEventTypes).toContain('CHECKOUT')
expect(presetEventTypes).toContain('CONTACT')
expect(presetEventTypes).toContain('LEAD')
expect(presetEventTypes).toContain('OFF_AMAZON_PURCHASES')
expect(presetEventTypes).toContain('MOBILE_APP_FIRST_START')
expect(presetEventTypes).toContain('PAGE_VIEW')
expect(presetEventTypes).toContain('SEARCH')
expect(presetEventTypes).toContain('SIGN_UP')
expect(presetEventTypes).toContain('SUBSCRIBE')
expect(presetEventTypes).toContain('OTHER')
})

it('should map Segment events to the correct Amazon event types', () => {
const presets = (Destination as DestinationDefinition<any>).presets || []

const eventMapping = {
'Product Added': 'ADD_TO_SHOPPING_CART',
'Application Submitted': 'APPLICATION',
'Checkout': 'CHECKOUT',
'Callback Started': 'CONTACT',
'Generate Lead': 'LEAD',
'Purchase': 'OFF_AMAZON_PURCHASES',
'Launch Application': 'MOBILE_APP_FIRST_START',
'page': 'PAGE_VIEW', // For type="page"
'Products Searched': 'SEARCH',
'Signed Up': 'SIGN_UP',
'Subscription Created': 'SUBSCRIBE',
'Other': 'OTHER'
}

// Check each mapping has a preset
for (const [segmentEvent, amazonEvent] of Object.entries(eventMapping)) {
let preset

if (segmentEvent === 'page') {
// Special case for page type
preset = presets.find(p => (p as any)?.subscribe === 'type = "page"')
} else {
preset = presets.find(p => (p as any)?.subscribe?.includes(`event = "${segmentEvent}"`))
}

expect(preset).toBeDefined()
expect(preset?.mapping?.eventType).toBe(amazonEvent)
}
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { createTestEvent, createTestIntegration } from '@segment/actions-core'
import { generateTestData } from '../../../lib/test-data'
import destination from '../index'
import nock from 'nock'

const testDestination = createTestIntegration(destination)
const destinationSlug = 'amazon-conversions-api'

describe(`Testing snapshot for ${destinationSlug} destination:`, () => {
for (const actionSlug in destination.actions) {
it(`${actionSlug} action - required fields`, async () => {
const seedName = `${destinationSlug}#${actionSlug}`
const action = destination.actions[actionSlug]
let [eventData, settingsData] = generateTestData(seedName, destination, action, true)

Check failure on line 14 in packages/destination-actions/src/destinations/amazon-conversions-api/__tests__/snapshot.test.ts

View workflow job for this annotation

GitHub Actions / Lint (22.x)

'eventData' is never reassigned. Use 'const' instead

// Ensure settingsData has required region field with proper URL
settingsData = {
...settingsData,
region: 'https://advertising-api.amazon.com',
advertiserId: 'test-advertiser-id',
profileId: 'test-profile-id'
}

// Mock specific Amazon API requests with proper URL
nock('https://advertising-api.amazon.com')
.persist()
.post('/events/v1')
.reply(207, {
error: [],
success: [
{
index: 1,
message: null
}
]
})

const event = createTestEvent({
properties: eventData
})

// Make sure enable_batching is included for trackConversion action (required field)
let mapping = event.properties
if (actionSlug === 'trackConversion') {
mapping = {
...event.properties,
enable_batching: true
}
}

const responses = await testDestination.testAction(actionSlug, {
event: event,
mapping: mapping,
settings: settingsData,
auth: undefined
})

const request = responses[0].request
const rawBody = await request.text()

try {
const json = JSON.parse(rawBody)
expect(json).toMatchSnapshot()
return
} catch (err) {
expect(rawBody).toMatchSnapshot()
}

expect(request.headers).toMatchSnapshot()
})

it(`${actionSlug} action - all fields`, async () => {
const seedName = `${destinationSlug}#${actionSlug}`
const action = destination.actions[actionSlug]
let [eventData, settingsData] = generateTestData(seedName, destination, action, false)

Check failure on line 75 in packages/destination-actions/src/destinations/amazon-conversions-api/__tests__/snapshot.test.ts

View workflow job for this annotation

GitHub Actions / Lint (22.x)

'eventData' is never reassigned. Use 'const' instead

// Ensure settingsData has required region field with proper URL
settingsData = {
...settingsData,
region: 'https://advertising-api.amazon.com',
advertiserId: 'test-advertiser-id',
profileId: 'test-profile-id'
}

// Mock specific Amazon API requests with proper URL
nock('https://advertising-api.amazon.com')
.persist()
.post('/events/v1')
.reply(207, {
error: [],
success: [
{
index: 1,
message: null
}
]
})

const event = createTestEvent({
properties: eventData
})

// Make sure enable_batching is included for trackConversion action (required field)
let mapping = event.properties
if (actionSlug === 'trackConversion') {
mapping = {
...event.properties,
enable_batching: true
}
}

const responses = await testDestination.testAction(actionSlug, {
event: event,
mapping: mapping,
settings: settingsData,
auth: undefined
})

const request = responses[0].request
const rawBody = await request.text()

try {
const json = JSON.parse(rawBody)
expect(json).toMatchSnapshot()
return
} catch (err) {
expect(rawBody).toMatchSnapshot()
}
})
}
})
Loading
Loading