Skip to content

Commit 3fefc02

Browse files
Innovative-GauravKocharGaurav Kochar
andauthored
STRATCONN-4169 | Events to Klaviyo destination is failing for delivery (#2407)
* STRATCONN-4169 | Events to Klaviyo destination is failing for delivery * used dayjs library to convert the timestamp to ISO String * Updated unit test case --------- Co-authored-by: Gaurav Kochar <[email protected]>
1 parent 504702a commit 3fefc02

File tree

6 files changed

+233
-4
lines changed

6 files changed

+233
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Order Completed should not pass time property in API when it is not mapped 1`] = `"{\\"data\\":{\\"type\\":\\"event\\",\\"attributes\\":{\\"properties\\":{\\"key\\":\\"value\\"},\\"value\\":10,\\"metric\\":{\\"data\\":{\\"type\\":\\"metric\\",\\"attributes\\":{\\"name\\":\\"Order Completed\\"}}},\\"profile\\":{\\"data\\":{\\"type\\":\\"profile\\",\\"attributes\\":{\\"anonymous_id\\":\\"an0nym0u51d\\"}}}}}}"`;
4+
5+
exports[`Order Completed should not throw an error when the time property has more than three digits in the milliseconds and should convert the time to ISO format. 1`] = `"{\\"data\\":{\\"type\\":\\"event\\",\\"attributes\\":{\\"properties\\":{\\"key\\":\\"value\\"},\\"time\\":\\"2024-07-22T20:08:49.891Z\\",\\"value\\":10,\\"metric\\":{\\"data\\":{\\"type\\":\\"metric\\",\\"attributes\\":{\\"name\\":\\"Order Completed\\"}}},\\"profile\\":{\\"data\\":{\\"type\\":\\"profile\\",\\"attributes\\":{\\"anonymous_id\\":\\"an0nym0u51d\\"}}}}}}"`;
6+
7+
exports[`Order Completed should successfully convert the timestamp for the time property to ISO format. 1`] = `"{\\"data\\":{\\"type\\":\\"event\\",\\"attributes\\":{\\"properties\\":{\\"key\\":\\"value\\"},\\"time\\":\\"2024-07-22T20:08:49.890Z\\",\\"value\\":10,\\"metric\\":{\\"data\\":{\\"type\\":\\"metric\\",\\"attributes\\":{\\"name\\":\\"Order Completed\\"}}},\\"profile\\":{\\"data\\":{\\"type\\":\\"profile\\",\\"attributes\\":{\\"anonymous_id\\":\\"an0nym0u51d\\"}}}}}}"`;

packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/index.test.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@ const createRequestBody = (
2323
properties: Record<string, any>,
2424
value: number,
2525
metricName: string,
26-
profile: Record<string, any>
26+
profile: Record<string, any>,
27+
time?: string
2728
) => ({
2829
data: {
2930
type: 'event',
3031
attributes: {
3132
properties,
3233
value,
34+
time,
3335
metric: createMetric(metricName),
3436
profile: {
3537
data: {
@@ -209,4 +211,69 @@ describe('Order Completed', () => {
209211

210212
await expect(testDestination.testAction(`orderCompleted`, { event, mapping, settings })).resolves.not.toThrowError()
211213
})
214+
215+
it('should not throw an error when the time property has more than three digits in the milliseconds and should convert the time to ISO format.', async () => {
216+
const profile = { anonymous_id: 'an0nym0u51d' }
217+
const properties = { key: 'value' }
218+
const metricName = 'Order Completed'
219+
const value = 10
220+
const eventName = 'Order Completed'
221+
const time = '2024-07-22T20:08:49.891Z' // convert the timestamp from '2024-07-22T20:08:49.89191341Z'
222+
const timestamp = '2024-07-22T20:08:49.89191341Z'
223+
const requestBody = createRequestBody(properties, value, metricName, profile, time)
224+
225+
nock(`${API_URL}`).post('/events/', requestBody).reply(200, {})
226+
227+
const event = createTestEvent({
228+
type: 'track',
229+
timestamp
230+
})
231+
232+
const mapping = { profile, metric_name: metricName, properties, value, event_name: eventName, time: timestamp }
233+
const res = await testDestination.testAction('orderCompleted', { event, mapping, settings })
234+
expect(res[0].options.body).toMatchSnapshot()
235+
})
236+
237+
it('should successfully convert the timestamp for the time property to ISO format.', async () => {
238+
const profile = { anonymous_id: 'an0nym0u51d' }
239+
const properties = { key: 'value' }
240+
const metricName = 'Order Completed'
241+
const value = 10
242+
const eventName = 'Order Completed'
243+
const time = '2024-07-22T20:08:49.890Z'
244+
const timestamp = '2024-07-22T20:08:49.89Z'
245+
const requestBody = createRequestBody(properties, value, metricName, profile, time)
246+
247+
nock(`${API_URL}`).post('/events/', requestBody).reply(200, {})
248+
249+
const event = createTestEvent({
250+
type: 'track',
251+
timestamp
252+
})
253+
254+
const mapping = { profile, metric_name: metricName, properties, value, event_name: eventName, time: timestamp }
255+
const res = await testDestination.testAction('orderCompleted', { event, mapping, settings })
256+
expect(res[0].options.body).toMatchSnapshot()
257+
})
258+
it('should not pass time property in API when it is not mapped', async () => {
259+
const profile = { anonymous_id: 'an0nym0u51d' }
260+
const properties = { key: 'value' }
261+
const metricName = 'Order Completed'
262+
const value = 10
263+
const eventName = 'Order Completed'
264+
const timestamp = '2024-07-22T20:08:49.89191341Z'
265+
const requestBody = createRequestBody(properties, value, metricName, profile)
266+
267+
nock(`${API_URL}`).post('/events/', requestBody).reply(200, {})
268+
269+
const event = createTestEvent({
270+
type: 'track',
271+
timestamp
272+
})
273+
274+
const mapping = { profile, metric_name: metricName, properties, value, event_name: eventName }
275+
276+
const res = await testDestination.testAction('orderCompleted', { event, mapping, settings })
277+
expect(res[0].options.body).toMatchSnapshot()
278+
})
212279
})

packages/destination-actions/src/destinations/klaviyo/orderCompleted/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import { API_URL } from '../config'
66
import { EventData } from '../types'
77
import { v4 as uuidv4 } from '@lukeed/uuid'
88
import { validatePhoneNumber } from '../functions'
9+
import dayjs from 'dayjs'
910

1011
const createEventData = (payload: Payload) => ({
1112
data: {
1213
type: 'event',
1314
attributes: {
1415
properties: { ...payload.properties },
15-
time: payload.time,
16+
time: payload.time ? dayjs(payload.time).toISOString() : undefined,
1617
value: payload.value,
1718
unique_id: payload.unique_id,
1819
metric: {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Track Event should not pass time property in API when it is not mapped or defined 1`] = `"{\\"data\\":{\\"type\\":\\"event\\",\\"attributes\\":{\\"properties\\":{\\"key\\":\\"value\\"},\\"value\\":10,\\"unique_id\\":\\"text-example-xyz\\",\\"metric\\":{\\"data\\":{\\"type\\":\\"metric\\",\\"attributes\\":{\\"name\\":\\"event_name\\"}}},\\"profile\\":{\\"data\\":{\\"type\\":\\"profile\\",\\"attributes\\":{\\"anonymous_id\\":\\"an0nym0u51d\\"}}}}}}"`;
4+
5+
exports[`Track Event should not throw an error when the time property has more than three digits in the milliseconds and should convert the time to ISO format. 1`] = `"{\\"data\\":{\\"type\\":\\"event\\",\\"attributes\\":{\\"properties\\":{\\"key\\":\\"value\\"},\\"time\\":\\"2024-09-11T20:08:49.891Z\\",\\"value\\":10,\\"unique_id\\":\\"text-example-xyz\\",\\"metric\\":{\\"data\\":{\\"type\\":\\"metric\\",\\"attributes\\":{\\"name\\":\\"event_name\\"}}},\\"profile\\":{\\"data\\":{\\"type\\":\\"profile\\",\\"attributes\\":{\\"anonymous_id\\":\\"an0nym0u51d\\"}}}}}}"`;

packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/index.test.ts

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ export const settings = {
1212
}
1313

1414
describe('Track Event', () => {
15+
beforeEach(() => {
16+
nock.cleanAll()
17+
jest.resetAllMocks()
18+
})
19+
1520
it('should throw error if no profile identifiers are provided', async () => {
1621
const event = createTestEvent({
1722
type: 'track'
@@ -238,4 +243,148 @@ describe('Track Event', () => {
238243
testDestination.testAction('trackEvent', { event, mapping, settings, useDefaultMappings: true })
239244
).rejects.toThrowError('Internal Server Error')
240245
})
246+
247+
it('should successfully convert the timestamp for the time property to ISO format.', async () => {
248+
const requestBody = {
249+
data: {
250+
type: 'event',
251+
attributes: {
252+
properties: { key: 'value' },
253+
time: '2024-07-22T20:08:49.790Z',
254+
value: 10,
255+
unique_id: 'text-example-xyz',
256+
metric: {
257+
data: {
258+
type: 'metric',
259+
attributes: {
260+
name: 'event_name'
261+
}
262+
}
263+
},
264+
profile: {
265+
data: {
266+
type: 'profile',
267+
attributes: {
268+
anonymous_id: 'an0nym0u51d'
269+
}
270+
}
271+
}
272+
}
273+
}
274+
}
275+
276+
nock(`${API_URL}`).post('/events/', requestBody).reply(200, {})
277+
278+
const event = createTestEvent({
279+
type: 'track',
280+
timestamp: '2024-07-22T20:08:49.79Z'
281+
})
282+
283+
const mapping = {
284+
profile: { anonymous_id: 'an0nym0u51d' },
285+
metric_name: 'event_name',
286+
properties: { key: 'value' },
287+
value: 10,
288+
unique_id: 'text-example-xyz'
289+
}
290+
291+
await expect(
292+
testDestination.testAction('trackEvent', { event, mapping, settings, useDefaultMappings: true })
293+
).resolves.not.toThrowError()
294+
})
295+
it('should not throw an error when the time property has more than three digits in the milliseconds and should convert the time to ISO format.', async () => {
296+
const timestamp = '2024-09-11T20:08:49.8919123123Z'
297+
const requestBody = {
298+
data: {
299+
type: 'event',
300+
attributes: {
301+
properties: { key: 'value' },
302+
time: '2024-09-11T20:08:49.891Z', // convert the timestamp from '2024-07-22T20:08:49.89191341Z'
303+
value: 10,
304+
unique_id: 'text-example-xyz',
305+
metric: {
306+
data: {
307+
type: 'metric',
308+
attributes: {
309+
name: 'event_name'
310+
}
311+
}
312+
},
313+
profile: {
314+
data: {
315+
type: 'profile',
316+
attributes: {
317+
anonymous_id: 'an0nym0u51d'
318+
}
319+
}
320+
}
321+
}
322+
}
323+
}
324+
325+
nock(`${API_URL}`).post('/events/', requestBody).reply(200, {})
326+
327+
const event = createTestEvent({
328+
type: 'track',
329+
timestamp
330+
})
331+
332+
const mapping = {
333+
profile: { anonymous_id: 'an0nym0u51d' },
334+
metric_name: 'event_name',
335+
properties: { key: 'value' },
336+
value: 10,
337+
unique_id: 'text-example-xyz'
338+
}
339+
340+
const res = await testDestination.testAction('trackEvent', { event, mapping, settings, useDefaultMappings: true })
341+
expect(res[0].options.body).toMatchSnapshot()
342+
})
343+
344+
it('should not pass time property in API when it is not mapped or defined', async () => {
345+
const requestBody = {
346+
data: {
347+
type: 'event',
348+
attributes: {
349+
properties: { key: 'value' },
350+
value: 10,
351+
unique_id: 'text-example-xyz',
352+
metric: {
353+
data: {
354+
type: 'metric',
355+
attributes: {
356+
name: 'event_name'
357+
}
358+
}
359+
},
360+
profile: {
361+
data: {
362+
type: 'profile',
363+
attributes: {
364+
anonymous_id: 'an0nym0u51d'
365+
}
366+
}
367+
}
368+
}
369+
}
370+
}
371+
372+
nock(`${API_URL}`).post('/events/', requestBody).reply(200, {})
373+
374+
const event = createTestEvent({
375+
type: 'track',
376+
timestamp: '2024-07-22T20:08:49.79Z'
377+
})
378+
379+
const mapping = {
380+
profile: { anonymous_id: 'an0nym0u51d' },
381+
metric_name: 'event_name',
382+
properties: { key: 'value' },
383+
value: 10,
384+
unique_id: 'text-example-xyz'
385+
}
386+
387+
const res = await testDestination.testAction('trackEvent', { event, mapping, settings })
388+
expect(res[0].options.body).toMatchSnapshot()
389+
})
241390
})

packages/destination-actions/src/destinations/klaviyo/trackEvent/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { Payload } from './generated-types'
55
import { PayloadValidationError } from '@segment/actions-core'
66
import { API_URL } from '../config'
77
import { validatePhoneNumber } from '../functions'
8+
import dayjs from 'dayjs'
89

910
const action: ActionDefinition<Settings, Payload> = {
1011
title: 'Track Event',
@@ -98,13 +99,12 @@ const action: ActionDefinition<Settings, Payload> = {
9899
if (phone_number && !validatePhoneNumber(phone_number)) {
99100
throw new PayloadValidationError(`${phone_number} is not a valid E.164 phone number.`)
100101
}
101-
102102
const eventData = {
103103
data: {
104104
type: 'event',
105105
attributes: {
106106
properties: { ...payload.properties },
107-
time: payload.time,
107+
time: payload?.time ? dayjs(payload.time).toISOString() : undefined,
108108
value: payload.value,
109109
unique_id: payload.unique_id,
110110
metric: {

0 commit comments

Comments
 (0)