From 5f299de8c899e6924760c4537a9213a44d6aaf10 Mon Sep 17 00:00:00 2001 From: Dilip Kola <33080863+koladilip@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:16:50 +0530 Subject: [PATCH 1/6] refactor: code to address sonar issues (#3926) * refactor: code to address sonar issues * refactor: garl record transform --- package-lock.json | 4 +- .../v2/destinations/pinterest_tag/utils.js | 62 +++--- src/v0/destinations/amazon_audience/utils.js | 3 +- .../recordTransform.js | 207 ++++++------------ 4 files changed, 94 insertions(+), 182 deletions(-) diff --git a/package-lock.json b/package-lock.json index 40033e278b..14832566c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10621,7 +10621,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", diff --git a/src/cdk/v2/destinations/pinterest_tag/utils.js b/src/cdk/v2/destinations/pinterest_tag/utils.js index 31a897f133..dbaeea9501 100644 --- a/src/cdk/v2/destinations/pinterest_tag/utils.js +++ b/src/cdk/v2/destinations/pinterest_tag/utils.js @@ -1,8 +1,8 @@ -/* eslint-disable no-param-reassign */ const sha256 = require('sha256'); const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); const { API_VERSION } = require('./config'); +const { CommonUtils } = require('../../../../util/common'); const VALID_ACTION_SOURCES = ['app_android', 'app_ios', 'web', 'offline']; @@ -21,9 +21,15 @@ const ecomEventMaps = [ }, ]; -const USER_NON_ARRAY_PROPERTIES = ['client_user_agent', 'client_ip_address']; +const USER_NON_ARRAY_PROPERTIES = [ + 'client_user_agent', + 'client_ip_address', + 'click_id', + 'partner_id', +]; -const getHashedValue = (key, value) => { +const transformValue = (key, value) => { + const arrayValue = CommonUtils.toArray(value); switch (key) { case 'em': case 'ct': @@ -32,33 +38,18 @@ const getHashedValue = (key, value) => { case 'ln': case 'fn': case 'ge': - value = Array.isArray(value) - ? value.map((val) => val.toString().trim().toLowerCase()) - : value.toString().trim().toLowerCase(); - break; + return arrayValue.map((val) => val.toString().trim().toLowerCase()); case 'ph': - // phone numbers should only contain digits & should not contain leading zeros - value = Array.isArray(value) - ? value.map((val) => val.toString().replace(/\D/g, '').replace(/^0+/, '')) - : value.toString().replace(/\D/g, '').replace(/^0+/, ''); - break; + return arrayValue.map((val) => val.toString().replace(/\D/g, '').replace(/^0+/, '')); case 'zp': - // zip fields should only contain digits - value = Array.isArray(value) - ? value.map((val) => val.toString().trim().replace(/\D/g, '')) - : value.toString().replace(/\D/g, ''); - break; - case 'hashed_maids': - case 'external_id': - case 'db': - // no action needed on value - break; + return arrayValue.map((val) => val.toString().trim().replace(/\D/g, '')); default: - return String(value); + return arrayValue; } - return Array.isArray(value) ? value.map((val) => sha256(val)) : [sha256(value)]; }; +const getHashedValue = (key, value) => transformValue(key, value).map((val) => sha256(val)); + /** * * @param {*} userPayload Payload mapped from user fields @@ -67,10 +58,15 @@ const getHashedValue = (key, value) => { * Ref: https://s.pinimg.com/ct/docs/conversions_api/dist/v3.html */ const processUserPayload = (userPayload) => { - Object.keys(userPayload).forEach((key) => { - userPayload[key] = getHashedValue(key, userPayload[key]); + const newPayload = { ...userPayload }; + Object.keys(newPayload).forEach((key) => { + if (USER_NON_ARRAY_PROPERTIES.includes(key)) { + newPayload[key] = String(newPayload[key]); + } else { + newPayload[key] = getHashedValue(key, newPayload[key]); + } }); - return userPayload; + return newPayload; }; /** @@ -99,11 +95,7 @@ const processHashedUserPayload = (userPayload, message) => { const processedHashedUserPayload = {}; Object.keys(userPayload).forEach((key) => { if (!USER_NON_ARRAY_PROPERTIES.includes(key)) { - if (Array.isArray(userPayload[key])) { - processedHashedUserPayload[key] = [...userPayload[key]]; - } else { - processedHashedUserPayload[key] = [userPayload[key]]; - } + processedHashedUserPayload[key] = CommonUtils.toArray(userPayload[key]); } else { processedHashedUserPayload[key] = userPayload[key]; } @@ -111,10 +103,8 @@ const processHashedUserPayload = (userPayload, message) => { // multiKeyMap will works on only specific values like m, male, MALE, f, F, Female // if hashed data is sent from the user, it is directly set over here const gender = message.traits?.gender || message.context?.traits?.gender; - if (gender && Array.isArray(gender)) { - processedHashedUserPayload.ge = [...gender]; - } else if (gender) { - processedHashedUserPayload.ge = [gender]; + if (gender) { + processedHashedUserPayload.ge = CommonUtils.toArray(gender); } return processedHashedUserPayload; }; diff --git a/src/v0/destinations/amazon_audience/utils.js b/src/v0/destinations/amazon_audience/utils.js index c25f301378..350d071a47 100644 --- a/src/v0/destinations/amazon_audience/utils.js +++ b/src/v0/destinations/amazon_audience/utils.js @@ -21,7 +21,8 @@ const buildResponseWithUsers = (users, action, config, jobIdList, secret) => { if (!secret?.clientId) { throw new OAuthSecretError('OAuth - Client Id not found'); } - const externalId = `Rudderstack_${sha256(`${jobIdList}`)}`; + const jobIdHash = sha256(String(jobIdList)); + const externalId = `Rudderstack_${jobIdHash}`; const response = defaultRequestConfig(); response.endpoint = ''; response.method = defaultPostRequestConfig.requestMethod; diff --git a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js index 5866b66538..c3bf27a75d 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js @@ -1,4 +1,3 @@ -/* eslint-disable no-const-assign */ const lodash = require('lodash'); const { InstrumentationError } = require('@rudderstack/integrations-lib'); const { @@ -19,29 +18,22 @@ const { const { getErrorResponse, createFinalResponse } = require('../../util/recordUtils'); const { offlineDataJobsMapping, consentConfigMap } = require('./config'); -const processRecordEventArray = ( - records, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - operationType, -) => { - let outputPayloads = {}; - // ** only send it if identifier > 0 - - const fieldsArray = []; - const metadata = []; - records.forEach((record) => { - fieldsArray.push(record.message.fields); - metadata.push(record.metadata); - }); +const processRecordEventArray = (records, context, operationType) => { + const { + message, + destination, + accessToken, + developerToken, + audienceId, + typeOfList, + userSchema, + isHashRequired, + userDataConsent, + personalizationConsent, + } = context; + + const fieldsArray = records.map((record) => record.message.fields); + const metadata = records.map((record) => record.metadata); const userIdentifiersList = populateIdentifiersForRecordEvent( fieldsArray, @@ -51,131 +43,60 @@ const processRecordEventArray = ( ); const outputPayload = constructPayload(message, offlineDataJobsMapping); - outputPayload.operations = []; - // breaking the userIdentiFier array in chunks of 20 + const userIdentifierChunks = returnArrayOfSubarrays(userIdentifiersList, 20); - // putting each chunk in different create/remove operations - switch (operationType) { - case 'add': - // for add operation - userIdentifierChunks.forEach((element) => { - const operations = { - create: {}, - }; - operations.create.userIdentifiers = element; - outputPayload.operations.push(operations); - }); - outputPayloads = { ...outputPayloads, create: outputPayload }; - break; - case 'remove': - // for remove operation - userIdentifierChunks.forEach((element) => { - const operations = { - remove: {}, - }; - operations.remove.userIdentifiers = element; - outputPayload.operations.push(operations); - }); - outputPayloads = { ...outputPayloads, remove: outputPayload }; - break; - default: - } + outputPayload.operations = userIdentifierChunks.map((chunk) => ({ + [operationType]: { userIdentifiers: chunk }, + })); - const toSendEvents = []; - Object.values(outputPayloads).forEach((data) => { - const consentObj = populateConsentFromConfig( - { userDataConsent, personalizationConsent }, - consentConfigMap, - ); - toSendEvents.push( - responseBuilder(accessToken, developerToken, data, destination, audienceId, consentObj), - ); - }); + const consentObj = populateConsentFromConfig( + { userDataConsent, personalizationConsent }, + consentConfigMap, + ); - const successResponse = getSuccessRespEvents(toSendEvents, metadata, destination, true); + const toSendEvents = [outputPayload].map((data) => + responseBuilder(accessToken, developerToken, data, destination, audienceId, consentObj), + ); - return successResponse; + return getSuccessRespEvents(toSendEvents, metadata, destination, true); }; -function preparepayload(events, config) { +function preparePayload(events, config) { const { destination, message, metadata } = events[0]; const accessToken = getAccessToken(metadata, 'access_token'); const developerToken = getValueFromMessage(metadata, 'secret.developer_token'); - const { - audienceId, - typeOfList, - isHashRequired, - userSchema, - userDataConsent, - personalizationConsent, - } = config; + + const context = { + message, + destination, + accessToken, + developerToken, + ...config, + }; const groupedRecordsByAction = lodash.groupBy(events, (record) => record.message.action?.toLowerCase(), ); - let insertResponse; - let deleteResponse; - let updateResponse; - - if (groupedRecordsByAction.delete) { - deleteResponse = processRecordEventArray( - groupedRecordsByAction.delete, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - 'remove', - ); - } - - if (groupedRecordsByAction.insert) { - insertResponse = processRecordEventArray( - groupedRecordsByAction.insert, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - 'add', - ); - } - - if (groupedRecordsByAction.update) { - updateResponse = processRecordEventArray( - groupedRecordsByAction.update, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - 'add', - ); - } + const actionResponses = ['delete', 'insert', 'update'].reduce((responses, action) => { + const operationType = action === 'delete' ? 'remove' : 'create'; + if (groupedRecordsByAction[action]) { + return { + ...responses, + [action]: processRecordEventArray(groupedRecordsByAction[action], context, operationType), + }; + } + return responses; + }, {}); const errorResponse = getErrorResponse(groupedRecordsByAction); const finalResponse = createFinalResponse( - deleteResponse, - insertResponse, - updateResponse, + actionResponses.delete, + actionResponses.insert, + actionResponses.update, errorResponse, ); + if (finalResponse.length === 0) { throw new InstrumentationError( 'Missing valid parameters, unable to generate transformed payload', @@ -196,14 +117,16 @@ function processRecordInputsV0(groupedRecordInputs) { personalizationConsent, } = destination.Config; - return preparepayload(groupedRecordInputs, { + const config = { audienceId: getOperationAudienceId(audienceId, message), typeOfList, userSchema, isHashRequired, userDataConsent, personalizationConsent, - }); + }; + + return preparePayload(groupedRecordInputs, config); } function processRecordInputsV1(groupedRecordInputs) { @@ -211,11 +134,7 @@ function processRecordInputsV1(groupedRecordInputs) { const { audienceId, typeOfList, isHashRequired, userDataConsent, personalizationConsent } = connection.config.destination; - const identifiers = message?.identifiers; - let userSchema; - if (identifiers) { - userSchema = Object.keys(identifiers); - } + const userSchema = message?.identifiers ? Object.keys(message.identifiers) : undefined; const events = groupedRecordInputs.map((record) => ({ ...record, @@ -225,23 +144,23 @@ function processRecordInputsV1(groupedRecordInputs) { }, })); - return preparepayload(events, { + const config = { audienceId, typeOfList, userSchema, isHashRequired, userDataConsent, personalizationConsent, - }); + }; + + return preparePayload(events, config); } function processRecordInputs(groupedRecordInputs) { const event = groupedRecordInputs[0]; - // First check for rETL flow and second check for ES flow - if (isEventSentByVDMV1Flow(event) || !isEventSentByVDMV2Flow(event)) { - return processRecordInputsV0(groupedRecordInputs); - } - return processRecordInputsV1(groupedRecordInputs); + return isEventSentByVDMV1Flow(event) || !isEventSentByVDMV2Flow(event) + ? processRecordInputsV0(groupedRecordInputs) + : processRecordInputsV1(groupedRecordInputs); } module.exports = { From 325dabe1070b5a2bf3a84b12ce10f19abf40a6a8 Mon Sep 17 00:00:00 2001 From: Sai Kumar Battinoju <88789928+saikumarrs@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:45:08 +0530 Subject: [PATCH 2/6] chore: remove references to legacy consent management fields (#3931) --- src/v0/destinations/braze/braze.util.test.js | 1 - .../data_scenarios/cdk_v2/failure.json | 9 +-- .../data_scenarios/cdk_v2/success.json | 9 +-- .../destination/batch/failure_batch.json | 20 ++---- .../destination/batch/successful_batch.json | 16 ++--- .../proc/batch_input_multiplex.json | 6 +- .../destination/proc/multiplex_failure.json | 3 +- .../proc/multiplex_partial_failure.json | 6 +- .../destination/proc/multiplex_success.json | 3 +- .../destination/router/failure_test.json | 15 ++--- .../destinations/algolia/router/data.ts | 20 ++---- .../destinations/braze/router/data.ts | 7 --- .../destinations/candu/processor/data.ts | 63 +++---------------- .../destinations/candu/router/data.ts | 14 +---- .../destinations/clicksend/commonConfig.ts | 5 -- .../destinations/clicksend/router/data.ts | 5 -- .../destinations/emarsys/deleteUsers/data.ts | 20 ------ .../destinations/emarsys/processor/data.ts | 55 ---------------- .../destinations/emarsys/router/data.ts | 5 -- .../fb_custom_audience/router/data.ts | 4 -- .../fb_custom_audience/router/rETL.ts | 2 - .../destinations/gainsight_px/router/data.ts | 2 +- .../router/data.ts | 7 --- .../destinations/hs/router/data.ts | 60 ------------------ .../processor/configLevelFeaturesTestData.ts | 5 -- .../linkedin_ads/processor/trackTestData.ts | 5 -- .../processor/validationTestData.ts | 5 -- .../destinations/linkedin_ads/router/data.ts | 5 -- .../destinations/rockerbox/processor/data.ts | 28 --------- .../destinations/rockerbox/router/data.ts | 12 ---- .../tune/processor/trackTestData.ts | 2 - .../destinations/tune/router/data.ts | 2 - .../destinations/webhook/processor/data.ts | 4 +- test/integrations/destinations/zoho/common.ts | 25 -------- 34 files changed, 44 insertions(+), 406 deletions(-) diff --git a/src/v0/destinations/braze/braze.util.test.js b/src/v0/destinations/braze/braze.util.test.js index 7d10035233..6fe4dbbb44 100644 --- a/src/v0/destinations/braze/braze.util.test.js +++ b/src/v0/destinations/braze/braze.util.test.js @@ -255,7 +255,6 @@ describe('dedup utility tests', () => { enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'test-rest-api-key', supportDedup: true, trackAnonymousUser: true, diff --git a/test/apitests/data_scenarios/cdk_v2/failure.json b/test/apitests/data_scenarios/cdk_v2/failure.json index 154d24481d..c252761e88 100644 --- a/test/apitests/data_scenarios/cdk_v2/failure.json +++ b/test/apitests/data_scenarios/cdk_v2/failure.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -448,7 +446,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -462,7 +460,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/cdk_v2/success.json b/test/apitests/data_scenarios/cdk_v2/success.json index 88f430dd7c..ce819c3f80 100644 --- a/test/apitests/data_scenarios/cdk_v2/success.json +++ b/test/apitests/data_scenarios/cdk_v2/success.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -448,7 +446,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -462,7 +460,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/batch/failure_batch.json b/test/apitests/data_scenarios/destination/batch/failure_batch.json index 6352ca1a11..80595e44f4 100644 --- a/test/apitests/data_scenarios/destination/batch/failure_batch.json +++ b/test/apitests/data_scenarios/destination/batch/failure_batch.json @@ -221,8 +221,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -257,7 +256,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -576,8 +574,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -612,7 +609,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -933,8 +929,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -969,7 +964,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -1247,8 +1241,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -1283,7 +1276,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -1722,8 +1714,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -1758,7 +1749,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], diff --git a/test/apitests/data_scenarios/destination/batch/successful_batch.json b/test/apitests/data_scenarios/destination/batch/successful_batch.json index 32745f49d5..45ceb1a545 100644 --- a/test/apitests/data_scenarios/destination/batch/successful_batch.json +++ b/test/apitests/data_scenarios/destination/batch/successful_batch.json @@ -221,8 +221,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -257,7 +256,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -578,8 +576,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -614,7 +611,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -935,8 +931,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -971,7 +966,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -1557,8 +1551,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -1593,7 +1586,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], diff --git a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json index 3deb7d4b8b..c24dd08e8d 100644 --- a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json +++ b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_failure.json index 68c7fc3baa..d08949ffb6 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_failure.json @@ -93,7 +93,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -107,7 +107,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json index a2652855d5..78e067e84b 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_success.json b/test/apitests/data_scenarios/destination/proc/multiplex_success.json index ba4d5266f3..2b05a2fad8 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_success.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_success.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/router/failure_test.json b/test/apitests/data_scenarios/destination/router/failure_test.json index 197456f66a..4b341142e9 100644 --- a/test/apitests/data_scenarios/destination/router/failure_test.json +++ b/test/apitests/data_scenarios/destination/router/failure_test.json @@ -157,7 +157,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -171,7 +171,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -395,7 +394,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -409,7 +408,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -633,7 +631,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -647,7 +645,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -1018,7 +1015,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -1032,7 +1029,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -1234,7 +1230,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -1248,7 +1244,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/integrations/destinations/algolia/router/data.ts b/test/integrations/destinations/algolia/router/data.ts index dca899693e..adc7be1596 100644 --- a/test/integrations/destinations/algolia/router/data.ts +++ b/test/integrations/destinations/algolia/router/data.ts @@ -2007,7 +2007,6 @@ export const data = [ { from: 'Order Completed', to: 'conversion' }, { from: 'Product Added', to: 'click' }, ], - oneTrustCookieCategories: [], eventDelivery: false, eventDeliveryTS: 1687213909459, }, @@ -2017,16 +2016,11 @@ export const data = [ DestinationDefinition: { Config: { destConfig: { - defaultConfig: [ - 'apiKey', - 'applicationId', - 'eventTypeSettings', - 'oneTrustCookieCategories', - ], + defaultConfig: ['apiKey', 'applicationId', 'eventTypeSettings'], }, secretKeys: ['apiKey', 'applicationId'], excludeKeys: [], - includeKeys: ['oneTrustCookieCategories'], + includeKeys: [], transformAt: 'router', cdkV2Enabled: true, transformAtV1: 'router', @@ -2146,21 +2140,15 @@ export const data = [ { from: 'Order Completed', to: 'conversion' }, { from: 'Product Added', to: 'click' }, ], - oneTrustCookieCategories: [], }, DestinationDefinition: { Config: { cdkV2Enabled: true, destConfig: { - defaultConfig: [ - 'apiKey', - 'applicationId', - 'eventTypeSettings', - 'oneTrustCookieCategories', - ], + defaultConfig: ['apiKey', 'applicationId', 'eventTypeSettings'], }, excludeKeys: [], - includeKeys: ['oneTrustCookieCategories'], + includeKeys: [], saveDestinationResponse: true, secretKeys: ['apiKey', 'applicationId'], supportedMessageTypes: ['track'], diff --git a/test/integrations/destinations/braze/router/data.ts b/test/integrations/destinations/braze/router/data.ts index b788e22741..8ab04c5d04 100644 --- a/test/integrations/destinations/braze/router/data.ts +++ b/test/integrations/destinations/braze/router/data.ts @@ -432,7 +432,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -502,7 +501,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -572,7 +570,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -626,7 +623,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -680,7 +676,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -833,7 +828,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -869,7 +863,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, diff --git a/test/integrations/destinations/candu/processor/data.ts b/test/integrations/destinations/candu/processor/data.ts index 6e5ae636bd..22bd0b3567 100644 --- a/test/integrations/destinations/candu/processor/data.ts +++ b/test/integrations/destinations/candu/processor/data.ts @@ -21,12 +21,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -182,12 +177,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -347,12 +337,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -478,12 +463,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -619,12 +599,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -757,12 +732,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -894,12 +864,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -1056,12 +1021,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -1221,12 +1181,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], diff --git a/test/integrations/destinations/candu/router/data.ts b/test/integrations/destinations/candu/router/data.ts index e6c7d96a15..02e1caa3e9 100644 --- a/test/integrations/destinations/candu/router/data.ts +++ b/test/integrations/destinations/candu/router/data.ts @@ -20,12 +20,7 @@ export const data = [ Config: { destConfig: { defaultConfig: ['apiKey'] }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -152,12 +147,7 @@ export const data = [ Config: { destConfig: { defaultConfig: ['apiKey'] }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], diff --git a/test/integrations/destinations/clicksend/commonConfig.ts b/test/integrations/destinations/clicksend/commonConfig.ts index 815973b8d9..c5c49e2b92 100644 --- a/test/integrations/destinations/clicksend/commonConfig.ts +++ b/test/integrations/destinations/clicksend/commonConfig.ts @@ -14,11 +14,6 @@ export const destination = { defaultSource: 'php', defaultSenderId: 'abc@gmail.com', defaultSenderPhoneNumber: '+919XXXXXXXX8', - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; diff --git a/test/integrations/destinations/clicksend/router/data.ts b/test/integrations/destinations/clicksend/router/data.ts index 3aa3c0abc4..54018787b0 100644 --- a/test/integrations/destinations/clicksend/router/data.ts +++ b/test/integrations/destinations/clicksend/router/data.ts @@ -18,11 +18,6 @@ const commonDestination = { defaultSenderId: 'abc@gmail.com', defaultSenderPhoneNumber: '+919XXXXXXXX8', defaultSource: 'php', - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, DestinationDefinition: { Config: { diff --git a/test/integrations/destinations/emarsys/deleteUsers/data.ts b/test/integrations/destinations/emarsys/deleteUsers/data.ts index 96b27cad0d..2596e9648c 100644 --- a/test/integrations/destinations/emarsys/deleteUsers/data.ts +++ b/test/integrations/destinations/emarsys/deleteUsers/data.ts @@ -64,11 +64,6 @@ export const data = [ defaultContactList: 'dummy', eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], @@ -113,11 +108,6 @@ export const data = [ defaultContactList: undefined, eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], @@ -161,11 +151,6 @@ export const data = [ defaultContactList: 'dummy', eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], @@ -210,11 +195,6 @@ export const data = [ defaultContactList: 'dummy', eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], diff --git a/test/integrations/destinations/emarsys/processor/data.ts b/test/integrations/destinations/emarsys/processor/data.ts index badd14e7cc..ddb61b83c7 100644 --- a/test/integrations/destinations/emarsys/processor/data.ts +++ b/test/integrations/destinations/emarsys/processor/data.ts @@ -112,11 +112,6 @@ export const data = [ emersysProperty: '3', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -285,11 +280,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -456,11 +446,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -599,11 +584,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -722,11 +702,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -842,11 +817,6 @@ export const data = [ emersysProperty: '2', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -964,11 +934,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1093,11 +1058,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1220,11 +1180,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1346,11 +1301,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1463,11 +1413,6 @@ export const data = [ emersysProperty: '3', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, diff --git a/test/integrations/destinations/emarsys/router/data.ts b/test/integrations/destinations/emarsys/router/data.ts index 5f6dad1077..4a7bcf9332 100644 --- a/test/integrations/destinations/emarsys/router/data.ts +++ b/test/integrations/destinations/emarsys/router/data.ts @@ -29,11 +29,6 @@ const config = { emersysProperty: '2', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }; const commonDestination = { diff --git a/test/integrations/destinations/fb_custom_audience/router/data.ts b/test/integrations/destinations/fb_custom_audience/router/data.ts index cfc24968a8..834b6315f6 100644 --- a/test/integrations/destinations/fb_custom_audience/router/data.ts +++ b/test/integrations/destinations/fb_custom_audience/router/data.ts @@ -611,7 +611,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -687,7 +686,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -795,7 +793,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -951,7 +948,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', diff --git a/test/integrations/destinations/fb_custom_audience/router/rETL.ts b/test/integrations/destinations/fb_custom_audience/router/rETL.ts index 0ba7f8b531..f8d5fc89a0 100644 --- a/test/integrations/destinations/fb_custom_audience/router/rETL.ts +++ b/test/integrations/destinations/fb_custom_audience/router/rETL.ts @@ -8,7 +8,6 @@ const destinationV2: Destination = { disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -167,7 +166,6 @@ export const destinationV1: Destination = { disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', diff --git a/test/integrations/destinations/gainsight_px/router/data.ts b/test/integrations/destinations/gainsight_px/router/data.ts index 1b3d5be875..3a5255f7d2 100644 --- a/test/integrations/destinations/gainsight_px/router/data.ts +++ b/test/integrations/destinations/gainsight_px/router/data.ts @@ -57,7 +57,7 @@ const destination2 = { { from: 'inboxready_signup_date', to: 'inboxready_signup_date' }, { from: 'gpt_setup', to: 'gpt_setup' }, ], - oneTrustCookieCategories: [], + apiKey: 'sample-api-key', eventDelivery: false, eventDeliveryTS: 1624472902670, diff --git a/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts b/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts index 82c8e9b3ff..bcc718485b 100644 --- a/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts @@ -314,7 +314,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -390,7 +389,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -464,7 +462,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -674,7 +671,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -986,7 +982,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -1152,7 +1147,6 @@ export const data = [ defaultUserIdentifier: 'email', hashUserIdentifier: true, validateOnly: false, - oneTrustCookieCategories: [], eventDelivery: false, eventDeliveryTS: 1715104236592, rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', @@ -1265,7 +1259,6 @@ export const data = [ defaultUserIdentifier: 'email', hashUserIdentifier: true, validateOnly: false, - oneTrustCookieCategories: [], eventDelivery: false, eventDeliveryTS: 1715104236592, rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', diff --git a/test/integrations/destinations/hs/router/data.ts b/test/integrations/destinations/hs/router/data.ts index b47d6b7f07..2f0879528b 100644 --- a/test/integrations/destinations/hs/router/data.ts +++ b/test/integrations/destinations/hs/router/data.ts @@ -1988,13 +1988,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2070,13 +2064,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2150,13 +2138,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2231,13 +2213,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2330,13 +2306,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2425,13 +2395,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2511,13 +2475,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2621,13 +2579,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2702,13 +2654,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2801,13 +2747,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, diff --git a/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts b/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts index 287e35e5a7..29ff1f10a8 100644 --- a/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts +++ b/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts @@ -36,11 +36,6 @@ const commonDestination: Destination = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, Enabled: true, }; diff --git a/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts b/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts index f9dfc528db..53272e73bf 100644 --- a/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts +++ b/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts @@ -32,11 +32,6 @@ const commonDestination: Destination = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, Enabled: true, }; diff --git a/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts b/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts index 5cb6ff8cf2..653ad32056 100644 --- a/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts +++ b/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts @@ -36,11 +36,6 @@ const commonDestination: Destination = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, Enabled: true, }; diff --git a/test/integrations/destinations/linkedin_ads/router/data.ts b/test/integrations/destinations/linkedin_ads/router/data.ts index cf7defe6af..16abc0cd06 100644 --- a/test/integrations/destinations/linkedin_ads/router/data.ts +++ b/test/integrations/destinations/linkedin_ads/router/data.ts @@ -20,11 +20,6 @@ const config = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }; const commonDestination = { diff --git a/test/integrations/destinations/rockerbox/processor/data.ts b/test/integrations/destinations/rockerbox/processor/data.ts index 76dd8ef11b..4a64ff09f6 100644 --- a/test/integrations/destinations/rockerbox/processor/data.ts +++ b/test/integrations/destinations/rockerbox/processor/data.ts @@ -85,13 +85,6 @@ export const data = [ clientAuthId: { web: 'test-client-auth-id', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: 'Marketing Sample', - }, - ], - }, customDomain: { web: 'https://cookiedomain.com', }, @@ -206,13 +199,6 @@ export const data = [ clientAuthId: { web: 'test-client-auth-id', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: 'Marketing Sample', - }, - ], - }, customDomain: { web: 'https://cookiedomain.com', }, @@ -339,13 +325,6 @@ export const data = [ clientAuthId: { web: 'test-client-auth-id', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: 'Marketing Sample', - }, - ], - }, customDomain: { web: 'https://cookiedomain.com', }, @@ -501,13 +480,6 @@ export const data = [ clientAuthId: { web: '', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: '', - }, - ], - }, customDomain: { web: '', }, diff --git a/test/integrations/destinations/rockerbox/router/data.ts b/test/integrations/destinations/rockerbox/router/data.ts index af943d7e6b..535b4f7da5 100644 --- a/test/integrations/destinations/rockerbox/router/data.ts +++ b/test/integrations/destinations/rockerbox/router/data.ts @@ -19,9 +19,6 @@ export const data = [ eventsMap: [{ from: 'Product Added', to: 'conv.add_to_cart' }], useNativeSDK: { web: false }, clientAuthId: { web: 'test-client-auth-id' }, - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, customDomain: { web: 'https://cookiedomain.com' }, enableCookieSync: { web: true }, }, @@ -108,9 +105,6 @@ export const data = [ enableCookieSync: { web: true }, eventFilteringOption: 'disable', eventsMap: [{ from: 'Product Added', to: 'conv.add_to_cart' }], - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, useNativeSDK: { web: false }, whitelistedEvents: [{ eventName: '' }], }, @@ -143,9 +137,6 @@ export const data = [ eventsMap: [{ from: 'Product Viewed', to: 'conv.add_to_cart' }], useNativeSDK: { web: false }, clientAuthId: { web: 'test-client-auth-id' }, - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, customDomain: { web: 'https://cookiedomain.com' }, enableCookieSync: { web: true }, }, @@ -232,9 +223,6 @@ export const data = [ enableCookieSync: { web: true }, eventFilteringOption: 'disable', eventsMap: [{ from: 'Product Viewed', to: 'conv.add_to_cart' }], - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, useNativeSDK: { web: false }, whitelistedEvents: [{ eventName: '' }], }, diff --git a/test/integrations/destinations/tune/processor/trackTestData.ts b/test/integrations/destinations/tune/processor/trackTestData.ts index 63178d0e33..d9bfab54e3 100644 --- a/test/integrations/destinations/tune/processor/trackTestData.ts +++ b/test/integrations/destinations/tune/processor/trackTestData.ts @@ -22,8 +22,6 @@ const destination: Destination = { }, subdomain: 'demo', consentManagement: {}, - oneTrustCookieCategories: {}, - ketchConsentPurposes: {}, tuneEvents: [ { eventName: 'Product added', diff --git a/test/integrations/destinations/tune/router/data.ts b/test/integrations/destinations/tune/router/data.ts index f21714d058..4aee5b8967 100644 --- a/test/integrations/destinations/tune/router/data.ts +++ b/test/integrations/destinations/tune/router/data.ts @@ -17,8 +17,6 @@ const destination: Destination = { }, subdomain: 'demo', consentManagement: {}, - oneTrustCookieCategories: {}, - ketchConsentPurposes: {}, tuneEvents: [ { eventName: 'Product added', diff --git a/test/integrations/destinations/webhook/processor/data.ts b/test/integrations/destinations/webhook/processor/data.ts index 92fe8f50d9..7720bc683c 100644 --- a/test/integrations/destinations/webhook/processor/data.ts +++ b/test/integrations/destinations/webhook/processor/data.ts @@ -3285,7 +3285,7 @@ export const data = [ Config: { webhookUrl: 'https://webhook.site/81dc2730-807f-4bbc-8914-5b37d21c8a55', webhookMethod: 'POST', - oneTrustCookieCategories: [], + connectionMode: 'cloud', eventDelivery: false, eventDeliveryTS: 1720497286192, @@ -3294,7 +3294,7 @@ export const data = [ Config: { secretKeys: ['headers.to'], excludeKeys: [], - includeKeys: ['oneTrustCookieCategories', 'consentManagement'], + includeKeys: ['consentManagement'], cdkV2Enabled: true, transformAtV1: 'processor', isAudienceSupported: true, diff --git a/test/integrations/destinations/zoho/common.ts b/test/integrations/destinations/zoho/common.ts index bea4437e6f..1d89dbce6d 100644 --- a/test/integrations/destinations/zoho/common.ts +++ b/test/integrations/destinations/zoho/common.ts @@ -65,11 +65,6 @@ const commonDeletionDestConfig: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -186,11 +181,6 @@ const commonUpsertDestConfig: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -225,11 +215,6 @@ const commonUpsertDestConfig2: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -264,11 +249,6 @@ const commonUpsertDestConfig2CustomModule: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -293,11 +273,6 @@ const commonUpsertDestConfig3: Destination = { module: 'Leads', trigger: 'workflow', addDefaultDuplicateCheck: true, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; From b7692c85adfb4c495ef12e1b31c6764b859ffc67 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Date: Wed, 11 Dec 2024 11:13:38 +0530 Subject: [PATCH 3/6] chore: silent testcase logs in local (#3932) --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e0b17a4f47..cb7379bb0f 100644 --- a/package.json +++ b/package.json @@ -36,11 +36,11 @@ "test": "jest -c jest.config.js --detectOpenHandles", "test:ci": "npm run test -- --coverage --expand --maxWorkers=50%", "test:js": "jest -c jest.default.config.js --detectOpenHandles", - "test:js:silent": "npm run test:js -- --silent", + "test:js:silent": "export LOG_LEVEL=silent && npm run test:js -- --silent", "test:js:ci": "npm run test:js -- --coverage --expand --maxWorkers=50%", "test:ts": "jest -c jest.config.typescript.js --detectOpenHandles", "test:ts:component:generateNwMocks": "npm run test:ts -- component --generate=true", - "test:ts:silent": "npm run test:ts -- --silent", + "test:ts:silent": "export LOG_LEVEL=silent && npm run test:ts -- --silent", "test:ts:ci": "npm run test:ts -- --coverage --expand --maxWorkers=50%", "test:ut:integration": "jest \"user_transformation.integration.test.js\" --detectOpenHandles --notify", "test:ut:integration:silent": "npm run test:ut:integration -- --silent", From d40db6c1e7f71c5ab5fc3a3659d1fc51b6d527fa Mon Sep 17 00:00:00 2001 From: Manish Kumar <144022547+manish339k@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:43:17 +0530 Subject: [PATCH 4/6] fix: handling partial error in a batch for reddit destination (#3935) * fix: handling partial error in a batch for reddit destination * fix: minor change * fix: moving networkHandler to v1 from v0 * fix: sonarcloud code analysis --- .../v2/destinations/reddit/rtWorkflow.yaml | 6 +- src/cdk/v2/destinations/reddit/utils.js | 1 + .../destinations/reddit/networkHandler.js | 65 +++-- .../reddit/dataDelivery/business.ts | 136 ++++++++- .../destinations/reddit/dataDelivery/oauth.ts | 10 +- .../destinations/reddit/network.ts | 107 +++++++ .../destinations/reddit/router/data.ts | 266 ++++++++++++++++++ 7 files changed, 566 insertions(+), 25 deletions(-) rename src/{v0 => v1}/destinations/reddit/networkHandler.js (52%) diff --git a/src/cdk/v2/destinations/reddit/rtWorkflow.yaml b/src/cdk/v2/destinations/reddit/rtWorkflow.yaml index 937ff021f4..fd315b381a 100644 --- a/src/cdk/v2/destinations/reddit/rtWorkflow.yaml +++ b/src/cdk/v2/destinations/reddit/rtWorkflow.yaml @@ -36,7 +36,11 @@ steps: description: Batches the successfulEvents using endpoint condition: $.outputs.successfulEvents.length template: | - let batches = $.batchEvents($.outputs.successfulEvents); + const dontBatchTrueEvents = $.outputs.successfulEvents{.metadata.dontBatch}[]; + const dontBatchFalseEvents = $.outputs.successfulEvents{!.metadata.dontBatch}[]; + const dontBatchTrueEventsChunks = $.chunk(dontBatchTrueEvents, 1); + + let batches = [...$.batchEvents(dontBatchFalseEvents), ...$.batchEventChunks(dontBatchTrueEventsChunks)]; batches@batch.({ "batchedRequest": { "body": { diff --git a/src/cdk/v2/destinations/reddit/utils.js b/src/cdk/v2/destinations/reddit/utils.js index f562d31313..e51a72142a 100644 --- a/src/cdk/v2/destinations/reddit/utils.js +++ b/src/cdk/v2/destinations/reddit/utils.js @@ -81,6 +81,7 @@ const populateRevenueField = (eventType, properties) => { }; module.exports = { batchEvents, + batchEventChunks, populateRevenueField, calculateDefaultRevenue, }; diff --git a/src/v0/destinations/reddit/networkHandler.js b/src/v1/destinations/reddit/networkHandler.js similarity index 52% rename from src/v0/destinations/reddit/networkHandler.js rename to src/v1/destinations/reddit/networkHandler.js index 7c9b32eaa4..608408a7fb 100644 --- a/src/v0/destinations/reddit/networkHandler.js +++ b/src/v1/destinations/reddit/networkHandler.js @@ -1,16 +1,31 @@ const { RetryableError, TAG_NAMES, NetworkError } = require('@rudderstack/integrations-lib'); const isString = require('lodash/isString'); const { prepareProxyRequest, proxyRequest } = require('../../../adapters/network'); -const { isHttpStatusSuccess } = require('../../util/index'); +const { isHttpStatusSuccess } = require('../../../v0/util/index'); const { REFRESH_TOKEN } = require('../../../adapters/networkhandler/authConstants'); const { processAxiosResponse, getDynamicErrorType, } = require('../../../adapters/utils/networkUtils'); +const { TransformerProxyError } = require('../../../v0/util/errorTypes'); -const redditRespHandler = (destResponse) => { - const { status, response } = destResponse; +const populateResponseWithDontBatch = (rudderJobMetadata, response) => { + const errorMessage = JSON.stringify(response); + return rudderJobMetadata.map((metadata) => { + // eslint-disable-next-line no-param-reassign + metadata.dontBatch = true; + return { + statusCode: 500, + metadata, + error: errorMessage, + }; + }); +}; + +const redditRespHandler = (responseParams) => { + const { destinationResponse, rudderJobMetadata } = responseParams; + const { status, response } = destinationResponse; // to handle the case when authorization-token is invalid if (status === 401) { @@ -28,26 +43,41 @@ const redditRespHandler = (destResponse) => { throw new RetryableError( `${errorMessage} during reddit response transformation`, status, - destResponse, + destinationResponse, authErrorCategory, ); } + if (status === 400 && Array.isArray(rudderJobMetadata) && rudderJobMetadata.length > 1) { + // sending back 500 for retry only when events came in a batch + const responseWithDontBatch = populateResponseWithDontBatch(rudderJobMetadata, response); + throw new TransformerProxyError( + `REDDIT: Error transformer proxy during REDDIT response transformation`, + 500, + { + [TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(500), + }, + destinationResponse, + '', + responseWithDontBatch, + ); + } + throw new NetworkError( `${JSON.stringify(response)} during reddit response transformation`, status, { [TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status), }, - destResponse, + destinationResponse, ); }; const responseHandler = (responseParams) => { - const { destinationResponse } = responseParams; + const { destinationResponse, rudderJobMetadata } = responseParams; const message = `Request Processed Successfully`; const { status } = destinationResponse; if (!isHttpStatusSuccess(status)) { // if error, successfully return status, message and original destination response - redditRespHandler(destinationResponse); + redditRespHandler(responseParams); } const { response } = destinationResponse; const errorMessage = @@ -55,20 +85,23 @@ const responseHandler = (responseParams) => { ? response?.invalid_events[0]?.error_message : null; const destResp = errorMessage || destinationResponse; + const responseWithIndividualEvents = rudderJobMetadata.map((metadata) => ({ + statusCode: 200, + metadata, + error: 'success', + })); // Mostly any error will not have a status of 2xx return { status, message, - destResp, + destinationResponse: destResp, + response: responseWithIndividualEvents, }; }; -// eslint-disable-next-line @typescript-eslint/naming-convention -class networkHandler { - constructor() { - this.responseHandler = responseHandler; - this.proxy = proxyRequest; - this.prepareProxy = prepareProxyRequest; - this.processAxiosResponse = processAxiosResponse; - } +function networkHandler() { + this.proxy = proxyRequest; + this.processAxiosResponse = processAxiosResponse; + this.prepareProxy = prepareProxyRequest; + this.responseHandler = responseHandler; } module.exports = { networkHandler }; diff --git a/test/integrations/destinations/reddit/dataDelivery/business.ts b/test/integrations/destinations/reddit/dataDelivery/business.ts index b48004a2ed..cc2feccffa 100644 --- a/test/integrations/destinations/reddit/dataDelivery/business.ts +++ b/test/integrations/destinations/reddit/dataDelivery/business.ts @@ -39,6 +39,71 @@ const validRequestPayload = { ], }; +const validRequestMultipleEventsInPayload = { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + { + event_at: '2018-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + ], +}; + const commonHeaders = { Authorization: 'Bearer dummyAccessToken', 'Content-Type': 'application/json', @@ -73,13 +138,14 @@ export const testScenariosForV0API = [ status: 200, body: { output: { - destResp: { + destinationResponse: { response: { message: 'Successfully processed 1 conversion events.', }, status: 200, }, - message: 'Request Processed Successfully', + message: + '[Generic Response Handler] Request for destination: reddit Processed Successfully', status: 200, }, }, @@ -116,8 +182,15 @@ export const testScenariosForV1API = [ body: { output: { message: 'Request Processed Successfully', + destinationResponse: { + response: { + message: 'Successfully processed 1 conversion events.', + }, + status: 200, + }, response: [ { + error: 'success', metadata: generateMetadata(1), statusCode: 200, }, @@ -180,4 +253,63 @@ export const testScenariosForV1API = [ }, }, }, + { + id: 'reddit_v1_scenario_3', + name: 'reddit', + description: + '[Proxy v1 API] :: Test for a valid request with a partial event failure from the destination', + scenario: 'PartialFailure', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + headers: commonHeaders, + JSON: validRequestMultipleEventsInPayload, + endpoint: + 'https://ads-api.reddit.com/api/v2.0/conversions/events/partial_failed_events', + }, + [generateMetadata(1), generateMetadata(2)], + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + message: 'REDDIT: Error transformer proxy during REDDIT response transformation', + response: [ + { + metadata: { ...generateMetadata(1), dontBatch: true }, + statusCode: 500, + error: + '{"message":"There were 1 invalid conversion events. None were processed.","invalid_events":[{"error_message":"event_at timestamp must be less than 168h0m0s old","event":{"event_at":"2018-10-14T09:03:17.562Z","event_type":{"tracking_type":"Purchase"},"event_metadata":{"item_count":0,"products":[{}],"conversion_id":"c054005afd85a4de74638a776eb8348d44ee875184d7a401830705b7a06e7df1"},"user":{"aaid":"c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a","email":"ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2","external_id":"7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d","ip_address":"e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36","screen_dimensions":{}}}}]}', + }, + { + metadata: { ...generateMetadata(2), dontBatch: true }, + statusCode: 500, + error: + '{"message":"There were 1 invalid conversion events. None were processed.","invalid_events":[{"error_message":"event_at timestamp must be less than 168h0m0s old","event":{"event_at":"2018-10-14T09:03:17.562Z","event_type":{"tracking_type":"Purchase"},"event_metadata":{"item_count":0,"products":[{}],"conversion_id":"c054005afd85a4de74638a776eb8348d44ee875184d7a401830705b7a06e7df1"},"user":{"aaid":"c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a","email":"ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2","external_id":"7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d","ip_address":"e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36","screen_dimensions":{}}}}]}', + }, + ], + statTags: { + destType: 'REDDIT', + destinationId: 'default-destinationId', + errorCategory: 'network', + errorType: 'retryable', + feature: 'dataDelivery', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + status: 500, + }, + }, + }, + }, + }, ]; diff --git a/test/integrations/destinations/reddit/dataDelivery/oauth.ts b/test/integrations/destinations/reddit/dataDelivery/oauth.ts index 8c0d486a7a..e3c5875a06 100644 --- a/test/integrations/destinations/reddit/dataDelivery/oauth.ts +++ b/test/integrations/destinations/reddit/dataDelivery/oauth.ts @@ -84,14 +84,13 @@ export const v0oauthScenarios = [ status: 401, body: { output: { - authErrorCategory: 'REFRESH_TOKEN', destinationResponse: { response: 'Authorization Required', status: 401, }, message: - 'Request failed due to Authorization Required during reddit response transformation', - statTags: expectedStatTags, + '[Generic Response Handler] Request failed for destination reddit with status: 401', + statTags: { ...expectedStatTags, errorType: 'aborted' }, status: 401, }, }, @@ -121,7 +120,6 @@ export const v0oauthScenarios = [ status: 401, body: { output: { - authErrorCategory: 'REFRESH_TOKEN', destinationResponse: { response: { success: false, @@ -134,8 +132,8 @@ export const v0oauthScenarios = [ status: 401, }, message: - 'This server could not verify that you are authorized to access the document you requested. during reddit response transformation', - statTags: expectedStatTags, + '[Generic Response Handler] Request failed for destination reddit with status: 401', + statTags: { ...expectedStatTags, errorType: 'aborted' }, status: 401, }, }, diff --git a/test/integrations/destinations/reddit/network.ts b/test/integrations/destinations/reddit/network.ts index 80c18c00a0..54d7a95b73 100644 --- a/test/integrations/destinations/reddit/network.ts +++ b/test/integrations/destinations/reddit/network.ts @@ -210,4 +210,111 @@ export const networkCallsData = [ statusText: 'Unauthorized', }, }, + { + httpReq: { + url: 'https://ads-api.reddit.com/api/v2.0/conversions/events/partial_failed_events', + data: { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + { + event_at: '2018-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + ], + }, + params: { destination: 'reddit' }, + headers: { + Authorization: 'Bearer dummyAccessToken', + 'Content-Type': 'application/json', + }, + method: 'POST', + }, + httpRes: { + data: { + message: 'There were 1 invalid conversion events. None were processed.', + invalid_events: [ + { + error_message: 'event_at timestamp must be less than 168h0m0s old', + event: { + event_at: '2018-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + event_metadata: { + item_count: 0, + products: [{}], + conversion_id: 'c054005afd85a4de74638a776eb8348d44ee875184d7a401830705b7a06e7df1', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + }, + }, + ], + }, + status: 400, + statusText: 'Bad Request', + }, + }, ]; diff --git a/test/integrations/destinations/reddit/router/data.ts b/test/integrations/destinations/reddit/router/data.ts index b5bed48ae7..f2dd887b84 100644 --- a/test/integrations/destinations/reddit/router/data.ts +++ b/test/integrations/destinations/reddit/router/data.ts @@ -178,6 +178,131 @@ export const data = [ userId: 'u1', }, }, + { + message: { + context: { + traits: { email: 'testone@gmail.com' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + ip: '54.100.200.255', + }, + type: 'track', + session_id: '16733896350494', + originalTimestamp: '2019-10-14T09:03:17.562Z', + anonymousId: '123456', + event: 'Order Completed', + userId: 'testuserId1', + properties: { + checkout_id: '12345', + order_id: '1234', + affiliation: 'Apple Store', + total: 20, + revenue: 15, + shipping: 4, + tax: 1, + discount: 1.5, + coupon: 'ImagePro', + currency: 'USD', + products: [ + { + product_id: '123', + sku: 'G-32', + name: 'Monopoly', + price: 14, + quantity: 1, + category: 'Games', + url: 'https://www.website.com/product/path', + image_url: 'https://www.website.com/product/path.jpg', + }, + { + product_id: '345', + sku: 'F-32', + name: 'UNO', + price: 3.45, + quantity: 2, + category: 'Games', + }, + ], + }, + integrations: { All: true }, + sentAt: '2019-10-14T09:03:22.563Z', + }, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 4, + userId: 'u1', + dontBatch: true, + }, + }, + { + message: { + context: { + traits: { email: 'testone@gmail.com' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + ip: '54.100.200.255', + }, + type: 'track', + originalTimestamp: '2019-10-14T09:03:17.562Z', + anonymousId: '123456', + event: 'Product List Viewed', + userId: 'testuserId1', + properties: { + list_id: 'list1', + category: "What's New", + value: 2600, + value_decimal: 26, + products: [ + { + product_id: '017c6f5d5cf86a4b22432066', + sku: '8732-98', + name: 'Just Another Game', + price: 22, + position: 2, + category: 'Games and Entertainment', + url: 'https://www.myecommercewebsite.com/product', + image_url: 'https://www.myecommercewebsite.com/product/path.jpg', + }, + { + product_id: '89ac6f5d5cf86a4b64eac145', + sku: '1267-01', + name: 'Wrestling Trump Cards', + price: 4, + position: 21, + category: 'Card Games', + }, + ], + }, + integrations: { All: true }, + sentAt: '2019-10-14T09:03:22.563Z', + }, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 5, + userId: 'u1', + dontBatch: true, + }, + }, ], destType: 'reddit', }, @@ -325,6 +450,147 @@ export const data = [ DestinationDefinition: { Config: { cdkV2Enabled: true } }, }, }, + { + batchedRequest: { + body: { + JSON: { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { tracking_type: 'Purchase' }, + user: { + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: + '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: + 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 2, + currency: 'USD', + value: 1500, + value_decimal: 15, + products: [ + { id: '123', name: 'Monopoly', category: 'Games' }, + { id: '345', name: 'UNO', category: 'Games' }, + ], + }, + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://ads-api.reddit.com/api/v2.0/conversions/events/a2_fsddXXXfsfd', + headers: { + Authorization: 'Bearer dummyAccessToken', + 'Content-Type': 'application/json', + }, + params: {}, + files: {}, + }, + metadata: [ + { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 4, + userId: 'u1', + dontBatch: true, + }, + ], + batched: true, + statusCode: 200, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + }, + { + batchedRequest: { + body: { + JSON: { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { tracking_type: 'ViewContent' }, + user: { + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: + '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: + 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 0, + value: 2600, + value_decimal: 26, + products: [ + { + id: '017c6f5d5cf86a4b22432066', + name: 'Just Another Game', + category: 'Games and Entertainment', + }, + { + id: '89ac6f5d5cf86a4b64eac145', + name: 'Wrestling Trump Cards', + category: 'Card Games', + }, + ], + }, + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://ads-api.reddit.com/api/v2.0/conversions/events/a2_fsddXXXfsfd', + headers: { + Authorization: 'Bearer dummyAccessToken', + 'Content-Type': 'application/json', + }, + params: {}, + files: {}, + }, + metadata: [ + { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 5, + userId: 'u1', + dontBatch: true, + }, + ], + batched: true, + statusCode: 200, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + }, ], }, }, From 227419f1ff618f96aafa849862828e2315e4ac55 Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti <110057617+aanshi07@users.noreply.github.com> Date: Fri, 13 Dec 2024 14:42:46 +0530 Subject: [PATCH 5/6] feat: onboard topsort destination (#3913) * chore: topsort changes * chore: boilerplates * chore: topsort changes * chore: function updates * chore: product array changes * chore: purchase event implementation * chore: purchase function updated * chore: build finalPayload * chore: few updations * chore: mockfn changes * chore: restructured files - moved impressions and clicks logic into its own file - moved purchase related logic into its own file * chore: update formatting * chore: test cases added * chore: destType updated --------- Co-authored-by: Utsab Chowdhury Co-authored-by: Sai Sankeerth --- src/features.ts | 1 + src/v0/destinations/topsort/config.js | 31 + .../data/TopSortPurchaseProductConfig.json | 24 + .../topsort/data/TopsortItemConfig.json | 15 + .../topsort/data/TopsortPlacementConfig.json | 36 ++ .../topsort/data/TopsortTrackConfig.json | 27 + .../topsort/impressions-and-clicks.js | 95 +++ src/v0/destinations/topsort/purchase.js | 56 ++ src/v0/destinations/topsort/transform.js | 158 +++++ src/v0/destinations/topsort/utils.js | 53 ++ src/v0/util/index.js | 8 + .../destinations/topsort/mocks.ts | 5 + .../destinations/topsort/processor/data.ts | 9 + .../topsort/processor/trackClicksTestData.ts | 571 ++++++++++++++++++ .../processor/trackImpressionsTestData.ts | 381 ++++++++++++ .../processor/trackPurchasesTestData.ts | 457 ++++++++++++++ .../destinations/topsort/router/data.ts | 418 +++++++++++++ test/integrations/testTypes.ts | 2 +- test/integrations/testUtils.ts | 1 + 19 files changed, 2347 insertions(+), 1 deletion(-) create mode 100644 src/v0/destinations/topsort/config.js create mode 100644 src/v0/destinations/topsort/data/TopSortPurchaseProductConfig.json create mode 100644 src/v0/destinations/topsort/data/TopsortItemConfig.json create mode 100644 src/v0/destinations/topsort/data/TopsortPlacementConfig.json create mode 100644 src/v0/destinations/topsort/data/TopsortTrackConfig.json create mode 100644 src/v0/destinations/topsort/impressions-and-clicks.js create mode 100644 src/v0/destinations/topsort/purchase.js create mode 100644 src/v0/destinations/topsort/transform.js create mode 100644 src/v0/destinations/topsort/utils.js create mode 100644 test/integrations/destinations/topsort/mocks.ts create mode 100644 test/integrations/destinations/topsort/processor/data.ts create mode 100644 test/integrations/destinations/topsort/processor/trackClicksTestData.ts create mode 100644 test/integrations/destinations/topsort/processor/trackImpressionsTestData.ts create mode 100644 test/integrations/destinations/topsort/processor/trackPurchasesTestData.ts create mode 100644 test/integrations/destinations/topsort/router/data.ts diff --git a/src/features.ts b/src/features.ts index 4ff419a7fe..fb91ae2883 100644 --- a/src/features.ts +++ b/src/features.ts @@ -93,6 +93,7 @@ const defaultFeaturesConfig: FeaturesConfig = { AMAZON_AUDIENCE: true, INTERCOM_V2: true, LINKEDIN_AUDIENCE: true, + TOPSORT: true, }, regulations: [ 'BRAZE', diff --git a/src/v0/destinations/topsort/config.js b/src/v0/destinations/topsort/config.js new file mode 100644 index 0000000000..5d4060f526 --- /dev/null +++ b/src/v0/destinations/topsort/config.js @@ -0,0 +1,31 @@ +const { getMappingConfig } = require('../../util'); + +const ENDPOINT = 'https://api.topsort.com/v2/events'; + +const ConfigCategory = { + TRACK: { + type: 'track', + name: 'TopsortTrackConfig', + }, + PLACEMENT: { name: 'TopsortPlacementConfig' }, + ITEM: { name: 'TopsortItemConfig' }, + PURCHASE_ITEM: { name: 'TopSortPurchaseProductConfig' }, +}; + +const ECOMM_EVENTS_WITH_PRODUCT_ARRAY = [ + 'Cart Viewed', + 'Checkout Started', + 'Order Updated', + 'Order Completed', + 'Order Refunded', + 'Order Cancelled', +]; + +const mappingConfig = getMappingConfig(ConfigCategory, __dirname); + +module.exports = { + mappingConfig, + ConfigCategory, + ENDPOINT, + ECOMM_EVENTS_WITH_PRODUCT_ARRAY, +}; diff --git a/src/v0/destinations/topsort/data/TopSortPurchaseProductConfig.json b/src/v0/destinations/topsort/data/TopSortPurchaseProductConfig.json new file mode 100644 index 0000000000..f3f9d877a9 --- /dev/null +++ b/src/v0/destinations/topsort/data/TopSortPurchaseProductConfig.json @@ -0,0 +1,24 @@ +[ + { + "destKey": "productId", + "sourceKeys": ["product_id", "properties.product_id"] + }, + { + "destKey": "unitPrice", + "sourceKeys": ["price", "properties.price"], + "metadata": { + "type": "toNumber" + } + }, + { + "destKey": "quantity", + "sourceKeys": ["quantity", "properties.quantity"], + "metadata": { + "toInt": true + } + }, + { + "destKey": "vendorId", + "sourceKeys": "properties.vendorId" + } +] diff --git a/src/v0/destinations/topsort/data/TopsortItemConfig.json b/src/v0/destinations/topsort/data/TopsortItemConfig.json new file mode 100644 index 0000000000..ff8c77a7ac --- /dev/null +++ b/src/v0/destinations/topsort/data/TopsortItemConfig.json @@ -0,0 +1,15 @@ +[ + { + "destKey": "position", + "sourceKeys": ["properties.position", "position"], + "metadata": { + "toInt": true + }, + "required": false + }, + { + "destKey": "productId", + "sourceKeys": ["properties.product_id", "product_id"], + "required": false + } +] diff --git a/src/v0/destinations/topsort/data/TopsortPlacementConfig.json b/src/v0/destinations/topsort/data/TopsortPlacementConfig.json new file mode 100644 index 0000000000..7c67bb183d --- /dev/null +++ b/src/v0/destinations/topsort/data/TopsortPlacementConfig.json @@ -0,0 +1,36 @@ +[ + { + "destKey": "path", + "sourceKeys": "context.page.path", + "required": false + }, + { + "destKey": "searchQuery", + "sourceKeys": "properties.query", + "required": false + }, + { + "destKey": "page", + "sourceKeys": "properties.pageNumber", + "metadata": { + "toInt": true + }, + "required": false + }, + { + "destKey": "pageSize", + "sourceKeys": "properties.pageSize", + "metadata": { + "toInt": true + }, + "required": false + }, + { + "destKey": "categoryIds", + "sourceKeys": "properties.category_id", + "required": false, + "metadata": { + "toArray": true + } + } +] diff --git a/src/v0/destinations/topsort/data/TopsortTrackConfig.json b/src/v0/destinations/topsort/data/TopsortTrackConfig.json new file mode 100644 index 0000000000..fcc9c57d1b --- /dev/null +++ b/src/v0/destinations/topsort/data/TopsortTrackConfig.json @@ -0,0 +1,27 @@ +[ + { + "destKey": "occurredAt", + "sourceKeys": ["timestamp", "originalTimestamp"], + "required": true + }, + { + "destKey": "opaqueUserId", + "sourceKeys": "anonymousId", + "required": true + }, + { + "destKey": "resolvedBidId", + "sourceKeys": "properties.resolvedBidId", + "required": false + }, + { + "destKey": "entity", + "sourceKeys": "properties.entity", + "required": false + }, + { + "destKey": "additionalAttribution", + "sourceKeys": "properties.additionalAttribution", + "required": false + } +] diff --git a/src/v0/destinations/topsort/impressions-and-clicks.js b/src/v0/destinations/topsort/impressions-and-clicks.js new file mode 100644 index 0000000000..ca3c6ad860 --- /dev/null +++ b/src/v0/destinations/topsort/impressions-and-clicks.js @@ -0,0 +1,95 @@ +const { ConfigCategory, mappingConfig } = require('./config'); +const { getItemPayloads, addFinalPayload } = require('./utils'); +const { constructPayload, generateUUID } = require('../../util'); + +const processImpressionsAndClicksUtility = { + // Create event data object + createEventData(basePayload, placementPayload, itemPayload, event) { + return { + topsortPayload: { + ...basePayload, + placement: { + ...placementPayload, + ...itemPayload, + }, + id: generateUUID(), + }, + event, + }; + }, + + // Process events with a product array + processProductArray({ + products, + basePayload, + placementPayload, + topsortEventName, + finalPayloads, + }) { + const itemPayloads = getItemPayloads(products, mappingConfig[ConfigCategory.ITEM.name]); + itemPayloads.forEach((itemPayload) => { + const eventData = this.createEventData( + basePayload, + placementPayload, + itemPayload, + topsortEventName, + ); + addFinalPayload(eventData, finalPayloads); + }); + }, + + // Process events with a single product + processSingleProduct({ + basePayload, + placementPayload, + message, + topsortEventName, + finalPayloads, + }) { + const itemPayload = constructPayload(message, mappingConfig[ConfigCategory.ITEM.name]); + const eventData = this.createEventData( + basePayload, + placementPayload, + itemPayload, + topsortEventName, + ); + + // Ensure messageId is used instead of generating a UUID for single product events + eventData.topsortPayload.id = message.messageId; + + // Add final payload with appropriate ID and other headers + addFinalPayload(eventData, finalPayloads); + }, + + processImpressionsAndClicks({ + isProductArrayAvailable, + basePayload, + topsortEventName, + finalPayloads, + products, + message, + placementPayload, + }) { + if (isProductArrayAvailable) { + // If product array is available, process the event with multiple products + this.processProductArray({ + basePayload, + topsortEventName, + finalPayloads, + products, + placementPayload, + }); + } else { + // Otherwise, process the event with a single product + this.processSingleProduct({ + basePayload, + topsortEventName, + finalPayloads, + message, + placementPayload, + }); + } + }, +}; + +module.exports = { processImpressionsAndClicksUtility }; diff --git a/src/v0/destinations/topsort/purchase.js b/src/v0/destinations/topsort/purchase.js new file mode 100644 index 0000000000..497188cb10 --- /dev/null +++ b/src/v0/destinations/topsort/purchase.js @@ -0,0 +1,56 @@ +const { ConfigCategory, mappingConfig } = require('./config'); +const { getItemPayloads, addFinalPayload } = require('./utils'); +const { constructPayload, generateUUID } = require('../../util'); + +const processPurchaseEventUtility = { + // Create event data object for purchase events + createEventData(basePayload, items, event) { + return { + topsortPayload: { + ...basePayload, + items, + id: generateUUID(), + }, + event, + }; + }, + + // Function to process events with a product array for purchase events + processProductArray(args) { + const { products, basePayload, topsortEventName, finalPayloads } = args; + const itemPayloads = getItemPayloads( + products, + mappingConfig[ConfigCategory.PURCHASE_ITEM.name], + ); + const eventData = this.createEventData(basePayload, itemPayloads, topsortEventName); + addFinalPayload(eventData, finalPayloads); + }, + + // Function to process events with a single product for purchase events + processSingleProduct(args) { + const { basePayload, message, topsortEventName, finalPayloads } = args; + const itemPayload = constructPayload(message, mappingConfig[ConfigCategory.PURCHASE_ITEM.name]); + const eventData = this.createEventData(basePayload, [itemPayload], topsortEventName); + + // Ensure messageId is used instead of generating a UUID for single product events + eventData.topsortPayload.id = message.messageId; + + // Add final payload with appropriate ID and other headers + addFinalPayload(eventData, finalPayloads); + }, + + // Function to process purchase events (either with a product array or single product) + processPurchaseEvent(args) { + if (args.isProductArrayAvailable) { + // Process the event with multiple products (product array) + this.processProductArray(args); + } else { + // Process the event with a single product + this.processSingleProduct(args); + } + }, +}; + +module.exports = { + processPurchaseEventUtility, +}; diff --git a/src/v0/destinations/topsort/transform.js b/src/v0/destinations/topsort/transform.js new file mode 100644 index 0000000000..e5997ab37d --- /dev/null +++ b/src/v0/destinations/topsort/transform.js @@ -0,0 +1,158 @@ +const { + InstrumentationError, + ConfigurationError, + getHashFromArray, +} = require('@rudderstack/integrations-lib'); +const { + mappingConfig, + ECOMM_EVENTS_WITH_PRODUCT_ARRAY, + ConfigCategory, + ENDPOINT, +} = require('./config'); +const { + constructPayload, + handleRtTfSingleEventError, + defaultRequestConfig, + defaultPostRequestConfig, + getSuccessRespEvents, +} = require('../../util'); +const { isProductArrayValid, getMappedEventName } = require('./utils'); +const { JSON_MIME_TYPE } = require('../../util/constant'); +const { processPurchaseEventUtility } = require('./purchase'); +const { processImpressionsAndClicksUtility } = require('./impressions-and-clicks'); + +const processTopsortEvents = (message, { Config }, finalPayloads) => { + const { topsortEvents } = Config; + const { event, properties } = message; + const { products } = properties; + + // Parse Topsort event mappings + const mappedEventName = getMappedEventName(getHashFromArray(topsortEvents), event); + + if (!mappedEventName) { + throw new InstrumentationError("Event not mapped in 'topsortEvents'. Dropping the event."); + } + + const topsortEventName = mappedEventName; + + // Construct base and placement payloads + const basePayload = constructPayload(message, mappingConfig[ConfigCategory.TRACK.name]); + + const commonArgs = { + basePayload, + topsortEventName, + finalPayloads, + products, + message, + isProductArrayAvailable: + ECOMM_EVENTS_WITH_PRODUCT_ARRAY.includes(event) && isProductArrayValid(event, properties), + }; + + // Process events based on type and construct payload within each logic block + if (topsortEventName === 'impressions' || topsortEventName === 'clicks') { + const placementPayload = constructPayload( + message, + mappingConfig[ConfigCategory.PLACEMENT.name], + ); + processImpressionsAndClicksUtility.processImpressionsAndClicks({ + ...commonArgs, + placementPayload, // Only pass placementPayload for impressions and clicks + }); + } else if (topsortEventName === 'purchases') { + processPurchaseEventUtility.processPurchaseEvent({ + ...commonArgs, + }); + } else { + throw new InstrumentationError(`Event not mapped: ${topsortEventName}`); + } + + return finalPayloads; +}; + +const processEvent = (message, destination, finalPayloads) => { + // Check for missing API Key or missing Advertiser ID + if (!destination.Config.apiKey) { + throw new ConfigurationError('API Key is missing. Aborting message.', 400); + } + if (!message.type) { + throw new InstrumentationError('Message Type is missing. Aborting message.', 400); + } + + const messageType = message.type.toLowerCase(); + + // Handle 'track' event type + if (messageType !== 'track') { + throw new InstrumentationError('Only "track" events are supported. Dropping event.', 400); + } + + processTopsortEvents(message, destination, finalPayloads); +}; + +// Process function that is called per event +const process = (event) => { + const finalPayloads = { + impressions: [], + clicks: [], + purchases: [], + }; + + processEvent(event.message, event.destination, finalPayloads); + + const response = defaultRequestConfig(); + const { apiKey } = event.destination.Config; + + response.method = defaultPostRequestConfig.requestMethod; + response.body.JSON = finalPayloads; + response.headers = { + 'content-type': JSON_MIME_TYPE, + Authorization: `Bearer ${apiKey}`, + }; + + response.endpoint = ENDPOINT; + + return response; +}; + +// Router destination handler to process a batch of events +const processRouterDest = async (inputs, reqMetadata) => { + const finalPayloads = { + impressions: [], + clicks: [], + purchases: [], + }; + + const failureResponses = []; + const successMetadatas = []; + + inputs.forEach((input) => { + try { + // Process the event + processEvent(input.message, input.destination, finalPayloads); + // Add to successMetadatas array + successMetadatas.push(input.metadata); + } catch (error) { + // Handle error and store the error details + const failureResponse = handleRtTfSingleEventError(input, error, reqMetadata); + failureResponses.push(failureResponse); + } + }); + + const response = defaultRequestConfig(); + const { destination } = inputs[0]; + const { apiKey } = destination.Config; + + response.method = defaultPostRequestConfig.requestMethod; + response.body.JSON = finalPayloads; + response.headers = { + 'content-type': JSON_MIME_TYPE, + Authorization: `Bearer ${apiKey}`, + }; + + response.endpoint = ENDPOINT; + + const successResponses = getSuccessRespEvents(response, successMetadatas, destination, true); + + return [successResponses, ...failureResponses]; +}; + +module.exports = { process, processRouterDest }; diff --git a/src/v0/destinations/topsort/utils.js b/src/v0/destinations/topsort/utils.js new file mode 100644 index 0000000000..ca9edfbcea --- /dev/null +++ b/src/v0/destinations/topsort/utils.js @@ -0,0 +1,53 @@ +const { ConfigurationError } = require('@rudderstack/integrations-lib'); +const { constructPayload } = require('../../util'); + +// Function to check if a product array is valid +const isProductArrayValid = (event, properties) => + Array.isArray(properties?.products) && properties?.products.length > 0; + +// Function to construct item payloads for each product +const getItemPayloads = (products, mappingConfigs) => + products.map((product) => constructPayload(product, mappingConfigs)); + +// Function to add the structured event data to the final payloads array +const addFinalPayload = (eventData, finalPayloads) => { + switch (eventData.event) { + case 'impressions': + finalPayloads.impressions.push(eventData.topsortPayload); + break; + case 'clicks': + finalPayloads.clicks.push(eventData.topsortPayload); + break; + case 'purchases': + finalPayloads.purchases.push(eventData.topsortPayload); + break; + default: + throw new ConfigurationError('Invalid event mapping'); + } +}; + +// Function to retrieve mapped event name from Topsort event mappings. +const getMappedEventName = (parsedTopsortEventMappings, event) => { + const eventName = event.toLowerCase(); + + const mappedEventNames = parsedTopsortEventMappings[eventName]; + + // Check if mapping exists + if (!mappedEventNames) { + throw new ConfigurationError(`Event '${eventName}' not found in Topsort event mappings`); + } + + // If there are multiple mappings, pick the first one or apply your logic + if (Array.isArray(mappedEventNames)) { + return mappedEventNames[0]; // Return the first mapping + } + + return mappedEventNames; // Return the single mapping if not an array +}; + +module.exports = { + isProductArrayValid, + getItemPayloads, + addFinalPayload, + getMappedEventName, +}; diff --git a/src/v0/util/index.js b/src/v0/util/index.js index ad08be448e..0f9abfb040 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -970,6 +970,7 @@ const handleMetadataForValue = (value, metadata, destKey, integrationsObj = null strictMultiMap, validateTimestamp, allowedKeyCheck, + toArray, } = metadata; // if value is null and defaultValue is supplied - use that @@ -1037,6 +1038,13 @@ const handleMetadataForValue = (value, metadata, destKey, integrationsObj = null } } + if (toArray) { + if (Array.isArray(formattedVal)) { + return formattedVal; + } + return [formattedVal]; + } + return formattedVal; }; diff --git a/test/integrations/destinations/topsort/mocks.ts b/test/integrations/destinations/topsort/mocks.ts new file mode 100644 index 0000000000..0a3e24b30f --- /dev/null +++ b/test/integrations/destinations/topsort/mocks.ts @@ -0,0 +1,5 @@ +import utils from '../../../../src/v0/util'; + +export const defaultMockFns = () => { + jest.spyOn(utils, 'generateUUID').mockReturnValue('test-id-123-123-123'); +}; diff --git a/test/integrations/destinations/topsort/processor/data.ts b/test/integrations/destinations/topsort/processor/data.ts new file mode 100644 index 0000000000..73f838f140 --- /dev/null +++ b/test/integrations/destinations/topsort/processor/data.ts @@ -0,0 +1,9 @@ +import { trackClicksTestData } from './trackClicksTestData'; +import { trackImpressionsTestData } from './trackImpressionsTestData'; +import { trackPurchasesTestData } from './trackPurchasesTestData'; + +export const data = [ + ...trackClicksTestData, + ...trackImpressionsTestData, + ...trackPurchasesTestData, +]; diff --git a/test/integrations/destinations/topsort/processor/trackClicksTestData.ts b/test/integrations/destinations/topsort/processor/trackClicksTestData.ts new file mode 100644 index 0000000000..2cfd458905 --- /dev/null +++ b/test/integrations/destinations/topsort/processor/trackClicksTestData.ts @@ -0,0 +1,571 @@ +import { Destination } from '../../../../../src/types'; +import { ProcessorTestData } from '../../../testTypes'; +import { + generateMetadata, + generateSimplifiedTrackPayload, + transformResultBuilder, +} from '../../../testUtils'; +import { defaultMockFns } from '../mocks'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', // Base URL for Topsort API + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Product Clicked', + to: 'clicks', + }, + { + from: 'Order Completed', + to: 'clicks', + }, + { + from: 'Order Refunded', + to: 'clicks', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const trackClicksTestData: ProcessorTestData[] = [ + { + id: 'Test 0', + name: 'topsort', + description: + 'Verifies that a Product Clicked event with all necessary properties is successfully processed and mapped correctly by Topsort.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Clicked', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 1', + name: 'topsort', + description: + 'Validates the correct processing and mapping of an Order Completed event with multiple products.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-id-123-123-123', + }, + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 2, + productId: '577c6f5d5cf86a4c7735ba03', + }, + id: 'test-id-123-123-123', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 2', + name: 'topsort', + description: + 'Tests the handling of an invalid event type (abc) and ensures that Topsort correctly drops the event with a 400 error indicating unsupported event type.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + type: 'abc', + event: 'Order Refunded', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }, + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: 'Only "track" events are supported. Dropping event.', + statTags: { + destType: 'TOPSORT', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: generateMetadata(1), + statusCode: 400, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 3', + name: 'topsort', + description: + 'Verifies the correct processing of an Order Completed event with multiple products and handles an error for an unrecognized Order Updated2 event in Topsort.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Updated2', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-id-123-123-123', + }, + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 2, + productId: '577c6f5d5cf86a4c7735ba03', + }, + id: 'test-id-123-123-123', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + { + error: "Event 'order updated2' not found in Topsort event mappings", + statTags: { + destType: 'TOPSORT', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'configuration', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: generateMetadata(1), + statusCode: 400, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, +]; diff --git a/test/integrations/destinations/topsort/processor/trackImpressionsTestData.ts b/test/integrations/destinations/topsort/processor/trackImpressionsTestData.ts new file mode 100644 index 0000000000..2f1fc60571 --- /dev/null +++ b/test/integrations/destinations/topsort/processor/trackImpressionsTestData.ts @@ -0,0 +1,381 @@ +import { Destination } from '../../../../../src/types'; +import { ProcessorTestData } from '../../../testTypes'; +import { + generateMetadata, + generateSimplifiedTrackPayload, + transformResultBuilder, +} from '../../../testUtils'; +import { defaultMockFns } from '../mocks'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', // Base URL for Topsort API + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Product Viewed', + to: 'impressions', + }, + { + from: 'Checkout Started', + to: 'impressions', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const trackImpressionsTestData: ProcessorTestData[] = [ + { + id: 'Test 0', + name: 'topsort', + description: + 'Track call with impressions event, verifies that a Product Viewed event is correctly mapped', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Viewed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + clicks: [], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 1', + name: 'topsort', + description: + 'Verifies that a Checkout Started event with multiple products is correctly mapped and ingested as impressions in Topsort.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Checkout Started', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-id-123-123-123', + }, + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 2, + productId: '577c6f5d5cf86a4c7735ba03', + }, + id: 'test-id-123-123-123', + }, + ], + clicks: [], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 2', + name: 'topsort', + description: + 'Verifies that an invalid event (Checkout done) that is not found in Topsort’s event mappings is handled and returns an error with a status code 400.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Checkout done', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: "Event 'checkout done' not found in Topsort event mappings", + statTags: { + destType: 'TOPSORT', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'configuration', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: generateMetadata(1), + statusCode: 400, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, +]; diff --git a/test/integrations/destinations/topsort/processor/trackPurchasesTestData.ts b/test/integrations/destinations/topsort/processor/trackPurchasesTestData.ts new file mode 100644 index 0000000000..a4736fb471 --- /dev/null +++ b/test/integrations/destinations/topsort/processor/trackPurchasesTestData.ts @@ -0,0 +1,457 @@ +import { Destination } from '../../../../../src/types'; +import { ProcessorTestData } from '../../../testTypes'; +import { + generateMetadata, + generateSimplifiedTrackPayload, + transformResultBuilder, +} from '../../../testUtils'; +import { defaultMockFns } from '../mocks'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', // Base URL for Topsort API + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Order Completed', + to: 'purchases', + }, + { + from: 'Product Added', + to: 'purchases', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const trackPurchasesTestData: ProcessorTestData[] = [ + { + id: 'Test 0', + name: 'topsort', + description: + 'Verifies that a Product Added event is correctly mapped and ingested as a purchase event in Topsort with the appropriate product details.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Added', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 1', + name: 'topsort', + description: + 'Verifies that a Checkout Started event with multiple products is correctly mapped with items.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + unitPrice: 40, + }, + { + productId: '577c6f5d5cf86a4c7735ba03', + unitPrice: 5, + }, + ], + id: 'test-id-123-123-123', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 2', + name: 'topsort', + description: + 'Verifies that both a Product Added and an Order Completed event are correctly mapped and ingested into Topsort as purchase events', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Added', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, +]; diff --git a/test/integrations/destinations/topsort/router/data.ts b/test/integrations/destinations/topsort/router/data.ts new file mode 100644 index 0000000000..0cabdcbac8 --- /dev/null +++ b/test/integrations/destinations/topsort/router/data.ts @@ -0,0 +1,418 @@ +import { Destination } from '../../../../../src/types'; +import { RouterTestData } from '../../../testTypes'; +import { generateMetadata } from '../../../testUtils'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Product Clicked', + to: 'clicks', + }, + { + from: 'Product Added', + to: 'purchases', + }, + { + from: 'Product Removed', + to: 'impressions', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const data: RouterTestData[] = [ + { + id: 'topsort-router-test-1', + name: 'topsort', + description: 'Basic Router Test for track call having clicks event', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200, and the output should correctly map the properties.', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + metadata: generateMetadata(1), + message: { + type: 'track', + event: 'Product Clicked', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + anonymousId: 'sampath', + channel: 'web', + context: { + page: { + path: '/category/123', + }, + ip: '0.0.0.0', + }, + integrations: { All: true }, + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + }, + }, + ], + destType: 'topsort', + }, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + body: { + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'sampath', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/category/123', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1)], + batched: true, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, + { + id: 'topsort-router-test-2', + name: 'topsort', + description: 'Basic Router Test for track call having impressions event', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200, and the output should correctly map the properties.', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + metadata: generateMetadata(1), + message: { + type: 'track', + event: 'Product Removed', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + anonymousId: 'sampath', + channel: 'web', + context: { + page: { + path: '/category/123', + }, + ip: '0.0.0.0', + }, + integrations: { All: true }, + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + }, + }, + ], + destType: 'topsort', + }, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + body: { + JSON: { + impressions: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'sampath', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/category/123', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + clicks: [], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1)], + batched: true, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, + { + id: 'topsort-router-test-3', + name: 'topsort', + description: 'Basic Router Test for track call having purchases event', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200, and the output should correctly map the properties.', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + metadata: generateMetadata(1), + message: { + type: 'track', + event: 'Product Added', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + anonymousId: 'sampath', + channel: 'web', + context: { + page: { + path: '/category/123', + }, + ip: '0.0.0.0', + }, + integrations: { All: true }, + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + ], + }, + }, + }, + ], + destType: 'topsort', + }, + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + body: { + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'sampath', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1)], + batched: true, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, +]; diff --git a/test/integrations/testTypes.ts b/test/integrations/testTypes.ts index 3c5cf60600..b11403f50a 100644 --- a/test/integrations/testTypes.ts +++ b/test/integrations/testTypes.ts @@ -101,7 +101,7 @@ export type ProcessorTestData = { body: ProcessorTransformationResponse[]; }; }; - mockFns?: (mockAdapter: MockAdapter) => {}; + mockFns?: (mockAdapter: MockAdapter) => void; }; export type RouterTestData = { id: string; diff --git a/test/integrations/testUtils.ts b/test/integrations/testUtils.ts index 7e6e6b9acb..73d08e452c 100644 --- a/test/integrations/testUtils.ts +++ b/test/integrations/testUtils.ts @@ -277,6 +277,7 @@ export const generateSimplifiedTrackPayload: any = (parametersOverride: any) => device: parametersOverride.context.device, os: parametersOverride.context.os, app: parametersOverride.context.app, + page: parametersOverride.context.page, }), anonymousId: parametersOverride.anonymousId || 'default-anonymousId', originalTimestamp: parametersOverride.originalTimestamp || '2021-01-03T17:02:53.193Z', From 7d4fbaad99c2b8a3e68672736085bfab318e0fc5 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 13 Dec 2024 09:36:27 +0000 Subject: [PATCH 6/6] chore(release): 1.87.0 --- CHANGELOG.md | 12 ++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e742ea1f55..ee9dead590 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.87.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.86.0...v1.87.0) (2024-12-13) + + +### Features + +* onboard topsort destination ([#3913](https://github.com/rudderlabs/rudder-transformer/issues/3913)) ([227419f](https://github.com/rudderlabs/rudder-transformer/commit/227419f1ff618f96aafa849862828e2315e4ac55)) + + +### Bug Fixes + +* handling partial error in a batch for reddit destination ([#3935](https://github.com/rudderlabs/rudder-transformer/issues/3935)) ([d40db6c](https://github.com/rudderlabs/rudder-transformer/commit/d40db6c1e7f71c5ab5fc3a3659d1fc51b6d527fa)) + ## [1.86.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.85.1...v1.86.0) (2024-12-09) diff --git a/package-lock.json b/package-lock.json index 5f9e7229f6..2aea3c8ffd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.86.0", + "version": "1.87.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.86.0", + "version": "1.87.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index b9064fac2c..aa0a700681 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.86.0", + "version": "1.87.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": {