diff --git a/src/constants/destinationCanonicalNames.js b/src/constants/destinationCanonicalNames.js index c694702f79..6a774811f4 100644 --- a/src/constants/destinationCanonicalNames.js +++ b/src/constants/destinationCanonicalNames.js @@ -87,6 +87,14 @@ const DestCanonicalNames = { ga4: ['GA4', 'ga4', 'Ga4', 'Google Analytics 4', 'googleAnalytics4'], pipedream: ['Pipedream', 'PipeDream', 'pipedream', 'PIPEDREAM'], pagerduty: ['pagerduty', 'PAGERDUTY', 'PagerDuty', 'Pagerduty', 'pagerDuty'], + optimizely_fullstack: [ + 'Optimizely Fullstack', + 'OPTIMIZELY FULLSTACK', + 'optimizely fullstack', + 'OptimizelyFullstack', + 'Optimizely_Fullstack', + 'optimizely_fullstack', + ], }; module.exports = { DestHandlerMap, DestCanonicalNames }; diff --git a/src/v0/destinations/optimizely_fullstack/config.js b/src/v0/destinations/optimizely_fullstack/config.js new file mode 100644 index 0000000000..662db6ba9d --- /dev/null +++ b/src/v0/destinations/optimizely_fullstack/config.js @@ -0,0 +1,20 @@ +const { getMappingConfig } = require('../../util'); + +const getTrackEndPoint = (baseUrl, event) => + `${baseUrl}/v1/track?eventKey=${encodeURIComponent(event)}`; + +const CONFIG_CATEGORIES = { + TRACK: { + name: 'OptimizelyFullStackTrackConfig', + type: 'track', + endpoint: '/v1/track', + }, +}; + +const MAPPING_CONFIG = getMappingConfig(CONFIG_CATEGORIES, __dirname); + +module.exports = { + CONFIG_CATEGORIES, + MAPPING_CONFIG, + getTrackEndPoint, +}; diff --git a/src/v0/destinations/optimizely_fullstack/data/OptimizelyFullStackTrackConfig.json b/src/v0/destinations/optimizely_fullstack/data/OptimizelyFullStackTrackConfig.json new file mode 100644 index 0000000000..d3ae45d7dc --- /dev/null +++ b/src/v0/destinations/optimizely_fullstack/data/OptimizelyFullStackTrackConfig.json @@ -0,0 +1,11 @@ +[ + { + "destKey": "userAttributes", + "sourceKeys": "traits", + "sourceFromGenericMap": true + }, + { + "destKey": "eventTags", + "sourceKeys": "properties" + } +] diff --git a/src/v0/destinations/optimizely_fullstack/transform.js b/src/v0/destinations/optimizely_fullstack/transform.js new file mode 100644 index 0000000000..20e1faae29 --- /dev/null +++ b/src/v0/destinations/optimizely_fullstack/transform.js @@ -0,0 +1,107 @@ +const { EventType } = require('../../../constants'); +const { + defaultRequestConfig, + simpleProcessRouterDest, + constructPayload, + removeUndefinedAndNullValues, + defaultPostRequestConfig, +} = require('../../util'); +const { validateConfig, validateEvent } = require('./util'); +const { CONFIG_CATEGORIES, MAPPING_CONFIG, getTrackEndPoint } = require('./config'); +const { TransformationError, InstrumentationError } = require('../../util/errorTypes'); + +const responseBuilder = (payload, endpoint, destination) => { + if (payload) { + const response = defaultRequestConfig(); + const { sdkKey } = destination.Config; + response.endpoint = endpoint; + response.headers = { + 'Content-Type': 'application/json', + 'X-Optimizely-SDK-Key': sdkKey, + }; + response.method = defaultPostRequestConfig.requestMethod; + response.body.JSON = removeUndefinedAndNullValues(payload); + return response; + } + // fail-safety for developer error + throw new TransformationError('Something went wrong while constructing the payload'); +}; + +// ref:- https://docs.developers.optimizely.com/experimentation/v3.1.0-full-stack/reference/trackevent +const trackResponseBuilder = (message, destination) => { + const { event, userId, anonymousId } = message; + if (!event) { + throw new InstrumentationError('Event name is required'); + } + + validateEvent(message, destination); + const { baseUrl, trackKnownUsers } = destination.Config; + const endpoint = getTrackEndPoint(baseUrl, event); + const { name } = CONFIG_CATEGORIES.TRACK; + const payload = constructPayload(message, MAPPING_CONFIG[name]); + + payload.userId = anonymousId; + if (trackKnownUsers) { + payload.userId = userId; + } + return responseBuilder(payload, endpoint, destination); +}; + +const pageResponseBuilder = (message, destination) => { + const { trackCategorizedPages, trackNamedPages } = destination.Config; + const newMessage = { ...message }; + const returnValue = []; + + if (message.category && trackCategorizedPages) { + newMessage.event = `Viewed ${message.category} page`; + returnValue.push(trackResponseBuilder(newMessage, destination)); + } + if (message.name && trackNamedPages) { + newMessage.event = `Viewed ${message.name} page`; + returnValue.push(trackResponseBuilder(newMessage, destination)); + } + + return returnValue; +}; + +const screenResponseBuilder = (message, destination) => { + const newMessage = { ...message }; + newMessage.event = 'Viewed screen'; + if (message.name) { + newMessage.event = `Viewed ${message.name} screen`; + } + return trackResponseBuilder(newMessage, destination); +}; + +const processEvent = (message, destination) => { + validateConfig(destination); + if (!message.type) { + throw new InstrumentationError('Event type is required'); + } + + const messageType = message.type.toLowerCase(); + let response; + switch (messageType) { + case EventType.TRACK: + response = trackResponseBuilder(message, destination); + break; + case EventType.PAGE: + response = pageResponseBuilder(message, destination); + break; + case EventType.SCREEN: + response = screenResponseBuilder(message, destination); + break; + default: + throw new InstrumentationError(`Event type "${messageType}" is not supported`); + } + return response; +}; + +const process = (event) => processEvent(event.message, event.destination); + +const processRouterDest = async (inputs, reqMetadata) => { + const respList = await simpleProcessRouterDest(inputs, process, reqMetadata); + return respList; +}; + +module.exports = { process, processRouterDest }; diff --git a/src/v0/destinations/optimizely_fullstack/util.js b/src/v0/destinations/optimizely_fullstack/util.js new file mode 100644 index 0000000000..4fa8c3a905 --- /dev/null +++ b/src/v0/destinations/optimizely_fullstack/util.js @@ -0,0 +1,30 @@ +const { ConfigurationError } = require('../../util/errorTypes'); + +const validateConfig = (destination) => { + if (!destination.Config.sdkKey) { + throw new ConfigurationError('SDK key is required'); + } + + if (!destination.Config.baseUrl) { + throw new ConfigurationError('Base url is required'); + } +}; + +const validateEvent = (message, destination) => { + const { userId, anonymousId } = message; + const { trackKnownUsers } = destination.Config; + + if (trackKnownUsers && !userId) { + throw new ConfigurationError( + 'RudderStack will only track users associated with a userId when the trackKnownUsers setting is enabled', + ); + } + + if (!trackKnownUsers && !anonymousId) { + throw new ConfigurationError( + 'AnonymousId is required when trackKnownUsers setting is disabled', + ); + } +}; + +module.exports = { validateConfig, validateEvent }; diff --git a/test/__tests__/data/optimizely_fullstack.json b/test/__tests__/data/optimizely_fullstack.json new file mode 100644 index 0000000000..3798523b1d --- /dev/null +++ b/test/__tests__/data/optimizely_fullstack.json @@ -0,0 +1,488 @@ +[ + { + "description": "Invalid Configuration (missing sdk key)", + "input": { + "message": { + "type": "track", + "channel": "web", + "event": "Product Added", + "properties": {}, + "context": {}, + "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "baseUrl": "https://example.com", + "trackKnownUsers": false, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + } + }, + "output": { + "error": "SDK key is required" + } + }, + { + "description": "Invalid Configuration (missing bsase url)", + "input": { + "message": { + "type": "track", + "channel": "web", + "event": "Product Added", + "properties": {}, + "context": {}, + "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "trackKnownUsers": false, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + } + }, + "output": { + "error": "Base url is required" + } + }, + { + "description": "Invalid Configuration (Track known users toggle is on and userId is missing in request)", + "input": { + "message": { + "type": "track", + "channel": "web", + "event": "Product Added", + "properties": { "price": 999, "quantity": 1 }, + "context": { "traits": { "firstName": "John", "age": 27 } }, + "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": true, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + } + }, + "output": { + "error": "RudderStack will only track users associated with a userId when the trackKnownUsers setting is enabled" + } + }, + { + "description": "Invalid Configuration (Track known users toggle is off and anonymousId is missing in request)", + "input": { + "message": { + "type": "track", + "channel": "web", + "event": "Product Added", + "properties": { "price": 999, "quantity": 1 }, + "context": { "traits": { "firstName": "John", "age": 27 } }, + "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": false, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + } + }, + "output": { + "error": "AnonymousId is required when trackKnownUsers setting is disabled" + } + }, + { + "description": "Track call without event", + "input": { + "message": { + "type": "track", + "channel": "web", + "properties": {}, + "context": {}, + "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": false, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + } + }, + "output": { + "error": "Event name is required" + } + }, + { + "description": "Track call with userId", + "input": { + "message": { + "type": "track", + "channel": "web", + "event": "Product Added", + "userId": "test123", + "properties": { "price": 999, "quantity": 1 }, + "context": { "traits": { "firstName": "John", "age": 27 } }, + "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": true, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + } + }, + "output": { + "body": { + "FORM": {}, + "JSON": { + "userId": "test123", + "userAttributes": { "firstName": "John", "age": 27 }, + "eventTags": { "price": 999, "quantity": 1 } + }, + "JSON_ARRAY": {}, + "XML": {} + }, + "endpoint": "https://example.com/v1/track?eventKey=Product%20Added", + "files": {}, + "headers": { + "Content-Type": "application/json", + "X-Optimizely-SDK-Key": "test-sdk-key" + }, + "method": "POST", + "params": {}, + "type": "REST", + "version": "1" + } + }, + { + "description": "Track call with anonymousId", + "input": { + "message": { + "type": "track", + "channel": "web", + "event": "Product Added", + "properties": { "price": 999, "quantity": 1 }, + "context": { "traits": { "firstName": "John", "age": 27 } }, + "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": false, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + } + }, + "output": { + "body": { + "FORM": {}, + "JSON": { + "userId": "97c46c81-3140-456d-b2a9-690d70aaca35", + "userAttributes": { "firstName": "John", "age": 27 }, + "eventTags": { "price": 999, "quantity": 1 } + }, + "JSON_ARRAY": {}, + "XML": {} + }, + "endpoint": "https://example.com/v1/track?eventKey=Product%20Added", + "files": {}, + "headers": { + "Content-Type": "application/json", + "X-Optimizely-SDK-Key": "test-sdk-key" + }, + "method": "POST", + "params": {}, + "type": "REST", + "version": "1" + } + }, + { + "description": "Page call with Track Categorized Pages is enabled", + "input": { + "message": { + "type": "page", + "channel": "web", + "userId": "test123", + "category": "food", + "properties": { + "url": "https://www.google.com/", + "title": "Google home" + }, + "context": { "traits": { "firstName": "John", "age": 27 } }, + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": true, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + } + }, + "output": [ + { + "body": { + "FORM": {}, + "JSON": { + "userId": "test123", + "userAttributes": { "firstName": "John", "age": 27 }, + "eventTags": { + "url": "https://www.google.com/", + "title": "Google home" + } + }, + "JSON_ARRAY": {}, + "XML": {} + }, + "endpoint": "https://example.com/v1/track?eventKey=Viewed%20food%20page", + "files": {}, + "headers": { + "Content-Type": "application/json", + "X-Optimizely-SDK-Key": "test-sdk-key" + }, + "method": "POST", + "params": {}, + "type": "REST", + "version": "1" + } + ] + }, + { + "description": "Page call with Track Named Pages is enabled", + "input": { + "message": { + "type": "page", + "channel": "web", + "userId": "test123", + "name": "Thank You", + "properties": { + "url": "https://www.google.com/", + "title": "Google home" + }, + "context": { "traits": { "firstName": "John", "age": 27 } }, + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": true, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": false, + "trackNamedPages": true + } + } + }, + "output": [ + { + "body": { + "FORM": {}, + "JSON": { + "userId": "test123", + "userAttributes": { "firstName": "John", "age": 27 }, + "eventTags": { + "url": "https://www.google.com/", + "title": "Google home" + } + }, + "JSON_ARRAY": {}, + "XML": {} + }, + "endpoint": "https://example.com/v1/track?eventKey=Viewed%20Thank%20You%20page", + "files": {}, + "headers": { + "Content-Type": "application/json", + "X-Optimizely-SDK-Key": "test-sdk-key" + }, + "method": "POST", + "params": {}, + "type": "REST", + "version": "1" + } + ] + }, + { + "description": "Page call with both Track Categorized Pages and Track Named Pages toggles are enabled", + "input": { + "message": { + "type": "page", + "channel": "web", + "userId": "test123", + "category": "Docs", + "name": "Index", + "properties": { + "url": "https://www.google.com/", + "title": "Google home" + }, + "context": { "traits": { "firstName": "John", "age": 27 } }, + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": true, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + } + }, + "output": [ + { + "body": { + "FORM": {}, + "JSON": { + "userId": "test123", + "userAttributes": { "firstName": "John", "age": 27 }, + "eventTags": { + "url": "https://www.google.com/", + "title": "Google home" + } + }, + "JSON_ARRAY": {}, + "XML": {} + }, + "endpoint": "https://example.com/v1/track?eventKey=Viewed%20Docs%20page", + "files": {}, + "headers": { + "Content-Type": "application/json", + "X-Optimizely-SDK-Key": "test-sdk-key" + }, + "method": "POST", + "params": {}, + "type": "REST", + "version": "1" + }, + { + "body": { + "FORM": {}, + "JSON": { + "userId": "test123", + "userAttributes": { "firstName": "John", "age": 27 }, + "eventTags": { + "url": "https://www.google.com/", + "title": "Google home" + } + }, + "JSON_ARRAY": {}, + "XML": {} + }, + "endpoint": "https://example.com/v1/track?eventKey=Viewed%20Index%20page", + "files": {}, + "headers": { + "Content-Type": "application/json", + "X-Optimizely-SDK-Key": "test-sdk-key" + }, + "method": "POST", + "params": {}, + "type": "REST", + "version": "1" + } + ] + }, + { + "description": "Screen call", + "input": { + "message": { + "type": "screen", + "channel": "web", + "userId": "test123", + "name": "Main", + "properties": { + "url": "https://www.google.com/", + "title": "Google Main" + }, + "context": { "traits": { "firstName": "John", "age": 27 } }, + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": true, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": false, + "trackNamedPages": true + } + } + }, + "output": { + "body": { + "FORM": {}, + "JSON": { + "userId": "test123", + "userAttributes": { "firstName": "John", "age": 27 }, + "eventTags": { + "url": "https://www.google.com/", + "title": "Google Main" + } + }, + "JSON_ARRAY": {}, + "XML": {} + }, + "endpoint": "https://example.com/v1/track?eventKey=Viewed%20Main%20screen", + "files": {}, + "headers": { + "Content-Type": "application/json", + "X-Optimizely-SDK-Key": "test-sdk-key" + }, + "method": "POST", + "params": {}, + "type": "REST", + "version": "1" + } + } +] diff --git a/test/__tests__/data/optimizely_fullstack_router.json b/test/__tests__/data/optimizely_fullstack_router.json new file mode 100644 index 0000000000..1d4edceb54 --- /dev/null +++ b/test/__tests__/data/optimizely_fullstack_router.json @@ -0,0 +1,228 @@ +[ + { + "input": [ + { + "message": { + "type": "track", + "channel": "web", + "event": "Product Added", + "userId": "test123", + "properties": { "price": 999, "quantity": 1 }, + "context": { "traits": { "firstName": "John", "age": 27 } }, + "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": true, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + }, + "metadata": { + "jobId": 1 + } + }, + { + "message": { + "type": "page", + "channel": "web", + "userId": "test123", + "category": "Docs", + "name": "Index", + "properties": { + "url": "https://www.google.com/", + "title": "Google home" + }, + "context": { "traits": { "firstName": "John", "age": 27 } }, + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": true, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + }, + "metadata": { + "jobId": 2 + } + }, + { + "message": { + "type": "track", + "channel": "web", + "event": "Product Added", + "properties": {}, + "context": {}, + "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", + "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "trackKnownUsers": false, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + }, + "metadata": { + "jobId": 3 + } + } + ], + "output": [ + { + "batched": false, + "batchedRequest": { + "body": { + "FORM": {}, + "JSON": { + "userId": "test123", + "userAttributes": { "firstName": "John", "age": 27 }, + "eventTags": { "price": 999, "quantity": 1 } + }, + "JSON_ARRAY": {}, + "XML": {} + }, + "endpoint": "https://example.com/v1/track?eventKey=Product%20Added", + "files": {}, + "headers": { + "Content-Type": "application/json", + "X-Optimizely-SDK-Key": "test-sdk-key" + }, + "method": "POST", + "params": {}, + "type": "REST", + "version": "1" + }, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": true, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + }, + "metadata": [ + { + "jobId": 1 + } + ], + "statusCode": 200 + }, + { + "batched": false, + "batchedRequest": [ + { + "body": { + "FORM": {}, + "JSON": { + "userId": "test123", + "userAttributes": { "firstName": "John", "age": 27 }, + "eventTags": { + "url": "https://www.google.com/", + "title": "Google home" + } + }, + "JSON_ARRAY": {}, + "XML": {} + }, + "endpoint": "https://example.com/v1/track?eventKey=Viewed%20Docs%20page", + "files": {}, + "headers": { + "Content-Type": "application/json", + "X-Optimizely-SDK-Key": "test-sdk-key" + }, + "method": "POST", + "params": {}, + "type": "REST", + "version": "1" + }, + { + "body": { + "FORM": {}, + "JSON": { + "userId": "test123", + "userAttributes": { "firstName": "John", "age": 27 }, + "eventTags": { + "url": "https://www.google.com/", + "title": "Google home" + } + }, + "JSON_ARRAY": {}, + "XML": {} + }, + "endpoint": "https://example.com/v1/track?eventKey=Viewed%20Index%20page", + "files": {}, + "headers": { + "Content-Type": "application/json", + "X-Optimizely-SDK-Key": "test-sdk-key" + }, + "method": "POST", + "params": {}, + "type": "REST", + "version": "1" + } + ], + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "baseUrl": "https://example.com", + "trackKnownUsers": true, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + }, + "metadata": [ + { + "jobId": 2 + } + ], + "statusCode": 200 + }, + { + "batched": false, + "error": "Base url is required", + "metadata": [ + { + "jobId": 3 + } + ], + "statTags": { + "errorCategory": "dataValidation", + "errorType": "configuration" + }, + "statusCode": 400, + "destination": { + "Config": { + "sdkKey": "test-sdk-key", + "trackKnownUsers": false, + "nonInteraction": false, + "listen": false, + "trackCategorizedPages": true, + "trackNamedPages": true + } + } + } + ] + } +] diff --git a/test/__tests__/optimizely_fullstack.test.js b/test/__tests__/optimizely_fullstack.test.js new file mode 100644 index 0000000000..23e614c219 --- /dev/null +++ b/test/__tests__/optimizely_fullstack.test.js @@ -0,0 +1,46 @@ +const integration = "optimizely_fullstack"; +const name = "Optimizely Fullstack"; + +const fs = require("fs"); +const path = require("path"); + +const version = "v0"; + +const transformer = require(`../../src/${version}/destinations/${integration}/transform`); + +// Processor Test files +const testDataFile = fs.readFileSync( + path.resolve(__dirname, `./data/${integration}.json`) +); +const testData = JSON.parse(testDataFile); + +// Router Test files +const routerTestDataFile = fs.readFileSync( + path.resolve(__dirname, `./data/${integration}_router.json`) + ); +const routerTestData = JSON.parse(routerTestDataFile); + +describe(`${name} Tests`, () => { + describe("Processor", () => { + testData.forEach(async (dataPoint, index) => { + it(`${index}. ${integration} - ${dataPoint.description}`, async () => { + try { + const output = await transformer.process(dataPoint.input); + expect(output).toEqual(dataPoint.output); + } catch (error) { + expect(error.message).toEqual(dataPoint.output.error); + } + }); + }); + }); + + describe("Router Tests", () => { + routerTestData.forEach(dataPoint => { + it("Payload", async () => { + const output = await transformer.processRouterDest(dataPoint.input); + expect(output).toEqual(dataPoint.output); + }); + }); + }); + +});