diff --git a/.github/workflows/component-test-report.yml b/.github/workflows/component-test-report.yml new file mode 100644 index 0000000000..0a13ab19db --- /dev/null +++ b/.github/workflows/component-test-report.yml @@ -0,0 +1,58 @@ +name: Component Test Reporter + +on: + pull_request: + types: + - opened + - reopened + - synchronize + +jobs: + test_and_upload: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4.1.1 + with: + fetch-depth: 1 + + - name: Setup Node + uses: actions/setup-node@v4.0.1 + with: + node-version-file: '.nvmrc' + cache: 'npm' + + - name: Install Dependencies + run: npm ci + + - name: Run Tests and Generate Report + run: | + npm run test:ts -- component + + - name: Upload Report to S3 + uses: jakejarvis/s3-sync-action@v0.5.0 + with: + args: --acl public-read --follow-symlinks --delete + env: + AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + SRC: ./test_reports/ + DEST: /integrations-test-reports/${{ github.run_number }}/ + - name: Comment on PR with S3 Object URL + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { owner, repo } = context.repo; + const runNumber = process.env.GITHUB_RUN_NUMBER; + const commentBody = `Test report for this run is available at: https://company.s3.amazonaws.com/integrations-test-reports/${runNumber}/test-report.html`; + + // Get the pull request number + const prNumber = context.payload.pull_request.number; + + // Comment on the pull request + await github.issues.createComment({ owner, repo, issue_number: prNumber, body: commentBody }); + + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 24d37f6354..f96c3ac807 100644 --- a/.gitignore +++ b/.gitignore @@ -134,4 +134,7 @@ dist **/.DS_Store -.idea \ No newline at end of file +.idea + +# component test report +test_reports/ \ No newline at end of file diff --git a/test/integrations/component.test.ts b/test/integrations/component.test.ts index 847dd4c91f..d8d7732e12 100644 --- a/test/integrations/component.test.ts +++ b/test/integrations/component.test.ts @@ -21,6 +21,8 @@ import tags from '../../src/v0/util/tags'; import { Server } from 'http'; import { appendFileSync } from 'fs'; import { responses } from '../testHelper'; +import { generateTestReport, initaliseReport } from '../test_reporter/reporter'; +import _ from 'lodash'; // To run single destination test cases // npm run test:ts -- component --destination=adobe_analytics @@ -37,6 +39,7 @@ command .option('-f, --feature ', 'Enter Feature Name(processor, router)') .option('-i, --index ', 'Enter Test index') .option('-g, --generate ', 'Enter "true" If you want to generate network file') + .option('-id, --id ', 'Enter unique "Id" of the test case you want to run') .parse(); const opts = command.opts(); @@ -50,7 +53,10 @@ if (opts.generate === 'true') { let server: Server; +const REPORT_COMPATIBLE_INTEGRATION = ['klaviyo']; + beforeAll(async () => { + initaliseReport(); const app = new Koa(); app.use( bodyParser({ @@ -124,6 +130,16 @@ const testRoute = async (route, tcData: TestCaseData) => { const outputResp = tcData.output.response || ({} as any); expect(response.status).toEqual(outputResp.status); + if (REPORT_COMPATIBLE_INTEGRATION.includes(tcData.name?.toLocaleLowerCase())) { + const bodyMatched = _.isEqual(response.body, outputResp.body); + const statusMatched = response.status === outputResp.status; + if (bodyMatched && statusMatched) { + generateTestReport(tcData, response.body, 'passed'); + } else { + generateTestReport(tcData, response.body, 'failed'); + } + } + if (outputResp?.body) { expect(response.body).toEqual(outputResp.body); } @@ -181,6 +197,14 @@ describe.each(allTestDataFilePaths)('%s Tests', (testDataPath) => { if (opts.index !== undefined) { testData = [testData[parseInt(opts.index)]]; } + if (opts.id) { + testData = testData.filter((data) => { + if (data['id'] === opts.id) { + return true; + } + return false; + }); + } describe(`${testData[0].name} ${testData[0].module}`, () => { test.each(testData)('$feature -> $description', async (tcData) => { tcData?.mockFns?.(mockAdapter); diff --git a/test/integrations/destinations/klaviyo/processor/data.ts b/test/integrations/destinations/klaviyo/processor/data.ts index 2025957716..06c4a3e530 100644 --- a/test/integrations/destinations/klaviyo/processor/data.ts +++ b/test/integrations/destinations/klaviyo/processor/data.ts @@ -1,2430 +1,15 @@ +import { ecomTestData } from './ecomTestData'; +import { groupTestData } from './groupTestData'; +import { identifyData } from './identifyTestData'; +import { screenTestData } from './screenTestData'; +import { trackTestData } from './trackTestData'; +import { validationTestData } from './validationTestData'; + export const data = [ - { - "name": "klaviyo", - "description": "Profile updating call and subscribe user (old transformer)", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey" - } - }, - "message": { - "type": "identify", - "sentAt": "2021-01-03T17:02:53.195Z", - "userId": "user@1", - "channel": "web", - "context": { - "os": { - "name": "", - "version": "" - }, - "app": { - "name": "RudderLabs JavaScript SDK", - "build": "1.0.0", - "version": "1.1.11", - "namespace": "com.rudderlabs.javascript" - }, - "traits": { - "firstName": "Test", - "lastName": "Rudderlabs", - "email": "test@rudderstack.com", - "phone": "+12 345 578 900", - "userId": "user@1", - "title": "Developer", - "organization": "Rudder", - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001", - "Flagged": false, - "Residence": "Shibuya", - "properties": { - "listId": "XUepkK", - "subscribe": true, - "consent": [ - "email", - "sms" - ] - } - }, - "locale": "en-US", - "screen": { - "density": 2 - }, - "library": { - "name": "RudderLabs JavaScript SDK", - "version": "1.1.11" - }, - "campaign": {}, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0" - }, - "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", - "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", - "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-03T17:02:53.193Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": - { - "version": "1", - "type": "REST", - "userId": "", - "method": "PATCH", - "endpoint": "https://a.klaviyo.com/api/profiles/01GW3PHVY0MTCDGS0A1612HARX", - "headers": { - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "Accept": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "profile", - "attributes": { - "external_id": "user@1", - "email": "test@rudderstack.com", - "first_name": "Test", - "last_name": "Rudderlabs", - "phone_number": "+12 345 578 900", - "title": "Developer", - "organization": "Rudder", - "location": { - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001" - }, - "properties": { - "Flagged": false, - "Residence": "Shibuya" - } - }, - "id": "01GW3PHVY0MTCDGS0A1612HARX" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "statusCode": 200 - }, { - "output": - { - "version": "1", - "type": "REST", - "method": "POST", - "userId": "", - "endpoint": "https://a.klaviyo.com/api/profile-subscription-bulk-create-jobs", - "headers": { - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "profile-subscription-bulk-create-job", - "attributes": { - "list_id": "XUepkK", - "subscriptions": [ - { - "email": "test@rudderstack.com", - "phone_number": "+12 345 578 900", - "channels": { - "email": [ - "MARKETING" - ], - "sms": [ - "MARKETING" - ] - } - } - ] - } - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "statusCode": 200 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Identify call for with flattenProperties enabled (old transformer)", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey", - "flattenProperties": true - } - }, - "message": { - "type": "identify", - "sentAt": "2021-01-03T17:02:53.195Z", - "userId": "user@1", - "channel": "web", - "context": { - "os": { - "name": "", - "version": "" - }, - "app": { - "name": "RudderLabs JavaScript SDK", - "build": "1.0.0", - "version": "1.1.11", - "namespace": "com.rudderlabs.javascript" - }, - "traits": { - "firstName": "Test", - "lastName": "Rudderlabs", - "email": "test@rudderstack.com", - "phone": "+12 345 578 900", - "userId": "user@1", - "title": "Developer", - "organization": "Rudder", - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001", - "Flagged": false, - "Residence": "Shibuya", - "friend": { - "names": { - "first": "Alice", - "last": "Smith" - }, - "age": 25 - }, - "properties": { - "listId": "XUepkK", - "subscribe": true, - "consent": [ - "email", - "sms" - ] - } - }, - "locale": "en-US", - "screen": { - "density": 2 - }, - "library": { - "name": "RudderLabs JavaScript SDK", - "version": "1.1.11" - }, - "campaign": {}, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0" - }, - "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", - "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", - "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-03T17:02:53.193Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": - { - "version": "1", - "type": "REST", - "userId": "", - "method": "PATCH", - "endpoint": "https://a.klaviyo.com/api/profiles/01GW3PHVY0MTCDGS0A1612HARX", - "headers": { - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "Accept": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "profile", - "attributes": { - "external_id": "user@1", - "email": "test@rudderstack.com", - "first_name": "Test", - "last_name": "Rudderlabs", - "phone_number": "+12 345 578 900", - "title": "Developer", - "organization": "Rudder", - "location": { - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001" - }, - "properties": { - "friend.age": 25, - "friend.names.first": "Alice", - "friend.names.last": "Smith", - "Flagged": false, - "Residence": "Shibuya" - } - }, - "id": "01GW3PHVY0MTCDGS0A1612HARX" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "statusCode": 200 - }, - { - "output": { - "version": "1", - "type": "REST", - "userId": "", - "method": "POST", - "endpoint": "https://a.klaviyo.com/api/profile-subscription-bulk-create-jobs", - "headers": { - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "profile-subscription-bulk-create-job", - "attributes": { - "list_id": "XUepkK", - "subscriptions": [ - { - "email": "test@rudderstack.com", - "phone_number": "+12 345 578 900", - "channels": { - "email": [ - "MARKETING" - ], - "sms": [ - "MARKETING" - ] - } - } - ] - } - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "statusCode": 200 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Profile updation call and subcribe user", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKeyforfailure" - } - }, - "message": { - "type": "identify", - "sentAt": "2021-01-03T17:02:53.195Z", - "userId": "user@1", - "channel": "web", - "context": { - "os": { - "name": "", - "version": "" - }, - "app": { - "name": "RudderLabs JavaScript SDK", - "build": "1.0.0", - "version": "1.1.11", - "namespace": "com.rudderlabs.javascript" - }, - "traits": { - "firstName": "Test", - "lastName": "Rudderlabs", - "email": "test3@rudderstack.com", - "phone": "+12 345 578 900", - "userId": "user@1", - "title": "Developer", - "organization": "Rudder", - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001", - "Flagged": false, - "Residence": "Shibuya", - "properties": { - "listId": "XUepkK", - "subscribe": true, - "consent": [ - "email", - "sms" - ] - } - }, - "locale": "en-US", - "screen": { - "density": 2 - }, - "library": { - "name": "RudderLabs JavaScript SDK", - "version": "1.1.11" - }, - "campaign": {}, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0" - }, - "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", - "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", - "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-03T17:02:53.193Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "error": "{\"message\":\"Failed to create user due to \\\"\\\"\",\"destinationResponse\":\"\\\"\\\"\"}", - "statTags": { - "destType": "KLAVIYO", - "errorCategory": "network", - "errorType": "retryable", - "feature": "processor", - "implementation": "native", - "module": "destination" - }, - "statusCode": 500 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Profile updation call listId is not provided for subscribing the user", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey" - } - }, - "message": { - "type": "identify", - "sentAt": "2021-01-03T17:02:53.195Z", - "userId": "user@1", - "channel": "web", - "context": { - "os": { - "name": "", - "version": "" - }, - "app": { - "name": "RudderLabs JavaScript SDK", - "build": "1.0.0", - "version": "1.1.11", - "namespace": "com.rudderlabs.javascript" - }, - "traits": { - "firstName": "Test", - "lastName": "Rudderlabs", - "email": "test@rudderstack.com", - "phone": "+12 345 578 900", - "userId": "user@1", - "title": "Developer", - "organization": "Rudder", - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001", - "Flagged": false, - "Residence": "Shibuya", - "properties": { - "subscribe": false, - "consent": [ - "email", - "sms" - ] - } - }, - "locale": "en-US", - "screen": { - "density": 2 - }, - "library": { - "name": "RudderLabs JavaScript SDK", - "version": "1.1.11" - }, - "campaign": {}, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0" - }, - "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", - "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", - "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-03T17:02:53.193Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": { - "version": "1", - "type": "REST", - "method": "PATCH", - "endpoint": "https://a.klaviyo.com/api/profiles/01GW3PHVY0MTCDGS0A1612HARX", - "headers": { - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "Accept": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "profile", - "attributes": { - "external_id": "user@1", - "email": "test@rudderstack.com", - "first_name": "Test", - "last_name": "Rudderlabs", - "phone_number": "+12 345 578 900", - "title": "Developer", - "organization": "Rudder", - "location": { - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001" - }, - "properties": { - "Flagged": false, - "Residence": "Shibuya" - } - }, - "id": "01GW3PHVY0MTCDGS0A1612HARX" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {}, - "userId": "" - }, - "statusCode": 200 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Identify call with enforceEmailAsPrimary enabled from UI", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey", - "enforceEmailAsPrimary": true - } - }, - "message": { - "type": "identify", - "sentAt": "2021-01-03T17:02:53.195Z", - "userId": "user@1", - "channel": "web", - "context": { - "os": { - "name": "", - "version": "" - }, - "app": { - "name": "RudderLabs JavaScript SDK", - "build": "1.0.0", - "version": "1.1.11", - "namespace": "com.rudderlabs.javascript" - }, - "traits": { - "firstName": "Test", - "lastName": "Rudderlabs", - "email": "test@rudderstack.com", - "phone": "+12 345 578 900", - "userId": "user@1", - "title": "Developer", - "organization": "Rudder", - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001", - "Flagged": false, - "Residence": "Shibuya", - "properties": { - "listId": "XUepkK", - "subscribe": true, - "consent": [ - "email", - "sms" - ] - } - }, - "locale": "en-US", - "screen": { - "density": 2 - }, - "library": { - "name": "RudderLabs JavaScript SDK", - "version": "1.1.11" - }, - "campaign": {}, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0" - }, - "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", - "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", - "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-03T17:02:53.193Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": - { - "version": "1", - "type": "REST", - "userId": "", - "method": "PATCH", - "endpoint": "https://a.klaviyo.com/api/profiles/01GW3PHVY0MTCDGS0A1612HARX", - "headers": { - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "Accept": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "profile", - "attributes": { - "email": "test@rudderstack.com", - "first_name": "Test", - "last_name": "Rudderlabs", - "phone_number": "+12 345 578 900", - "title": "Developer", - "organization": "Rudder", - "location": { - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001" - }, - "properties": { - "Flagged": false, - "Residence": "Shibuya", - "_id": "user@1" - } - }, - "id": "01GW3PHVY0MTCDGS0A1612HARX" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "statusCode": 200 - }, - { - "output": { - "version": "1", - "type": "REST", - "userId": "", - "method": "POST", - "endpoint": "https://a.klaviyo.com/api/profile-subscription-bulk-create-jobs", - "headers": { - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "profile-subscription-bulk-create-job", - "attributes": { - "list_id": "XUepkK", - "subscriptions": [ - { - "email": "test@rudderstack.com", - "phone_number": "+12 345 578 900", - "channels": { - "email": [ - "MARKETING" - ], - "sms": [ - "MARKETING" - ] - } - } - ] - } - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "statusCode": 200 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Identify call without user custom Properties", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey", - "enforceEmailAsPrimary": false - } - }, - "message": { - "type": "identify", - "sentAt": "2021-01-03T17:02:53.195Z", - "userId": "user@1", - "channel": "web", - "context": { - "os": { - "name": "", - "version": "" - }, - "app": { - "name": "RudderLabs JavaScript SDK", - "build": "1.0.0", - "version": "1.1.11", - "namespace": "com.rudderlabs.javascript" - }, - "traits": { - "firstName": "Test", - "lastName": "Rudderlabs", - "email": "test@rudderstack.com", - "phone": "+12 345 578 900", - "userId": "user@1", - "title": "Developer", - "organization": "Rudder", - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001", - "properties": { - "listId": "XUepkK", - "subscribe": true, - "consent": [ - "email", - "sms" - ] - } - }, - "locale": "en-US", - "screen": { - "density": 2 - }, - "library": { - "name": "RudderLabs JavaScript SDK", - "version": "1.1.11" - }, - "campaign": {}, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0" - }, - "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", - "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", - "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-03T17:02:53.193Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": { - "version": "1", - "type": "REST", - "userId": "", - "method": "PATCH", - "endpoint": "https://a.klaviyo.com/api/profiles/01GW3PHVY0MTCDGS0A1612HARX", - "headers": { - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "Accept": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "profile", - "attributes": { - "email": "test@rudderstack.com", - "first_name": "Test", - "last_name": "Rudderlabs", - "phone_number": "+12 345 578 900", - "external_id": "user@1", - "title": "Developer", - "organization": "Rudder", - "location": { - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001" - } - }, - "id": "01GW3PHVY0MTCDGS0A1612HARX" - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "statusCode": 200 - }, - { - "output": { - "version": "1", - "type": "REST", - "userId": "", - "method": "POST", - "endpoint": "https://a.klaviyo.com/api/profile-subscription-bulk-create-jobs", - "headers": { - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "profile-subscription-bulk-create-job", - "attributes": { - "list_id": "XUepkK", - "subscriptions": [ - { - "email": "test@rudderstack.com", - "phone_number": "+12 345 578 900", - "channels": { - "email": [ - "MARKETING" - ], - "sms": [ - "MARKETING" - ] - } - } - ] - } - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {} - }, - "statusCode": 200 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Identify call without email and phone & enforceEmailAsPrimary enabled from UI", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey", - "enforceEmailAsPrimary": true - } - }, - "message": { - "type": "identify", - "sentAt": "2021-01-03T17:02:53.195Z", - "userId": "user@1", - "channel": "web", - "context": { - "os": { - "name": "", - "version": "" - }, - "app": { - "name": "RudderLabs JavaScript SDK", - "build": "1.0.0", - "version": "1.1.11", - "namespace": "com.rudderlabs.javascript" - }, - "traits": { - "firstName": "Test", - "lastName": "Rudderlabs", - "userId": "user@1", - "title": "Developer", - "organization": "Rudder", - "city": "Tokyo", - "region": "Kanto", - "country": "JP", - "zip": "100-0001", - "Flagged": false, - "Residence": "Shibuya", - "properties": { - "listId": "XUepkK", - "subscribe": true, - "consent": [ - "email", - "sms" - ] - } - }, - "locale": "en-US", - "screen": { - "density": 2 - }, - "library": { - "name": "RudderLabs JavaScript SDK", - "version": "1.1.11" - }, - "campaign": {}, - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0" - }, - "rudderId": "8f8fa6b5-8e24-489c-8e22-61f23f2e364f", - "messageId": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", - "anonymousId": "97c46c81-3140-456d-b2a9-690d70aaca35", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-03T17:02:53.193Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "error": "None of email and phone are present in the payload", - "statTags": { - "destType": "KLAVIYO", - "errorCategory": "dataValidation", - "errorType": "instrumentation", - "feature": "processor", - "implementation": "native", - "module": "destination" - }, - "statusCode": 400 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Screen event call", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey" - } - }, - "message": { - "type": "screen", - "event": "TestEven001", - "sentAt": "2021-01-25T16:12:02.048Z", - "userId": "sajal12", - "channel": "mobile", - "context": { - "os": { - "name": "Android", - "version": "10" - }, - "app": { - "name": "KlaviyoTest", - "build": "1", - "version": "1.0", - "namespace": "com.rudderstack.android.rudderstack.sampleAndroidApp" - }, - "device": { - "id": "9c6bd77ea9da3e68", - "name": "raphaelin", - "type": "android", - "model": "Redmi K20 Pro", - "manufacturer": "Xiaomi" - }, - "locale": "en-IN", - "screen": { - "width": 1080, - "height": 2210, - "density": 440 - }, - "traits": { - "id": "user@1", - "age": "22", - "email": "test@rudderstack.com", - "phone": "9112340375", - "anonymousId": "9c6bd77ea9da3e68" - }, - "library": { - "name": "com.rudderstack.android.sdk.core", - "version": "1.0.2" - }, - "network": { - "wifi": true, - "carrier": "airtel", - "cellular": true, - "bluetooth": false - }, - "timezone": "Asia/Kolkata", - "userAgent": "Dalvik/2.1.0 (Linux; U; Android 10; Redmi K20 Pro MIUI/V12.0.4.0.QFKINXM)" - }, - "rudderId": "b7b24f86-f7bf-46d8-b2b4-ccafc080239c", - "messageId": "1611588776408-ee5a3212-fbf9-4cbb-bbad-3ed0f7c6a2ce", - "properties": { - "PreviouslyVicePresident": true, - "YearElected": 1801, - "VicePresidents": [ - "Aaron Burr", - "George Clinton" - ] - }, - "anonymousId": "9c6bd77ea9da3e68", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-25T15:32:56.409Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://a.klaviyo.com/api/events", - "headers": { - "Accept": "application/json", - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "event", - "attributes": { - "metric": { - "name": "TestEven001" - }, - "properties": { - "PreviouslyVicePresident": true, - "YearElected": 1801, - "VicePresidents": [ - "Aaron Burr", - "George Clinton" - ] - }, - "profile": { - "$email": "test@rudderstack.com", - "$phone_number": "9112340375", - "$id": "sajal12", - "age": "22" - } - } - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {}, - "userId": "" - }, - "statusCode": 200 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Track event call with flatten properties enabled", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey", - "flattenProperties": true - } - }, - "message": { - "type": "track", - "event": "TestEven001", - "sentAt": "2021-01-25T16:12:02.048Z", - "userId": "sajal12", - "channel": "mobile", - "context": { - "os": { - "name": "Android", - "version": "10" - }, - "app": { - "name": "KlaviyoTest", - "build": "1", - "version": "1.0", - "namespace": "com.rudderstack.android.rudderstack.sampleAndroidApp" - }, - "device": { - "id": "9c6bd77ea9da3e68", - "name": "raphaelin", - "type": "android", - "model": "Redmi K20 Pro", - "manufacturer": "Xiaomi" - }, - "locale": "en-IN", - "screen": { - "width": 1080, - "height": 2210, - "density": 440 - }, - "traits": { - "id": "user@1", - "age": "22", - "email": "test@rudderstack.com", - "phone": "9112340375", - "anonymousId": "9c6bd77ea9da3e68", - "plan_details": { - "plan_type": "gold", - "duration": "3 months" - } - }, - "library": { - "name": "com.rudderstack.android.sdk.core", - "version": "1.0.2" - }, - "network": { - "wifi": true, - "carrier": "airtel", - "cellular": true, - "bluetooth": false - }, - "timezone": "Asia/Kolkata", - "userAgent": "Dalvik/2.1.0 (Linux; U; Android 10; Redmi K20 Pro MIUI/V12.0.4.0.QFKINXM)" - }, - "rudderId": "b7b24f86-f7bf-46d8-b2b4-ccafc080239c", - "messageId": "1611588776408-ee5a3212-fbf9-4cbb-bbad-3ed0f7c6a2ce", - "properties": { - "vicePresdentInfo": { - "PreviouslVicePresident": true, - "YearElected": 1801, - "VicePresidents": [ - "AaronBurr", - "GeorgeClinton" - ] - } - }, - "anonymousId": "9c6bd77ea9da3e68", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-25T15:32:56.409Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://a.klaviyo.com/api/events", - "headers": { - "Accept": "application/json", - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "event", - "attributes": { - "metric": { - "name": "TestEven001" - }, - "properties": { - "vicePresdentInfo.PreviouslVicePresident": true, - "vicePresdentInfo.VicePresidents": [ - "AaronBurr", - "GeorgeClinton" - ], - "vicePresdentInfo.YearElected": 1801 - }, - "profile": { - "$email": "test@rudderstack.com", - "$phone_number": "9112340375", - "$id": "sajal12", - "age": "22", - "plan_details.plan_type": "gold", - "plan_details.duration": "3 months" - } - } - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {}, - "userId": "" - }, - "statusCode": 200 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Track event call", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey" - } - }, - "message": { - "type": "track", - "event": "TestEven002", - "sentAt": "2021-01-25T16:12:02.048Z", - "userId": "sajal12", - "channel": "mobile", - "context": { - "os": { - "name": "Android", - "version": "10" - }, - "app": { - "name": "KlaviyoTest", - "build": "1", - "version": "1.0", - "namespace": "com.rudderstack.android.rudderstack.sampleAndroidApp" - }, - "device": { - "id": "9c6bd77ea9da3e68", - "name": "raphaelin", - "type": "android", - "model": "Redmi K20 Pro", - "manufacturer": "Xiaomi" - }, - "locale": "en-IN", - "screen": { - "width": 1080, - "height": 2210, - "density": 440 - }, - "traits": { - "id": "user@1", - "age": "22", - "name": "Test", - "email": "test@rudderstack.com", - "phone": "9112340375", - "anonymousId": "9c6bd77ea9da3e68", - "description": "Sample description" - }, - "library": { - "name": "com.rudderstack.android.sdk.core", - "version": "1.0.2" - }, - "network": { - "wifi": true, - "carrier": "airtel", - "cellular": true, - "bluetooth": false - }, - "timezone": "Asia/Kolkata", - "userAgent": "Dalvik/2.1.0 (Linux; U; Android 10; Redmi K20 Pro MIUI/V12.0.4.0.QFKINXM)" - }, - "rudderId": "b7b24f86-f7bf-46d8-b2b4-ccafc080239c", - "messageId": "1611588776408-ee5a3212-fbf9-4cbb-bbad-3ed0f7c6a2ce", - "properties": { - "PreviouslyVicePresident": true, - "YearElected": 1801, - "VicePresidents": [ - "Aaron Burr", - "George Clinton" - ], - "revenue": 3000 - }, - "anonymousId": "9c6bd77ea9da3e68", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-25T15:32:56.409Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://a.klaviyo.com/api/events", - "headers": { - "Accept": "application/json", - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "event", - "attributes": { - "metric": { - "name": "TestEven002" - }, - "properties": { - "PreviouslyVicePresident": true, - "YearElected": 1801, - "VicePresidents": [ - "Aaron Burr", - "George Clinton" - ] - }, - "profile": { - "$email": "test@rudderstack.com", - "$phone_number": "9112340375", - "$id": "sajal12", - "age": "22", - "name": "Test", - "description": "Sample description" - }, - "value": 3000 - } - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {}, - "userId": "" - }, - "statusCode": 200 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Track event call, with make email or phone as primary identifier toggle on", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey", - "enforceEmailAsPrimary": true - } - }, - "message": { - "type": "track", - "event": "TestEven001", - "sentAt": "2021-01-25T16:12:02.048Z", - "userId": "sajal12", - "channel": "mobile", - "context": { - "os": { - "name": "Android", - "version": "10" - }, - "app": { - "name": "KlaviyoTest", - "build": "1", - "version": "1.0", - "namespace": "com.rudderstack.android.rudderstack.sampleAndroidApp" - }, - "device": { - "id": "9c6bd77ea9da3e68", - "name": "raphaelin", - "type": "android", - "model": "Redmi K20 Pro", - "manufacturer": "Xiaomi" - }, - "locale": "en-IN", - "screen": { - "width": 1080, - "height": 2210, - "density": 440 - }, - "traits": { - "id": "user@1", - "age": "22", - "email": "test@rudderstack.com", - "phone": "9112340375", - "anonymousId": "9c6bd77ea9da3e68" - }, - "library": { - "name": "com.rudderstack.android.sdk.core", - "version": "1.0.2" - }, - "network": { - "wifi": true, - "carrier": "airtel", - "cellular": true, - "bluetooth": false - }, - "timezone": "Asia/Kolkata", - "userAgent": "Dalvik/2.1.0 (Linux; U; Android 10; Redmi K20 Pro MIUI/V12.0.4.0.QFKINXM)" - }, - "rudderId": "b7b24f86-f7bf-46d8-b2b4-ccafc080239c", - "messageId": "1611588776408-ee5a3212-fbf9-4cbb-bbad-3ed0f7c6a2ce", - "properties": { - "PreviouslyVicePresident": true, - "YearElected": 1801, - "VicePresidents": [ - "Aaron Burr", - "George Clinton" - ] - }, - "anonymousId": "9c6bd77ea9da3e68", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-25T15:32:56.409Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://a.klaviyo.com/api/events", - "headers": { - "Accept": "application/json", - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "event", - "attributes": { - "metric": { - "name": "TestEven001" - }, - "properties": { - "PreviouslyVicePresident": true, - "YearElected": 1801, - "VicePresidents": [ - "Aaron Burr", - "George Clinton" - ] - }, - "profile": { - "$email": "test@rudderstack.com", - "$phone_number": "9112340375", - "age": "22", - "_id": "sajal12" - } - } - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {}, - "userId": "" - }, - "statusCode": 200 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Track event call, without email and phone & with (make email or phone as primary identifier) toggle on", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey", - "enforceEmailAsPrimary": true - } - }, - "message": { - "type": "track", - "event": "TestEven001", - "sentAt": "2021-01-25T16:12:02.048Z", - "userId": "sajal12", - "channel": "mobile", - "context": { - "os": { - "name": "Android", - "version": "10" - }, - "app": { - "name": "KlaviyoTest", - "build": "1", - "version": "1.0", - "namespace": "com.rudderstack.android.rudderstack.sampleAndroidApp" - }, - "device": { - "id": "9c6bd77ea9da3e68", - "name": "raphaelin", - "type": "android", - "model": "Redmi K20 Pro", - "manufacturer": "Xiaomi" - }, - "locale": "en-IN", - "screen": { - "width": 1080, - "height": 2210, - "density": 440 - }, - "traits": { - "id": "user@1", - "age": "22", - "anonymousId": "9c6bd77ea9da3e68" - }, - "library": { - "name": "com.rudderstack.android.sdk.core", - "version": "1.0.2" - }, - "network": { - "wifi": true, - "carrier": "airtel", - "cellular": true, - "bluetooth": false - }, - "timezone": "Asia/Kolkata", - "userAgent": "Dalvik/2.1.0 (Linux; U; Android 10; Redmi K20 Pro MIUI/V12.0.4.0.QFKINXM)" - }, - "rudderId": "b7b24f86-f7bf-46d8-b2b4-ccafc080239c", - "messageId": "1611588776408-ee5a3212-fbf9-4cbb-bbad-3ed0f7c6a2ce", - "properties": { - "PreviouslyVicePresident": true, - "YearElected": 1801, - "VicePresidents": [ - "Aaron Burr", - "George Clinton" - ] - }, - "anonymousId": "9c6bd77ea9da3e68", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-25T15:32:56.409Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "error": "None of email and phone are present in the payload", - "statTags": { - "destType": "KLAVIYO", - "errorCategory": "dataValidation", - "errorType": "instrumentation", - "feature": "processor", - "implementation": "native", - "module": "destination" - }, - "statusCode": 400 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "group call", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey" - } - }, - "message": { - "userId": "user123", - "type": "group", - "groupId": "XUepkK", - "traits": { - "subscribe": true - }, - "context": { - "traits": { - "email": "test@rudderstack.com", - "phone": "+12 345 678 900", - "consent": [ - "email" - ] - }, - "ip": "14.5.67.21", - "library": { - "name": "http" - } - }, - "timestamp": "2020-01-21T00:21:34.208Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { "output": { "body": { "FORM": {}, "JSON": { "data": { "attributes": { "list_id": "XUepkK", "subscriptions": [{ "email": "test@rudderstack.com", "phone_number": "+12 345 678 900" }] }, "type": "profile-subscription-bulk-create-job" } }, "JSON_ARRAY": {}, "XML": {} }, "endpoint": "https://a.klaviyo.com/api/profile-subscription-bulk-create-jobs", "files": {}, "headers": { "Accept": "application/json", "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", "Content-Type": "application/json", "revision": "2023-02-22" }, "method": "POST", "params": {}, "type": "REST", "userId": "", "version": "1" }, "statusCode": 200 } - ] - } - } - }, - { - "name": "klaviyo", - "description": "group call without groupId", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey" - } - }, - "message": { - "userId": "user123", - "type": "group", - "groupId": "", - "traits": { - "subscribe": true - }, - "context": { - "traits": { - "email": "test@rudderstack.com", - "phone": "+12 345 678 900", - "consent": "email" - }, - "ip": "14.5.67.21", - "library": { - "name": "http" - } - }, - "timestamp": "2020-01-21T00:21:34.208Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "error": "groupId is a required field for group events", - "statTags": { - "destType": "KLAVIYO", - "errorCategory": "dataValidation", - "errorType": "instrumentation", - "feature": "processor", - "implementation": "native", - "module": "destination" - }, - "statusCode": 400 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "[Error]: Check for unsupported message type", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey" - } - }, - "message": { - "userId": "user123", - "type": "random", - "groupId": "XUepkK", - "traits": { - "subscribe": true - }, - "context": { - "traits": { - "email": "test@rudderstack.com", - "phone": "+12 345 678 900", - "consent": "email" - }, - "ip": "14.5.67.21", - "library": { - "name": "http" - } - }, - "timestamp": "2020-01-21T00:21:34.208Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "error": "Event type random is not supported", - "statTags": { - "destType": "KLAVIYO", - "errorCategory": "dataValidation", - "errorType": "instrumentation", - "feature": "processor", - "implementation": "native", - "module": "destination" - }, - "statusCode": 400 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Track call with Ecom events (Viewed Product)", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey" - } - }, - "message": { - "type": "track", - "event": "product viewed", - "sentAt": "2021-01-25T16:12:02.048Z", - "userId": "sajal12", - "channel": "mobile", - "context": { - "os": { - "name": "Android", - "version": "10" - }, - "app": { - "name": "KlaviyoTest", - "build": "1", - "version": "1.0", - "namespace": "com.rudderstack.android.rudderstack.sampleAndroidApp" - }, - "device": { - "id": "9c6bd77ea9da3e68", - "name": "raphaelin", - "type": "android", - "model": "Redmi K20 Pro", - "manufacturer": "Xiaomi" - }, - "locale": "en-IN", - "screen": { - "width": 1080, - "height": 2210, - "density": 440 - }, - "traits": { - "id": "user@1", - "age": "22", - "name": "Test", - "email": "test@rudderstack.com", - "phone": "9112340375", - "anonymousId": "9c6bd77ea9da3e68", - "description": "Sample description" - }, - "library": { - "name": "com.rudderstack.android.sdk.core", - "version": "1.0.2" - }, - "network": { - "wifi": true, - "carrier": "airtel", - "cellular": true, - "bluetooth": false - }, - "timezone": "Asia/Kolkata", - "userAgent": "Dalvik/2.1.0 (Linux; U; Android 10; Redmi K20 Pro MIUI/V12.0.4.0.QFKINXM)" - }, - "rudderId": "b7b24f86-f7bf-46d8-b2b4-ccafc080239c", - "messageId": "1611588776408-ee5a3212-fbf9-4cbb-bbad-3ed0f7c6a2ce", - "properties": { - "name": "test product", - "product_id": "1114", - "sku": "WINNIePuh12", - "image_url": "http://www.example.com/path/to/product/image.png", - "url": "http://www.example.com/path/to/product", - "brand": "Not for Kids", - "price": 9.9, - "categories": [ - "Fiction", - "Children" - ] - }, - "anonymousId": "9c6bd77ea9da3e68", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-25T15:32:56.409Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://a.klaviyo.com/api/events", - "headers": { - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "Accept": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "event", - "attributes": { - "metric": { - "name": "Viewed Product" - }, - "profile": { - "$email": "test@rudderstack.com", - "$phone_number": "9112340375", - "$id": "sajal12", - "age": "22", - "name": "Test", - "description": "Sample description" - }, - "properties": { - "ProductName": "test product", - "ProductID": "1114", - "SKU": "WINNIePuh12", - "ImageURL": "http://www.example.com/path/to/product/image.png", - "URL": "http://www.example.com/path/to/product", - "Brand": "Not for Kids", - "Price": 9.9, - "Categories": [ - "Fiction", - "Children" - ] - } - } - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {}, - "userId": "" - }, - "statusCode": 200 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Track call with Ecom events (Checkout Started) with enabled flattenProperties", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey", - "flattenProperties": true - } - }, - "message": { - "type": "track", - "event": "checkout started", - "sentAt": "2021-01-25T16:12:02.048Z", - "userId": "sajal12", - "channel": "mobile", - "context": { - "os": { - "name": "Android", - "version": "10" - }, - "app": { - "name": "KlaviyoTest", - "build": "1", - "version": "1.0", - "namespace": "com.rudderstack.android.rudderstack.sampleAndroidApp" - }, - "device": { - "id": "9c6bd77ea9da3e68", - "name": "raphaelin", - "type": "android", - "model": "Redmi K20 Pro", - "manufacturer": "Xiaomi" - }, - "locale": "en-IN", - "screen": { - "width": 1080, - "height": 2210, - "density": 440 - }, - "traits": { - "id": "user@1", - "age": "22", - "name": "Test", - "email": "test@rudderstack.com", - "phone": "9112340375", - "anonymousId": "9c6bd77ea9da3e68", - "description": "Sample description" - }, - "library": { - "name": "com.rudderstack.android.sdk.core", - "version": "1.0.2" - }, - "network": { - "wifi": true, - "carrier": "airtel", - "cellular": true, - "bluetooth": false - }, - "timezone": "Asia/Kolkata", - "userAgent": "Dalvik/2.1.0 (Linux; U; Android 10; Redmi K20 Pro MIUI/V12.0.4.0.QFKINXM)" - }, - "rudderId": "b7b24f86-f7bf-46d8-b2b4-ccafc080239c", - "messageId": "1611588776408-ee5a3212-fbf9-4cbb-bbad-3ed0f7c6a2ce", - "properties": { - "order_id": "1234", - "affiliation": "Apple Store", - "value": 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" - } - ] - }, - "anonymousId": "9c6bd77ea9da3e68", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-25T15:32:56.409Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://a.klaviyo.com/api/events", - "headers": { - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "Accept": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "event", - "attributes": { - "metric": { - "name": "Started Checkout" - }, - "properties": { - "$event_id": "1234", - "$value": 20, - "items[0].ProductID": "123", - "items[0].SKU": "G-32", - "items[0].ProductName": "Monopoly", - "items[0].Quantity": 1, - "items[0].ItemPrice": 14, - "items[0].ProductURL": "https://www.website.com/product/path", - "items[0].ImageURL": "https://www.website.com/product/path.jpg", - "items[1].ProductID": "345", - "items[1].SKU": "F-32", - "items[1].ProductName": "UNO", - "items[1].Quantity": 2, - "items[1].ItemPrice": 3.45 - }, - "profile": { - "$email": "test@rudderstack.com", - "$phone_number": "9112340375", - "$id": "sajal12", - "age": "22", - "name": "Test", - "description": "Sample description" - } - } - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {}, - "userId": "" - }, - "statusCode": 200 - } - ] - } - } - }, - { - "name": "klaviyo", - "description": "Track call with Ecom events (Added to Cart) with properties.products", - "feature": "processor", - "module": "destination", - "version": "v0", - "input": { - "request": { - "body": [ - { - "destination": { - "Config": { - "publicApiKey": "dummyPublicApiKey", - "privateApiKey": "dummyPrivateApiKey" - } - }, - "message": { - "type": "track", - "event": "product added", - "sentAt": "2021-01-25T16:12:02.048Z", - "userId": "sajal12", - "channel": "mobile", - "context": { - "os": { - "name": "Android", - "version": "10" - }, - "app": { - "name": "KlaviyoTest", - "build": "1", - "version": "1.0", - "namespace": "com.rudderstack.android.rudderstack.sampleAndroidApp" - }, - "device": { - "id": "9c6bd77ea9da3e68", - "name": "raphaelin", - "type": "android", - "model": "Redmi K20 Pro", - "manufacturer": "Xiaomi" - }, - "locale": "en-IN", - "screen": { - "width": 1080, - "height": 2210, - "density": 440 - }, - "traits": { - "id": "user@1", - "age": "22", - "name": "Test", - "email": "test@rudderstack.com", - "phone": "9112340375", - "anonymousId": "9c6bd77ea9da3e68", - "description": "Sample description" - }, - "library": { - "name": "com.rudderstack.android.sdk.core", - "version": "1.0.2" - }, - "network": { - "wifi": true, - "carrier": "airtel", - "cellular": true, - "bluetooth": false - }, - "timezone": "Asia/Kolkata", - "userAgent": "Dalvik/2.1.0 (Linux; U; Android 10; Redmi K20 Pro MIUI/V12.0.4.0.QFKINXM)" - }, - "rudderId": "b7b24f86-f7bf-46d8-b2b4-ccafc080239c", - "messageId": "1611588776408-ee5a3212-fbf9-4cbb-bbad-3ed0f7c6a2ce", - "properties": { - "order_id": "1234", - "value": 12.12, - "categories": [ - "Fiction3", - "Children3" - ], - "checkout_url": "http://www.heythere.com", - "item_names": [ - "book1", - "book2" - ], - "products": [ - { - "product_id": "b1pid", - "sku": "123x", - "name": "book1", - "url": "heyther.com", - "price": 12 - }, - { - "product_id": "b2pid", - "sku": "123x", - "name": "book2", - "url": "heyther2.com", - "price": 14 - } - ] - }, - "anonymousId": "9c6bd77ea9da3e68", - "integrations": { - "All": true - }, - "originalTimestamp": "2021-01-25T15:32:56.409Z" - } - } - ] - } - }, - "output": { - "response": { - "status": 200, - "body": [ - { - "output": { - "version": "1", - "type": "REST", - "method": "POST", - "endpoint": "https://a.klaviyo.com/api/events", - "headers": { - "Authorization": "Klaviyo-API-Key dummyPrivateApiKey", - "Content-Type": "application/json", - "Accept": "application/json", - "revision": "2023-02-22" - }, - "params": {}, - "body": { - "JSON": { - "data": { - "type": "event", - "attributes": { - "metric": { - "name": "Added to Cart" - }, - "profile": { - "$email": "test@rudderstack.com", - "$phone_number": "9112340375", - "$id": "sajal12", - "age": "22", - "name": "Test", - "description": "Sample description" - }, - "properties": { - "$value": 12.12, - "AddedItemCategories": [ - "Fiction3", - "Children3" - ], - "ItemNames": [ - "book1", - "book2" - ], - "CheckoutURL": "http://www.heythere.com", - "items": [ - { - "ProductID": "b1pid", - "SKU": "123x", - "ProductName": "book1", - "ItemPrice": 12, - "ProductURL": "heyther.com" - }, - { - "ProductID": "b2pid", - "SKU": "123x", - "ProductName": "book2", - "ItemPrice": 14, - "ProductURL": "heyther2.com" - } - ] - } - } - } - }, - "JSON_ARRAY": {}, - "XML": {}, - "FORM": {} - }, - "files": {}, - "userId": "" - }, - "statusCode": 200 - } - ] - } - } - } -] \ No newline at end of file + ...identifyData, + ...trackTestData, + ...screenTestData, + ...groupTestData, + ...ecomTestData, + ...validationTestData, +]; diff --git a/test/integrations/destinations/klaviyo/processor/ecomTestData.ts b/test/integrations/destinations/klaviyo/processor/ecomTestData.ts new file mode 100644 index 0000000000..fab4cf85ce --- /dev/null +++ b/test/integrations/destinations/klaviyo/processor/ecomTestData.ts @@ -0,0 +1,344 @@ +import { overrideDestination, transformResultBuilder } from '../../../testUtils'; + +const destination = { + Config: { + publicApiKey: 'dummyPublicApiKey', + privateApiKey: 'dummyPrivateApiKey', + }, +}; + +const commonTraits = { + id: 'user@1', + age: '22', + name: 'Test', + email: 'test@rudderstack.com', + phone: '9112340375', + anonymousId: '9c6bd77ea9da3e68', + description: 'Sample description', +}; + +const eventsEndpoint = 'https://a.klaviyo.com/api/events'; + +const commonOutputHeaders = { + Authorization: 'Klaviyo-API-Key dummyPrivateApiKey', + 'Content-Type': 'application/json', + Accept: 'application/json', + revision: '2023-02-22', +}; + +export const ecomTestData = [ + { + id: 'klaviyo-ecom-test-1', + name: 'klaviyo', + description: 'Track call with Ecom events (Viewed Product)', + scenario: 'Business', + successCriteria: + 'Response should contain only event payload and status code should be 200, for the event payload should contain contextual traits and properties in the payload the event name should be Viewed Product and the properties should be mapped to the Klaviyo event properties', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: { + type: 'track', + event: 'product viewed', + sentAt: '2021-01-25T16:12:02.048Z', + userId: 'sajal12', + channel: 'mobile', + context: { + traits: commonTraits, + }, + properties: { + name: 'test product', + product_id: '1114', + sku: 'WINNIePuh12', + image_url: 'http://www.example.com/path/to/product/image.png', + url: 'http://www.example.com/path/to/product', + brand: 'Not for Kids', + price: 9.9, + categories: ['Fiction', 'Children'], + }, + anonymousId: '9c6bd77ea9da3e68', + originalTimestamp: '2021-01-25T15:32:56.409Z', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: eventsEndpoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'event', + attributes: { + metric: { + name: 'Viewed Product', + }, + profile: { + $email: 'test@rudderstack.com', + $phone_number: '9112340375', + $id: 'sajal12', + age: '22', + name: 'Test', + description: 'Sample description', + }, + properties: { + ProductName: 'test product', + ProductID: '1114', + SKU: 'WINNIePuh12', + ImageURL: 'http://www.example.com/path/to/product/image.png', + URL: 'http://www.example.com/path/to/product', + Brand: 'Not for Kids', + Price: 9.9, + Categories: ['Fiction', 'Children'], + }, + }, + }, + }, + userId: '', + }), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'klaviyo-ecom-test-2', + name: 'klaviyo', + description: 'Track call with Ecom events (Checkout Started) with enabled flattenProperties', + scenario: 'Business', + successCriteria: + 'Response should contain only event payload and status code should be 200, for the event payload should contain contextual traits and properties in the payload the event name should be Started Checkout and the properties should be mapped to the Klaviyo event properties with flattened properties', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: overrideDestination(destination, { flattenProperties: true }), + message: { + type: 'track', + event: 'checkout started', + sentAt: '2021-01-25T16:12:02.048Z', + userId: 'sajal12', + channel: 'mobile', + context: { + traits: commonTraits, + }, + properties: { + order_id: '1234', + affiliation: 'Apple Store', + value: 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', + }, + ], + }, + anonymousId: '9c6bd77ea9da3e68', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: eventsEndpoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'event', + attributes: { + metric: { + name: 'Started Checkout', + }, + properties: { + $event_id: '1234', + $value: 20, + 'items[0].ProductID': '123', + 'items[0].SKU': 'G-32', + 'items[0].ProductName': 'Monopoly', + 'items[0].Quantity': 1, + 'items[0].ItemPrice': 14, + 'items[0].ProductURL': 'https://www.website.com/product/path', + 'items[0].ImageURL': 'https://www.website.com/product/path.jpg', + 'items[1].ProductID': '345', + 'items[1].SKU': 'F-32', + 'items[1].ProductName': 'UNO', + 'items[1].Quantity': 2, + 'items[1].ItemPrice': 3.45, + }, + profile: { + $email: 'test@rudderstack.com', + $phone_number: '9112340375', + $id: 'sajal12', + age: '22', + name: 'Test', + description: 'Sample description', + }, + }, + }, + }, + userId: '', + }), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'klaviyo-ecom-test-3', + name: 'klaviyo', + description: 'Track call with Ecom events (Added to Cart) with properties.products', + scenario: 'Business', + successCriteria: + 'Response should contain only event payload and status code should be 200, for the event payload should contain contextual traits and properties in the payload the event name should be Added to Cart and the properties should be mapped to the Klaviyo event properties with flattened properties and products array should be mapped to items array in the payload', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: { + type: 'track', + event: 'product added', + sentAt: '2021-01-25T16:12:02.048Z', + userId: 'sajal12', + channel: 'mobile', + context: { + traits: commonTraits, + }, + rudderId: 'b7b24f86-f7bf-46d8-b2b4-ccafc080239c', + messageId: '1611588776408-ee5a3212-fbf9-4cbb-bbad-3ed0f7c6a2ce', + properties: { + order_id: '1234', + value: 12.12, + categories: ['Fiction3', 'Children3'], + checkout_url: 'http://www.heythere.com', + item_names: ['book1', 'book2'], + products: [ + { + product_id: 'b1pid', + sku: '123x', + name: 'book1', + url: 'heyther.com', + price: 12, + }, + { + product_id: 'b2pid', + sku: '123x', + name: 'book2', + url: 'heyther2.com', + price: 14, + }, + ], + }, + anonymousId: '9c6bd77ea9da3e68', + integrations: { + All: true, + }, + originalTimestamp: '2021-01-25T15:32:56.409Z', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://a.klaviyo.com/api/events', + headers: commonOutputHeaders, + JSON: { + data: { + type: 'event', + attributes: { + metric: { + name: 'Added to Cart', + }, + profile: { + $email: 'test@rudderstack.com', + $phone_number: '9112340375', + $id: 'sajal12', + age: '22', + name: 'Test', + description: 'Sample description', + }, + properties: { + $value: 12.12, + AddedItemCategories: ['Fiction3', 'Children3'], + ItemNames: ['book1', 'book2'], + CheckoutURL: 'http://www.heythere.com', + items: [ + { + ProductID: 'b1pid', + SKU: '123x', + ProductName: 'book1', + ItemPrice: 12, + ProductURL: 'heyther.com', + }, + { + ProductID: 'b2pid', + SKU: '123x', + ProductName: 'book2', + ItemPrice: 14, + ProductURL: 'heyther2.com', + }, + ], + }, + }, + }, + }, + userId: '', + }), + statusCode: 200, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/destinations/klaviyo/processor/groupTestData.ts b/test/integrations/destinations/klaviyo/processor/groupTestData.ts new file mode 100644 index 0000000000..a516a0c7bc --- /dev/null +++ b/test/integrations/destinations/klaviyo/processor/groupTestData.ts @@ -0,0 +1,136 @@ +import { generateGroupPayload, transformResultBuilder } from '../../../testUtils'; + +const destination = { + Config: { + publicApiKey: 'dummyPublicApiKey', + privateApiKey: 'dummyPrivateApiKey', + }, +}; + +const headers = { + Accept: 'application/json', + Authorization: 'Klaviyo-API-Key dummyPrivateApiKey', + 'Content-Type': 'application/json', + revision: '2023-02-22', +}; + +const commonEndpoint = 'https://a.klaviyo.com/api/profile-subscription-bulk-create-jobs'; + +export const groupTestData = [ + { + id: 'klaviyo-group-test-1', + name: 'klaviyo', + description: 'Simple group call', + scenario: 'Business', + successCriteria: + 'Response should contain only group payload and status code should be 200, for the group payload a subscription payload should be present in the final payload with email and phone', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: generateGroupPayload({ + userId: 'user123', + groupId: 'XUepkK', + traits: { + subscribe: true, + }, + context: { + traits: { + email: 'test@rudderstack.com', + phone: '+12 345 678 900', + consent: ['email'], + }, + }, + timestamp: '2020-01-21T00:21:34.208Z', + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + JSON: { + data: { + attributes: { + list_id: 'XUepkK', + subscriptions: [ + { email: 'test@rudderstack.com', phone_number: '+12 345 678 900' }, + ], + }, + type: 'profile-subscription-bulk-create-job', + }, + }, + endpoint: commonEndpoint, + headers: headers, + method: 'POST', + userId: '', + }), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'klaviyo-group-test-2', + name: 'klaviyo', + description: 'Simple group call without groupId', + scenario: 'Business', + successCriteria: + 'Response should contain error message and status code should be 400, as we are not sending groupId in the payload and groupId is a required field for group events', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: generateGroupPayload({ + userId: 'user123', + groupId: '', + traits: { + subscribe: true, + }, + context: { + traits: { + email: 'test@rudderstack.com', + phone: '+12 345 678 900', + consent: 'email', + }, + }, + timestamp: '2020-01-21T00:21:34.208Z', + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: 'groupId is a required field for group events', + statTags: { + destType: 'KLAVIYO', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + }, + statusCode: 400, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/destinations/klaviyo/processor/identifyTestData.ts b/test/integrations/destinations/klaviyo/processor/identifyTestData.ts new file mode 100644 index 0000000000..04d964d1ef --- /dev/null +++ b/test/integrations/destinations/klaviyo/processor/identifyTestData.ts @@ -0,0 +1,551 @@ +import { removeUndefinedAndNullValues } from '@rudderstack/integrations-lib'; +import { + overrideDestination, + generateIndentifyPayload, + transformResultBuilder, +} from '../../../testUtils'; + +const destination = { + Config: { + publicApiKey: 'dummyPublicApiKey', + privateApiKey: 'dummyPrivateApiKey', + }, +}; + +const commonTraits = { + firstName: 'Test', + lastName: 'Rudderlabs', + email: 'test@rudderstack.com', + phone: '+12 345 578 900', + userId: 'user@1', + title: 'Developer', + organization: 'Rudder', + city: 'Tokyo', + region: 'Kanto', + country: 'JP', + zip: '100-0001', + Flagged: false, + Residence: 'Shibuya', + properties: { + listId: 'XUepkK', + subscribe: true, + consent: ['email', 'sms'], + }, +}; + +const commonOutputUserProps = { + external_id: 'user@1', + email: 'test@rudderstack.com', + first_name: 'Test', + last_name: 'Rudderlabs', + phone_number: '+12 345 578 900', + title: 'Developer', + organization: 'Rudder', + location: { + city: 'Tokyo', + region: 'Kanto', + country: 'JP', + zip: '100-0001', + }, + properties: { + Flagged: false, + Residence: 'Shibuya', + }, +}; + +const commonOutputSubscriptionProps = { + list_id: 'XUepkK', + subscriptions: [ + { + email: 'test@rudderstack.com', + phone_number: '+12 345 578 900', + channels: { + email: ['MARKETING'], + sms: ['MARKETING'], + }, + }, + ], +}; + +const commonOutputHeaders = { + Authorization: 'Klaviyo-API-Key dummyPrivateApiKey', + 'Content-Type': 'application/json', + Accept: 'application/json', + revision: '2023-02-22', +}; + +const anonymousId = '97c46c81-3140-456d-b2a9-690d70aaca35'; +const userId = 'user@1'; +const sentAt = '2021-01-03T17:02:53.195Z'; +const originalTimestamp = '2021-01-03T17:02:53.193Z'; +const commonUserUpdateEndpoint = 'https://a.klaviyo.com/api/profiles/01GW3PHVY0MTCDGS0A1612HARX'; +const subscribeEndpoint = 'https://a.klaviyo.com/api/profile-subscription-bulk-create-jobs'; + +export const identifyData = [ + { + id: 'klaviyo-identify-test-1', + name: 'klaviyo', + description: + 'Identify and Subscribe user where the user doesnot exists[mock] (without suppression status code feature from server)', + scenario: 'Business + Framework', + successCriteria: + 'Response should containt two payloads one for profile updation and other for subscription, response status code should be 200', + comment: + 'Reasoning: As suppression status code feature is not enabled from server, so we would expect 2 responses from transformer one for profile updation (deafult behaviour) and other for subscription', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: generateIndentifyPayload({ + context: { + traits: commonTraits, + }, + anonymousId, + userId, + sentAt, + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + userId: '', + method: 'PATCH', + endpoint: commonUserUpdateEndpoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'profile', + attributes: commonOutputUserProps, + id: '01GW3PHVY0MTCDGS0A1612HARX', + }, + }, + }), + statusCode: 200, + }, + { + output: transformResultBuilder({ + method: 'POST', + userId: '', + endpoint: subscribeEndpoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'profile-subscription-bulk-create-job', + attributes: commonOutputSubscriptionProps, + }, + }, + }), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'klaviyo-identify-test-2', + name: 'klaviyo', + description: 'Identify call for with flattenProperties enabled in destination config', + scenario: 'Business', + successCriteria: + 'The profile updation response should contain the flattened properties of the friend object', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: overrideDestination(destination, { flattenProperties: true }), + message: generateIndentifyPayload({ + sentAt, + userId, + context: { + traits: { + ...commonTraits, + friend: { + names: { + first: 'Alice', + last: 'Smith', + }, + age: 25, + }, + }, + }, + anonymousId, + originalTimestamp, + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + userId: '', + method: 'PATCH', + endpoint: commonUserUpdateEndpoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'profile', + id: '01GW3PHVY0MTCDGS0A1612HARX', + attributes: { + ...commonOutputUserProps, + properties: { + ...commonOutputUserProps.properties, + 'friend.age': 25, + 'friend.names.first': 'Alice', + 'friend.names.last': 'Smith', + }, + }, + }, + }, + }), + statusCode: 200, + }, + { + output: transformResultBuilder({ + userId: '', + method: 'POST', + endpoint: subscribeEndpoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'profile-subscription-bulk-create-job', + attributes: commonOutputSubscriptionProps, + }, + }, + }), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'klaviyo-identify-test-3', + name: 'klaviyo', + description: 'Negative Test Case for Profile updation call and subcribe user', + scenario: 'Business + Framework', + successCriteria: + 'Response should contain error message and status code should be 500, as we are getting a network error from klaviyo', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: { + Config: { + publicApiKey: 'dummyPublicApiKey', + privateApiKey: 'dummyPrivateApiKeyforfailure', + }, + }, + message: generateIndentifyPayload({ + sentAt, + userId, + context: { + traits: { + ...commonTraits, + email: 'test3@rudderstack.com', + }, + }, + anonymousId, + originalTimestamp, + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: + '{"message":"Failed to create user due to \\"\\"","destinationResponse":"\\"\\""}', + statTags: { + destType: 'KLAVIYO', + errorCategory: 'network', + errorType: 'retryable', + feature: 'processor', + implementation: 'native', + module: 'destination', + }, + statusCode: 500, + }, + ], + }, + }, + }, + { + id: 'klaviyo-identify-test-4', + name: 'klaviyo', + description: 'Profile create update without subscribing the user', + scenario: 'Business', + successCriteria: + 'Response should contain only profile update payload and status code should be 200 as subscribe is set to false in the payload', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: generateIndentifyPayload({ + sentAt, + userId, + context: { + traits: { + ...commonTraits, + properties: { ...commonTraits.properties, subscribe: false }, + }, + }, + anonymousId, + originalTimestamp, + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'PATCH', + endpoint: commonUserUpdateEndpoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'profile', + attributes: commonOutputUserProps, + id: '01GW3PHVY0MTCDGS0A1612HARX', + }, + }, + userId: '', + }), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'klaviyo-identify-test-5', + name: 'klaviyo', + description: 'Identify call with enforceEmailAsPrimary enabled in destination config', + scenario: 'Business', + successCriteria: + 'Response should contain two payloads one for profile updation and other for subscription, response status code should be 200, for the profile updation payload there should be no external_id field in the payload as enforceEmailAsPrimary is set to true in the destination config and the userId should be mapped to _id field in the properties object', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: overrideDestination(destination, { enforceEmailAsPrimary: true }), + message: generateIndentifyPayload({ + sentAt, + userId, + context: { + traits: commonTraits, + }, + anonymousId, + originalTimestamp, + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + userId: '', + method: 'PATCH', + endpoint: commonUserUpdateEndpoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'profile', + attributes: removeUndefinedAndNullValues({ + ...commonOutputUserProps, + properties: { + ...commonOutputUserProps.properties, + _id: userId, + }, + // remove external_id from the payload + external_id: undefined, + }), + id: '01GW3PHVY0MTCDGS0A1612HARX', + }, + }, + }), + statusCode: 200, + }, + { + output: transformResultBuilder({ + userId: '', + method: 'POST', + endpoint: subscribeEndpoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'profile-subscription-bulk-create-job', + attributes: commonOutputSubscriptionProps, + }, + }, + }), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'klaviyo-identify-test-6', + name: 'klaviyo', + description: 'Identify call without user custom Properties', + scenario: 'Business', + successCriteria: + 'Response should contain two payloads one for profile updation and other for subscription, response status code should be 200, for the profile updation payload does not have any custom properties in the payload', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: destination, + message: generateIndentifyPayload({ + sentAt, + userId, + context: { + traits: removeUndefinedAndNullValues({ + ...commonTraits, + Flagged: undefined, + Residence: undefined, + }), + }, + anonymousId, + originalTimestamp, + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + userId: '', + method: 'PATCH', + endpoint: commonUserUpdateEndpoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'profile', + attributes: removeUndefinedAndNullValues({ + ...commonOutputUserProps, + properties: undefined, + }), + id: '01GW3PHVY0MTCDGS0A1612HARX', + }, + }, + }), + statusCode: 200, + }, + { + output: transformResultBuilder({ + userId: '', + method: 'POST', + endpoint: subscribeEndpoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'profile-subscription-bulk-create-job', + attributes: commonOutputSubscriptionProps, + }, + }, + }), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'klaviyo-identify-test-7', + name: 'klaviyo', + description: 'Identify call without email and phone & enforceEmailAsPrimary enabled from UI', + scenario: 'Business', + successCriteria: + 'Response should contain error message and status code should be 400, as we are not sending email and phone in the payload and enforceEmailAsPrimary is enabled from UI', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: overrideDestination(destination, { enforceEmailAsPrimary: true }), + message: generateIndentifyPayload({ + sentAt, + userId, + context: { + traits: removeUndefinedAndNullValues({ + ...commonTraits, + email: undefined, + phone: undefined, + }), + }, + anonymousId, + originalTimestamp, + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: 'None of email and phone are present in the payload', + statTags: { + destType: 'KLAVIYO', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + }, + statusCode: 400, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/destinations/klaviyo/processor/screenTestData.ts b/test/integrations/destinations/klaviyo/processor/screenTestData.ts new file mode 100644 index 0000000000..b21ffccdd3 --- /dev/null +++ b/test/integrations/destinations/klaviyo/processor/screenTestData.ts @@ -0,0 +1,97 @@ +import { generatePageOrScreenPayload, transformResultBuilder } from '../../../testUtils'; + +const destination = { + Config: { + publicApiKey: 'dummyPublicApiKey', + privateApiKey: 'dummyPrivateApiKey', + }, +}; + +export const screenTestData = [ + { + id: 'klaviyo-screen-test-1', + name: 'klaviyo', + description: 'Screen event call with properties and contextual traits', + scenario: 'Business', + successCriteria: + 'Response should contain only event payload and status code should be 200, for the event payload should contain properties and contextual traits in the payload', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: generatePageOrScreenPayload( + { + event: 'TestEven001', + sentAt: '2021-01-25T16:12:02.048Z', + userId: 'sajal12', + context: { + traits: { + id: 'user@1', + age: '22', + email: 'test@rudderstack.com', + phone: '9112340375', + anonymousId: '9c6bd77ea9da3e68', + }, + }, + properties: { + PreviouslyVicePresident: true, + YearElected: 1801, + VicePresidents: ['Aaron Burr', 'George Clinton'], + }, + anonymousId: '9c6bd77ea9da3e68', + originalTimestamp: '2021-01-25T15:32:56.409Z', + }, + 'screen', + ), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://a.klaviyo.com/api/events', + headers: { + Accept: 'application/json', + Authorization: 'Klaviyo-API-Key dummyPrivateApiKey', + 'Content-Type': 'application/json', + revision: '2023-02-22', + }, + JSON: { + data: { + type: 'event', + attributes: { + metric: { + name: 'TestEven001', + }, + properties: { + PreviouslyVicePresident: true, + YearElected: 1801, + VicePresidents: ['Aaron Burr', 'George Clinton'], + }, + profile: { + $email: 'test@rudderstack.com', + $phone_number: '9112340375', + $id: 'sajal12', + age: '22', + }, + }, + }, + }, + userId: '', + }), + statusCode: 200, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/destinations/klaviyo/processor/trackTestData.ts b/test/integrations/destinations/klaviyo/processor/trackTestData.ts new file mode 100644 index 0000000000..0b30adfb6b --- /dev/null +++ b/test/integrations/destinations/klaviyo/processor/trackTestData.ts @@ -0,0 +1,315 @@ +import { + generateTrackPayload, + overrideDestination, + transformResultBuilder, +} from '../../../testUtils'; + +const destination = { + Config: { + publicApiKey: 'dummyPublicApiKey', + privateApiKey: 'dummyPrivateApiKey', + }, +}; + +const commonTraits = { + id: 'user@1', + age: '22', + anonymousId: '9c6bd77ea9da3e68', +}; + +const commonProps = { + PreviouslVicePresident: true, + YearElected: 1801, + VicePresidents: ['AaronBurr', 'GeorgeClinton'], +}; + +const commonOutputHeaders = { + Accept: 'application/json', + Authorization: 'Klaviyo-API-Key dummyPrivateApiKey', + 'Content-Type': 'application/json', + revision: '2023-02-22', +}; + +const eventEndPoint = 'https://a.klaviyo.com/api/events'; + +export const trackTestData = [ + { + id: 'klaviyo-track-test-1', + name: 'klaviyo', + description: 'Track event call with flatten properties enabled in destination config', + scenario: 'Business', + successCriteria: + 'Response should contain only event payload and status code should be 200, for the event payload should contain flattened properties in the payload', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: overrideDestination(destination, { flattenProperties: true }), + message: generateTrackPayload({ + type: 'track', + event: 'TestEven001', + sentAt: '2021-01-25T16:12:02.048Z', + userId: 'sajal12', + context: { + traits: { + ...commonTraits, + email: 'test@rudderstack.com', + phone: '9112340375', + plan_details: { + plan_type: 'gold', + duration: '3 months', + }, + }, + }, + properties: { + vicePresdentInfo: commonProps, + }, + anonymousId: '9c6bd77ea9da3e68', + originalTimestamp: '2021-01-25T15:32:56.409Z', + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: eventEndPoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'event', + attributes: { + metric: { + name: 'TestEven001', + }, + properties: { + 'vicePresdentInfo.PreviouslVicePresident': true, + 'vicePresdentInfo.VicePresidents': ['AaronBurr', 'GeorgeClinton'], + 'vicePresdentInfo.YearElected': 1801, + }, + profile: { + $email: 'test@rudderstack.com', + $phone_number: '9112340375', + $id: 'sajal12', + age: '22', + 'plan_details.plan_type': 'gold', + 'plan_details.duration': '3 months', + }, + }, + }, + }, + userId: '', + }), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'klaviyo-track-test-2', + name: 'klaviyo', + description: 'Simple track event call', + scenario: 'Business', + successCriteria: + 'Response should contain only event payload and status code should be 200, for the event payload should contain contextual traits and properties in the payload', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: generateTrackPayload({ + type: 'track', + event: 'TestEven002', + sentAt: '2021-01-25T16:12:02.048Z', + userId: 'sajal12', + context: { + traits: { + ...commonTraits, + name: 'Test', + email: 'test@rudderstack.com', + phone: '9112340375', + description: 'Sample description', + }, + }, + properties: { + ...commonProps, + revenue: 3000, + }, + anonymousId: '9c6bd77ea9da3e68', + originalTimestamp: '2021-01-25T15:32:56.409Z', + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: eventEndPoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'event', + attributes: { + metric: { + name: 'TestEven002', + }, + properties: commonProps, + profile: { + $email: 'test@rudderstack.com', + $phone_number: '9112340375', + $id: 'sajal12', + age: '22', + name: 'Test', + description: 'Sample description', + }, + value: 3000, + }, + }, + }, + userId: '', + }), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'klaviyo-track-test-3', + name: 'klaviyo', + description: 'Track event call, with make email or phone as primary identifier toggle on', + scenario: 'Business', + successCriteria: + 'Response should contain only event payload and status code should be 200, for the event payload should contain contextual traits and properties in the payload, and email should be mapped to $email and userId should be mapped to _id', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: overrideDestination(destination, { enforceEmailAsPrimary: true }), + message: generateTrackPayload({ + type: 'track', + event: 'TestEven001', + sentAt: '2021-01-25T16:12:02.048Z', + userId: 'sajal12', + context: { + traits: { + ...commonTraits, + email: 'test@rudderstack.com', + phone: '9112340375', + }, + }, + properties: commonProps, + anonymousId: '9c6bd77ea9da3e68', + originalTimestamp: '2021-01-25T15:32:56.409Z', + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: eventEndPoint, + headers: commonOutputHeaders, + JSON: { + data: { + type: 'event', + attributes: { + metric: { + name: 'TestEven001', + }, + properties: commonProps, + profile: { + $email: 'test@rudderstack.com', + $phone_number: '9112340375', + age: '22', + _id: 'sajal12', + }, + }, + }, + }, + userId: '', + }), + statusCode: 200, + }, + ], + }, + }, + }, + { + id: 'klaviyo-track-test-4', + name: 'klaviyo', + description: + 'Track event call, without email and phone & with (make email or phone as primary identifier) toggle on', + scenario: 'Business', + successCriteria: + 'Response should contain error message and status code should be 400, as we are not sending email and phone in the payload and enforceEmailAsPrimary is enabled from UI', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: overrideDestination(destination, { enforceEmailAsPrimary: true }), + message: generateTrackPayload({ + type: 'track', + event: 'TestEven001', + sentAt: '2021-01-25T16:12:02.048Z', + userId: 'sajal12', + context: { + traits: commonTraits, + }, + properties: commonProps, + anonymousId: '9c6bd77ea9da3e68', + originalTimestamp: '2021-01-25T15:32:56.409Z', + }), + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: 'None of email and phone are present in the payload', + statTags: { + destType: 'KLAVIYO', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + }, + statusCode: 400, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/destinations/klaviyo/processor/validationTestData.ts b/test/integrations/destinations/klaviyo/processor/validationTestData.ts new file mode 100644 index 0000000000..59556cfe5f --- /dev/null +++ b/test/integrations/destinations/klaviyo/processor/validationTestData.ts @@ -0,0 +1,62 @@ +export const validationTestData = [ + { + id: 'klaviyo-validation-test-1', + name: 'klaviyo', + description: '[Error]: Check for unsupported message type', + scenario: 'Framework', + successCriteria: + 'Response should contain error message and status code should be 400, as we are sending a message type which is not supported by Klaviyo destination and the error message should be Event type random is not supported', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: { + Config: { + publicApiKey: 'dummyPublicApiKey', + privateApiKey: 'dummyPrivateApiKey', + }, + }, + message: { + userId: 'user123', + type: 'random', + groupId: 'XUepkK', + traits: { + subscribe: true, + }, + context: { + traits: { + email: 'test@rudderstack.com', + phone: '+12 345 678 900', + consent: 'email', + }, + }, + timestamp: '2020-01-21T00:21:34.208Z', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: 'Event type random is not supported', + statTags: { + destType: 'KLAVIYO', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + }, + statusCode: 400, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/destinations/klaviyo/router/data.ts b/test/integrations/destinations/klaviyo/router/data.ts index 0fb735d6bf..61d18b1ee1 100644 --- a/test/integrations/destinations/klaviyo/router/data.ts +++ b/test/integrations/destinations/klaviyo/router/data.ts @@ -1,7 +1,9 @@ export const data = [ { name: 'klaviyo', - description: 'Test 0', + description: 'Basic Router Test to test multiple payloads', + scenario: 'Framework', + successCriteria: 'All the subscription events should be batched', feature: 'router', module: 'destination', version: 'v0', diff --git a/test/integrations/testUtils.ts b/test/integrations/testUtils.ts index f5be8107ed..136a07da51 100644 --- a/test/integrations/testUtils.ts +++ b/test/integrations/testUtils.ts @@ -4,7 +4,10 @@ import { MockHttpCallsData, TestCaseData } from './testTypes'; import MockAdapter from 'axios-mock-adapter'; import isMatch from 'lodash/isMatch'; import { OptionValues } from 'commander'; +import { removeUndefinedAndNullValues } from '@rudderstack/integrations-lib'; +const generateAlphanumericId = (size = 36) => + [...Array(size)].map(() => ((Math.random() * size) | 0).toString(size)).join(''); export const getTestDataFilePaths = (dirPath: string, opts: OptionValues): string[] => { const globPattern = join(dirPath, '**', 'data.ts'); let testFilePaths = globSync(globPattern); @@ -74,3 +77,212 @@ export const overrideDestination = (destination, overrideConfigValues) => { Config: { ...destination.Config, ...overrideConfigValues }, }); }; + +export const generateIndentifyPayload = (parametersOverride: any) => { + const payload = { + type: 'identify', + sentAt: parametersOverride.sentAt || '2021-01-03T17:02:53.195Z', + userId: parametersOverride.userId || 'default-userId', + channel: 'web', + context: { + externalId: parametersOverride.externalId || [], + os: { name: '', version: '1.12.3' }, + app: { + name: 'RudderLabs JavaScript SDK', + build: '1.0.0', + version: '1.1.11', + namespace: 'com.rudderlabs.javascript', + }, + traits: parametersOverride.context.traits, + locale: 'en-US', + device: { token: 'token', id: 'id', type: 'ios' }, + screen: { density: 2 }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.1.11' }, + campaign: {}, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0', + }, + traits: parametersOverride.traits, + integrations: parametersOverride.integrations || {}, + rudderId: parametersOverride.rudderId || generateAlphanumericId(36), + messageId: parametersOverride.messageId || generateAlphanumericId(36), + anonymousId: parametersOverride.anonymousId || 'default-anonymousId', + originalTimestamp: parametersOverride.originalTimestamp || '2021-01-03T17:02:53.193Z', + }; + + return removeUndefinedAndNullValues(payload); +}; + +export const generateTrackPayload = (parametersOverride: any) => { + const payload = { + type: 'track', + sentAt: parametersOverride.sentAt || '2021-01-03T17:02:53.195Z', + userId: parametersOverride.userId || 'default-user-id', + channel: 'web', + context: { + externalId: parametersOverride.externalId || [], + os: { name: '', version: '1.12.3' }, + app: { + name: 'RudderLabs JavaScript SDK', + build: '1.0.0', + version: '1.1.11', + namespace: 'com.rudderlabs.javascript', + }, + traits: parametersOverride.context.traits, + locale: 'en-US', + device: { token: 'token', id: 'id', type: 'ios' }, + screen: { density: 2 }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.1.11' }, + campaign: {}, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0', + }, + rudderId: parametersOverride.rudderId || generateAlphanumericId(36), + messageId: parametersOverride.messageId || generateAlphanumericId(36), + anonymousId: parametersOverride.anonymousId || 'default-anonymousId', + originalTimestamp: parametersOverride.originalTimestamp || '2021-01-03T17:02:53.193Z', + timestamp: parametersOverride.timestamp, + event: parametersOverride.event || 'test-event', + integrations: parametersOverride.integrations || {}, + properties: parametersOverride.properties || {}, + }; + + return removeUndefinedAndNullValues(payload); +}; + +export const generatePageOrScreenPayload = (parametersOverride: any, eventType: string) => { + const payload = { + channel: 'web', + userId: parametersOverride.userId || 'default-userId', + rudderId: parametersOverride.rudderId || generateAlphanumericId(36), + originalTimestamp: parametersOverride.originalTimestamp || '2022-04-26T05:17:09Z', + timestamp: parametersOverride.timestamp, + context: removeUndefinedAndNullValues({ + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + device: { + adTrackingEnabled: 'false', + advertisingId: 'T0T0T072-5e28-45a1-9eda-ce22a3e36d1a', + id: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', + manufacturer: 'Google', + model: 'AOSP on IA Emulator', + name: 'generic_x86_arm', + type: 'ios', + attTrackingStatus: 3, + }, + ip: '0.0.0.0', + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + locale: 'en-US', + os: { + name: 'iOS', + version: '14.4.1', + }, + screen: { + density: 2, + }, + traits: parametersOverride.context.traits, + externalId: parametersOverride.externalId || [], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', + }), + event: parametersOverride.event, + anonymousId: parametersOverride.anonymousId || 'default-anonymousId', + properties: parametersOverride.properties, + type: eventType || 'page', + integrations: parametersOverride.integrations || {}, + sentAt: '2022-04-20T15:20:57Z', + }; + return removeUndefinedAndNullValues(payload); +}; + +export const generateGroupPayload = (parametersOverride: any) => { + const payload = { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + 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', + locale: 'en-US', + ip: '0.0.0.0', + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, + traits: parametersOverride.context.traits || {}, + }, + messageId: parametersOverride.messageId || generateAlphanumericId(36), + session_id: parametersOverride.session_id || generateAlphanumericId(36), + originalTimestamp: parametersOverride.originalTimestamp || '2019-10-14T09:03:17.562Z', + timestamp: parametersOverride.timestamp, + anonymousId: parametersOverride.anonymousId || generateAlphanumericId(36), + userId: parametersOverride.userId || 'default-user-id', + type: 'group', + groupId: parametersOverride.groupId, + traits: parametersOverride.traits || {}, + integrations: parametersOverride.integrations || {}, + sentAt: parametersOverride.sentAt || '2019-10-14T09:03:22.563Z', + }; + return payload; +}; + +export const transformResultBuilder = (matchData) => { + return removeUndefinedAndNullValues({ + version: '1', + type: 'REST', + userId: matchData.userId, + method: matchData.method || 'POST', + endpoint: matchData.endpoint || '', + headers: matchData.headers || {}, + params: matchData.params || {}, + body: { + JSON: matchData.JSON || {}, + JSON_ARRAY: matchData.JSON_ARRAY || {}, + XML: matchData.XML || {}, + FORM: matchData.FORM || {}, + }, + files: matchData.files || {}, + }); +}; + +export const compareObjects = (obj1, obj2, logPrefix = '', differences: string[] = []) => { + for (const key in obj1) { + if (obj1.hasOwnProperty(key)) { + const fullKey = logPrefix ? `${logPrefix}.${key}` : key; + + if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') { + compareObjects(obj1[key], obj2[key], fullKey, differences); + } else if (obj1[key] !== obj2[key]) { + differences.push(fullKey); + } + } + } + + // Check for keys in obj2 that are not present in obj1 + for (const key in obj2) { + if (obj2.hasOwnProperty(key) && !obj1.hasOwnProperty(key)) { + const fullKey = logPrefix ? `${logPrefix}.${key}` : key; + differences.push(fullKey); + } + } + + return differences; +}; diff --git a/test/test_reporter/reporter.ts b/test/test_reporter/reporter.ts new file mode 100644 index 0000000000..6c7a4957f4 --- /dev/null +++ b/test/test_reporter/reporter.ts @@ -0,0 +1,426 @@ +import fs from 'fs'; +import { compareObjects } from '../integrations/testUtils'; + +// Step 1: Generate the template HTML +const generateHTMLTemplate = () => ` + + + + + + Test Report + + + + + +

Test Report

+ + + + + + + + + + + + + + + + + +
Integration NameIdDescriptionSuccess CriteriaScenarioModuleFeatureAPI VersionTest InputTest OutputExpected OutputDiff KeysTest Status
+ + + +`; + +// Step 2: Iterate through each test data element and add it to the HTML template +const generateHTMLContent = (testData, expectedData, testStatus) => { + let htmlContent = ''; + let diffKeys: string[] = []; + diffKeys = compareObjects(testData.output.response.body, expectedData); + htmlContent += ` + + ${testData.name} + ${testData.id} + ${testData.description} + ${testData.successCriteria} + ${testData.scenario} + ${testData.module} + ${testData.feature} + ${testData.version} + ${JSON.stringify(testData.input.request.body)} + ${JSON.stringify(testData.output.response.body)} + ${JSON.stringify(expectedData)} + ${JSON.stringify(diffKeys)} + ${testStatus} + + + `; + + return htmlContent; +}; + +// Example test data +const testData = [ + // ... Your test data here + { + name: 'active_campaign', + description: 'Test 0', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination: { + Config: { + apiKey: 'dummyApiToken', + apiUrl: 'https://active.campaigns.rudder.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + }, + metadata: { + jobId: 2, + }, + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + 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', + locale: 'en-US', + ip: '0.0.0.0', + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, + }, + messageId: '84e26acc-56a5-4835-8233-591137fca468', + session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', + originalTimestamp: '2019-10-14T09:03:17.562Z', + anonymousId: 'anon_id', + userId: '123456', + type: 'identify', + traits: { + anonymousId: 'anon_id', + email: 'jamesDoe@gmail.com', + firstName: 'James', + lastName: 'Doe', + phone: '92374162212', + tags: ['Test_User', 'Interested_User', 'DIY_Hobby'], + fieldInfo: { + Office: 'Trastkiv', + Country: 'Russia', + Likes: ['Potato', 'Onion'], + Random: 'random', + }, + lists: [ + { + id: 2, + status: 'subscribe', + }, + { + id: 3, + status: 'unsubscribe', + }, + { + id: 3, + status: 'unsubscribexyz', + }, + ], + address: { + city: 'kolkata', + country: 'India', + postalCode: 789223, + state: 'WB', + street: '', + }, + }, + integrations: { + All: true, + }, + sentAt: '2019-10-14T09:03:22.563Z', + }, + }, + { + destination: { + Config: { + apiKey: 'dummyApiToken', + apiUrl: 'https://active.campaigns.rudder.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + }, + metadata: { + jobId: 2, + }, + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { + email: 'jamesDoe@gmail.com', + anonymousId: '12345', + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + 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', + locale: 'en-US', + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, + }, + request_ip: '1.1.1.1', + type: 'page', + messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', + session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', + originalTimestamp: '2019-10-14T11:15:18.299Z', + anonymousId: '00000000000000000000000000', + userId: '12345', + properties: { + name: 'ApplicationLoaded', + path: '/test', + referrer: 'Rudder', + search: 'abc', + title: 'Test Page', + url: 'https://www.rudderlabs.com', + }, + integrations: { + All: true, + }, + sentAt: '2019-10-14T11:15:53.296Z', + }, + }, + ], + destType: 'active_campaign', + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + body: { + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + JSON: { + contact: { + email: 'jamesDoe@gmail.com', + firstName: 'James', + lastName: 'Doe', + phone: '92374162212', + fieldValues: [ + { + field: '0', + value: 'Trastkiv', + }, + { + field: '1', + value: 'Russia', + }, + { + field: '3', + value: '||Potato||Onion||', + }, + { + field: '4', + value: 'random', + }, + ], + }, + }, + }, + type: 'REST', + files: {}, + method: 'POST', + params: {}, + headers: { + 'Api-Token': 'dummyApiToken', + 'Content-Type': 'application/json', + }, + version: '1', + endpoint: 'https://active.campaigns.rudder.com/api/3/contact/sync', + }, + metadata: [ + { + jobId: 2, + }, + ], + batched: false, + statusCode: 200, + destination: { + Config: { + apiKey: 'dummyApiToken', + apiUrl: 'https://active.campaigns.rudder.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + }, + }, + { + batchedRequest: { + body: { + XML: {}, + FORM: {}, + JSON_ARRAY: {}, + JSON: { + contact: { + email: 'jamesDoe@gmail.com', + firstName: 'James', + lastName: 'Doe', + phone: '92374162212', + fieldValues: [ + { + field: '0', + value: 'Trastkiv', + }, + { + field: '1', + value: 'Russia', + }, + { + field: '3', + value: '||Potato||Onion||', + }, + { + field: '4', + value: 'random', + }, + ], + }, + }, + }, + type: 'REST', + files: {}, + method: 'POST', + params: {}, + headers: { + 'Api-Token': 'dummyApiToken', + 'Content-Type': 'application/json', + }, + version: '1', + endpoint: 'https://active.campaigns.rudder.com/api/3/contact/sync', + }, + metadata: [ + { + jobId: 2, + }, + ], + batched: false, + statusCode: 200, + destination: { + Config: { + apiKey: 'dummyApiToken', + apiUrl: 'https://active.campaigns.rudder.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + }, + }, + ], + }, + }, + }, + }, +]; + +// Step 3: Write the HTML report to a file +export const generateTestReport = (testData, output, result) => { + fs.readFile('test_reports/test-report.html', 'utf8', (err, htmlTemplate) => { + if (err) { + console.error(err); + return; + } + + const htmlContent = generateHTMLContent(testData, output, result); + const finalHTML = htmlTemplate.replace('', htmlContent); + fs.writeFileSync('test_reports/test-report.html', finalHTML); + }); +}; + +export const initaliseReport = () => { + const htmlTemplate = generateHTMLTemplate(); + fs.writeFileSync('test_reports/test-report.html', htmlTemplate); + console.log('Report initialised'); +};