diff --git a/CHANGELOG.md b/CHANGELOG.md index 7917057a58..141d06b68b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. See [standa ### Bug Fixes * mixpanel timestamp in ms ([#2990](https://github.com/rudderlabs/rudder-transformer/issues/2990)) ([0da63a4](https://github.com/rudderlabs/rudder-transformer/commit/0da63a4e368e59d46c1eaa4a77d4ac81e686183a)) +* klaviyo: Event validation to be string before operating on it ([#2994](https://github.com/rudderlabs/rudder-transformer/issues/2994)) ([cd68d7c](https://github.com/rudderlabs/rudder-transformer/commit/cd68d7c4068588a325029e0cc523b74c3d3ccb1a)) ## [1.53.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.52.4...v1.53.0) (2024-01-08) diff --git a/src/v0/destinations/klaviyo/transform.js b/src/v0/destinations/klaviyo/transform.js index 9273b6a048..1d0df76835 100644 --- a/src/v0/destinations/klaviyo/transform.js +++ b/src/v0/destinations/klaviyo/transform.js @@ -36,6 +36,7 @@ const { handleRtTfSingleEventError, flattenJson, isNewStatusCodesAccepted, + validateEventName, } = require('../../util'); const { JSON_MIME_TYPE, HTTP_STATUS_CODES } = require('../../util/constant'); @@ -156,7 +157,8 @@ const trackRequestHandler = (message, category, destination) => { const payload = {}; const { privateApiKey, flattenProperties } = destination.Config; let event = get(message, 'event'); - event = event ? event.trim().toLowerCase() : event; + validateEventName(event); + event = event.trim().toLowerCase(); let attributes = {}; if (ecomEvents.includes(event) && message.properties) { const eventName = eventNameMapping[event]; diff --git a/test/integrations/destinations/klaviyo/network.ts b/test/integrations/destinations/klaviyo/network.ts index aa788a60da..d76d235c6f 100644 --- a/test/integrations/destinations/klaviyo/network.ts +++ b/test/integrations/destinations/klaviyo/network.ts @@ -1,75 +1,73 @@ export const networkCallsData = [ - { - httpReq: { - url: 'https://a.klaviyo.com/api/v2/list/XUepkK/subscribe', - method: 'GET', - }, - httpRes: { - status: 200 - }, + { + httpReq: { + url: 'https://a.klaviyo.com/api/v2/list/XUepkK/subscribe', + method: 'GET', }, - { - httpReq: { - url: 'https://a.klaviyo.com/api/v2/list/XUepkK/members', - method: 'GET', - }, - httpRes: { - status: 200 - }, + httpRes: { + status: 200, }, - { - httpReq: { - url: 'https://a.klaviyo.com/api/profiles', - method: 'GET', - data: { - attributes: { - email: "test3@rudderstack.com" - } - } - }, - httpRes: { - status: 409, - data: { - } - }, + }, + { + httpReq: { + url: 'https://a.klaviyo.com/api/v2/list/XUepkK/members', + method: 'GET', }, - { - httpReq: { - url: 'https://a.klaviyo.com/api/profiles', - method: 'GET', - }, - httpRes: { - status: 201, - data: { - data: { - id: '01GW3PHVY0MTCDGS0A1612HARX', - attributes: {} - }, - } - }, + httpRes: { + status: 200, }, - { - httpReq: { - url: 'https://a.klaviyo.com/api/profiles', - method: 'POST', - headers: { Authorization: 'Klaviyo-API-Key dummyPrivateApiKeyforfailure' } - }, - httpRes: { + }, + { + httpReq: { + url: 'https://a.klaviyo.com/api/profiles', + method: 'GET', + data: { + attributes: { + email: 'test3@rudderstack.com', }, + }, + }, + httpRes: { + status: 409, + data: {}, }, - { - httpReq: { - url: 'https://a.klaviyo.com/api/profiles', - method: 'POST', + }, + { + httpReq: { + url: 'https://a.klaviyo.com/api/profiles', + method: 'GET', + }, + httpRes: { + status: 201, + data: { + data: { + id: '01GW3PHVY0MTCDGS0A1612HARX', + attributes: {}, }, - httpRes: { - status: 201, - data: { - data: { - id: '01GW3PHVY0MTCDGS0A1612HARX', - attributes: {} - }, - } + }, + }, + }, + { + httpReq: { + url: 'https://a.klaviyo.com/api/profiles', + method: 'POST', + headers: { Authorization: 'Klaviyo-API-Key dummyPrivateApiKeyforfailure' }, + }, + httpRes: {}, + }, + { + httpReq: { + url: 'https://a.klaviyo.com/api/profiles', + method: 'POST', + }, + httpRes: { + status: 201, + data: { + data: { + id: '01GW3PHVY0MTCDGS0A1612HARX', + attributes: {}, }, - } + }, + }, + }, ]; diff --git a/test/integrations/destinations/klaviyo/processor/data.ts b/test/integrations/destinations/klaviyo/processor/data.ts index 2025957716..cd05ded315 100644 --- a/test/integrations/destinations/klaviyo/processor/data.ts +++ b/test/integrations/destinations/klaviyo/processor/data.ts @@ -1491,6 +1491,115 @@ export const data = [ } } }, + { + "name": "klaviyo", + "description": "Track event call -> Invalid event i.e. sent as non-string", + "feature": "processor", + "module": "destination", + "version": "v0", + "input": { + "request": { + "body": [ + { + "destination": { + "Config": { + "publicApiKey": "dummyPublicApiKey", + "privateApiKey": "dummyPrivateApiKey" + } + }, + "message": { + "type": "track", + "event": { "name": "TestEven002" }, + "sentAt": "2021-01-25T16:12:02.048Z", + "userId": "sajal12", + "channel": "mobile", + "context": { + "os": { + "name": "Android", + "version": "10" + }, + "app": { + "name": "KlaviyoTest", + "build": "1", + "version": "1.0", + "namespace": "com.rudderstack.android.rudderstack.sampleAndroidApp" + }, + "device": { + "id": "9c6bd77ea9da3e68", + "name": "raphaelin", + "type": "android", + "model": "Redmi K20 Pro", + "manufacturer": "Xiaomi" + }, + "locale": "en-IN", + "screen": { + "width": 1080, + "height": 2210, + "density": 440 + }, + "traits": { + "id": "user@1", + "age": "22", + "name": "Test", + "email": "test@rudderstack.com", + "phone": "9112340375", + "anonymousId": "9c6bd77ea9da3e68", + "description": "Sample description" + }, + "library": { + "name": "com.rudderstack.android.sdk.core", + "version": "1.0.2" + }, + "network": { + "wifi": true, + "carrier": "airtel", + "cellular": true, + "bluetooth": false + }, + "timezone": "Asia/Kolkata", + "userAgent": "Dalvik/2.1.0 (Linux; U; Android 10; Redmi K20 Pro MIUI/V12.0.4.0.QFKINXM)" + }, + "rudderId": "b7b24f86-f7bf-46d8-b2b4-ccafc080239c", + "messageId": "1611588776408-ee5a3212-fbf9-4cbb-bbad-3ed0f7c6a2ce", + "properties": { + "PreviouslyVicePresident": true, + "YearElected": 1801, + "VicePresidents": [ + "Aaron Burr", + "George Clinton" + ], + "revenue": 3000 + }, + "anonymousId": "9c6bd77ea9da3e68", + "integrations": { + "All": true + }, + "originalTimestamp": "2021-01-25T15:32:56.409Z" + } + } + ] + } + }, + "output": { + "response": { + "status": 200, + "body": [ + { + "error": "Event is a required field and should be a string", + "statTags": { + "destType": "KLAVIYO", + "errorCategory": "dataValidation", + "errorType": "instrumentation", + "feature": "processor", + "implementation": "native", + "module": "destination", + }, + "statusCode": 400 + } + ] + } + } + }, { "name": "klaviyo", "description": "Track event call, with make email or phone as primary identifier toggle on",