From fbcc53a38cfabbd1b4c78a3c40c0c67556eebd12 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Sun, 18 Aug 2024 21:03:01 +0530 Subject: [PATCH 01/22] feat: onboard shopify to v1, initial commit --- src/v1/sources/shopify/config.js | 123 +++++++ .../sources/shopify/data/identifyMapping.json | 112 +++++++ .../shopify/data/lineItemsMapping.json | 26 ++ src/v1/sources/shopify/data/mapping.json | 10 + .../sources/shopify/data/productMapping.json | 18 ++ src/v1/sources/shopify/shopify.util.test.js | 60 ++++ .../shopify/shopify_redis.util.test.js | 289 +++++++++++++++++ src/v1/sources/shopify/transform.js | 300 ++++++++++++++++++ src/v1/sources/shopify/util.js | 284 +++++++++++++++++ 9 files changed, 1222 insertions(+) create mode 100644 src/v1/sources/shopify/config.js create mode 100644 src/v1/sources/shopify/data/identifyMapping.json create mode 100644 src/v1/sources/shopify/data/lineItemsMapping.json create mode 100644 src/v1/sources/shopify/data/mapping.json create mode 100644 src/v1/sources/shopify/data/productMapping.json create mode 100644 src/v1/sources/shopify/shopify.util.test.js create mode 100644 src/v1/sources/shopify/shopify_redis.util.test.js create mode 100644 src/v1/sources/shopify/transform.js create mode 100644 src/v1/sources/shopify/util.js diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js new file mode 100644 index 0000000000..b8b3cde284 --- /dev/null +++ b/src/v1/sources/shopify/config.js @@ -0,0 +1,123 @@ +const path = require('path'); +const fs = require('fs'); +const { EventType } = require('../../../constants'); + +const IDENTIFY_TOPICS = { + CUSTOMERS_CREATE: 'customers_create', + CUSTOMERS_UPDATE: 'customers_update', +}; + +// Mapping from shopify_topic name for ecom events +const ECOM_TOPICS = { + CHECKOUTS_CREATE: 'checkouts_create', + CHECKOUTS_UPDATE: 'checkouts_update', + ORDERS_UPDATE: 'orders_updated', + ORDERS_CREATE: 'orders_create', +}; + +const RUDDER_ECOM_MAP = { + checkouts_create: 'Checkout Started', + checkouts_update: 'Checkout Updated', + orders_updated: 'Order Updated', + orders_create: 'Order Created', +}; +const SHOPIFY_ADMIN_ONLY_EVENTS = ['Order Deleted', 'Fulfillments Create', 'Fulfillments Update']; + +const SHOPIFY_TRACK_MAP = { + checkouts_delete: 'Checkout Deleted', + carts_update: 'Cart Update', + customers_enable: 'Customer Enabled', + customers_disable: 'Customer Disabled', + fulfillments_create: 'Fulfillments Create', + fulfillments_update: 'Fulfillments Update', + orders_delete: 'Order Deleted', + orders_edited: 'Order Edited', + orders_cancelled: 'Order Cancelled', + orders_fulfilled: 'Order Fulfilled', + orders_paid: 'Order Paid', + orders_partially_fullfilled: 'Order Partially Fulfilled', +}; + +const identifyMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'data', 'identifyMapping.json')), +); + +const productMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'data', 'productMapping.json')), +); + +const lineItemsMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'data', 'lineItemsMapping.json')), +); + +const INTEGERATION = 'SHOPIFY'; + +const MAPPING_CATEGORIES = { + [EventType.IDENTIFY]: identifyMappingJSON, + [EventType.TRACK]: productMappingJSON, +}; + +const LINE_ITEM_EXCLUSION_FIELDS = [ + 'product_id', + 'sku', + 'name', + 'price', + 'vendor', + 'quantity', + 'variant_id', + 'variant_price', + 'variant_title', +]; + +const PRODUCT_MAPPING_EXCLUSION_FIELDS = [ + 'id', + 'total_price', + 'total_tax', + 'currency', + 'line_items', + 'customer', + 'shipping_address', + 'billing_address', +]; + +/** + * list of events name supported as generic track calls + * track events not belonging to this list or ecom events will + * be discarded. + */ +const SUPPORTED_TRACK_EVENTS = [ + 'checkouts_delete', + 'checkouts_update', + 'customers_disable', + 'customers_enable', + 'carts_update', + 'fulfillments_create', + 'fulfillments_update', + 'orders_create', + 'orders_delete', + 'orders_edited', + 'orders_cancelled', + 'orders_fulfilled', + 'orders_paid', + 'orders_partially_fullfilled', +]; + +const maxTimeToIdentifyRSGeneratedCall = 10000; // in ms +const useRedisDatabase = process.env.USE_REDIS_DB === 'true' || false; + +module.exports = { + ECOM_TOPICS, + IDENTIFY_TOPICS, + INTEGERATION, + MAPPING_CATEGORIES, + RUDDER_ECOM_MAP, + lineItemsMappingJSON, + productMappingJSON, + LINE_ITEM_EXCLUSION_FIELDS, + PRODUCT_MAPPING_EXCLUSION_FIELDS, + SUPPORTED_TRACK_EVENTS, + SHOPIFY_TRACK_MAP, + useRedisDatabase, + SHOPIFY_ADMIN_ONLY_EVENTS, + maxTimeToIdentifyRSGeneratedCall, +}; diff --git a/src/v1/sources/shopify/data/identifyMapping.json b/src/v1/sources/shopify/data/identifyMapping.json new file mode 100644 index 0000000000..0367267502 --- /dev/null +++ b/src/v1/sources/shopify/data/identifyMapping.json @@ -0,0 +1,112 @@ +[ + { + "sourceKeys": "id", + "destKeys": "userId" + }, + { + "sourceKeys": "email", + "destKeys": "traits.email" + }, + + { + "sourceKeys": "first_name", + "destKeys": "traits.firstName" + }, + + { + "sourceKeys": "last_name", + "destKeys": "traits.lastName" + }, + + { + "sourceKeys": "phone", + "destKeys": "traits.phone" + }, + + { + "sourceKeys": "addresses", + "destKeys": "traits.addressList" + }, + + { + "sourceKeys": "default_address", + "destKeys": "traits.address" + }, + + { + "sourceKeys": "shipping_address", + "destKeys": "traits.shippingAddress" + }, + + { + "sourceKeys": "billing_address", + "destKeys": "traits.billingAddress" + }, + + { + "sourceKeys": "accepts_marketing", + "destKeys": "traits.acceptsMarketing" + }, + + { + "sourceKeys": "orders_count", + "destKeys": "traits.orderCount" + }, + + { + "sourceKeys": "state", + "destKeys": "traits.state" + }, + { + "sourceKeys": "total_spent", + "destKeys": "traits.totalSpent" + }, + { + "sourceKeys": "note", + "destKeys": "traits.note" + }, + { + "sourceKeys": "verified_email", + "destKeys": "traits.verifiedEmail" + }, + { + "sourceKeys": "multipass_identifier", + "destKeys": "traits.multipassIdentifier" + }, + { + "sourceKeys": "tax_exempt", + "destKeys": "traits.taxExempt" + }, + { + "sourceKeys": "tags", + "destKeys": "traits.tags" + }, + { + "sourceKeys": "last_order_name", + "destKeys": "traits.lastOrderName" + }, + { + "sourceKeys": "currency", + "destKeys": "traits.currency" + }, + { + "sourceKeys": "marketing_opt_in_level", + "destKeys": "traits.marketingOptInLevel" + }, + { + "sourceKeys": "tax_exemptions", + "destKeys": "traits.taxExemptions" + }, + { + "sourceKeys": "sms_marketing_consent", + "destKeys": "traits.smsMarketingConsent" + }, + { + "sourceKeys": "admin_graphql_api_id", + "destKeys": "traits.adminGraphqlApiId" + }, + { + "sourceKeys": "accepts_marketing_updated_at", + "destKeys": "traits.acceptsMarketingUpdatedAt" + } +] diff --git a/src/v1/sources/shopify/data/lineItemsMapping.json b/src/v1/sources/shopify/data/lineItemsMapping.json new file mode 100644 index 0000000000..eb6e41834e --- /dev/null +++ b/src/v1/sources/shopify/data/lineItemsMapping.json @@ -0,0 +1,26 @@ +[ + { + "sourceKeys": "product_id", + "destKey": "product_id" + }, + { + "sourceKeys": "sku", + "destKey": "sku" + }, + { + "sourceKeys": "name", + "destKey": "title" + }, + { + "sourceKeys": "price", + "destKey": "price" + }, + { + "sourceKeys": "vendor", + "destKey": "brand" + }, + { + "sourceKeys": "quantity", + "destKey": "quantity" + } +] diff --git a/src/v1/sources/shopify/data/mapping.json b/src/v1/sources/shopify/data/mapping.json new file mode 100644 index 0000000000..6c268ef13c --- /dev/null +++ b/src/v1/sources/shopify/data/mapping.json @@ -0,0 +1,10 @@ +[ + { + "sourceKeys": "line_items", + "destKeys": "products" + }, + { + "sourceKeys": "id", + "destKeys": "properties.order_id" + } +] diff --git a/src/v1/sources/shopify/data/productMapping.json b/src/v1/sources/shopify/data/productMapping.json new file mode 100644 index 0000000000..1cf75a44c4 --- /dev/null +++ b/src/v1/sources/shopify/data/productMapping.json @@ -0,0 +1,18 @@ +[ + { + "sourceKeys": "id", + "destKey": "order_id" + }, + { + "sourceKeys": "total_price", + "destKey": "value" + }, + { + "sourceKeys": "total_tax", + "destKey": "tax" + }, + { + "sourceKeys": "currency", + "destKey": "currency" + } +] diff --git a/src/v1/sources/shopify/shopify.util.test.js b/src/v1/sources/shopify/shopify.util.test.js new file mode 100644 index 0000000000..d058db36b5 --- /dev/null +++ b/src/v1/sources/shopify/shopify.util.test.js @@ -0,0 +1,60 @@ +const { getShopifyTopic } = require('./util'); +jest.mock('ioredis', () => require('../../../../test/__mocks__/redis')); +describe('Shopify Utils Test', () => { + describe('Fetching Shopify Topic Test Cases', () => { + it('Invalid Topic Test', () => { + const input = { + query_parameters: {}, + }; + const expectedOutput = { + error: 'Invalid topic in query_parameters', + }; + try { + getShopifyTopic(input); + } catch (error) { + expect(error.message).toEqual(expectedOutput.error); + } + }); + + it('No Topic Found Test', () => { + const input = { + query_parameters: { + topic: [], + }, + }; + const expectedOutput = { + error: 'Topic not found', + }; + try { + getShopifyTopic(input); + } catch (error) { + expect(error.message).toEqual(expectedOutput.error); + } + }); + + it('Successfully fetched topic Test', () => { + const input = { + query_parameters: { + topic: [''], + }, + }; + const expectedOutput = ''; + const actualOutput = getShopifyTopic(input); + expect(actualOutput).toEqual(expectedOutput); + }); + + it('Empty Query Params Test', () => { + const input = { + randomKey: 'randomValue', + }; + const expectedOutput = { + error: 'Query_parameters is missing', + }; + try { + getShopifyTopic(input); + } catch (error) { + expect(error.message).toEqual(expectedOutput.error); + } + }); + }); +}); diff --git a/src/v1/sources/shopify/shopify_redis.util.test.js b/src/v1/sources/shopify/shopify_redis.util.test.js new file mode 100644 index 0000000000..fb99837932 --- /dev/null +++ b/src/v1/sources/shopify/shopify_redis.util.test.js @@ -0,0 +1,289 @@ +const { getAnonymousIdAndSessionId, checkAndUpdateCartItems } = require('./util'); +jest.mock('ioredis', () => require('../../../../test/__mocks__/redis')); +const metricMetadata = { + writeKey: 'dummyKey', + source: 'src', +}; +describe('Shopify Utils Test', () => { + describe('Check for valid cart update event test cases', () => { + it('Event containing token and nothing is retreived from redis and less than req. time difference between created_at and uadated_at', async () => { + const input = { + query_parameters: { + topic: ['carts_update'], + }, + id: 'cartTokenTest1', + line_items: [], + note: null, + updated_at: '2023-02-10T12:05:07.251Z', + created_at: '2023-02-10T12:05:04.402Z', + }; + const expectedOutput = false; + const output = await checkAndUpdateCartItems(input, null, metricMetadata); + expect(output).toEqual(expectedOutput); + }); + it('Event containing token and nothing is retreived from redis', async () => { + const input = { + token: 'token_not_in_redis', + line_items: [ + { + prod_id: 'prod_1', + quantity: 1, + }, + ], + }; + const expectedOutput = true; + const output = await checkAndUpdateCartItems(input, null, metricMetadata); + expect(output).toEqual(expectedOutput); + }); + + it('Event contain id for cart_update event and isValid', async () => { + const input = { + id: 'shopify_test2', + line_items: [ + { + prod_id: 'prod_1', + quantity: 1, + }, + ], + }; + + const expectedOutput = true; + const output = await checkAndUpdateCartItems(input, null, metricMetadata); + expect(output).toEqual(expectedOutput); + }); + + it('Event contain id for cart_update event and isInValid', async () => { + const input = { + id: 'shopify_test_duplicate_cart', + line_items: [ + { + prod_id: 'prod_1', + quantity: 1, + }, + ], + }; + + const expectedOutput = false; + const output = await checkAndUpdateCartItems(input, null, metricMetadata); + expect(output).toEqual(expectedOutput); + }); + + it('Valid Cart Event but not able to set data due to redis error', async () => { + const input = { + id: 'shopify_test_set_redis_error', + line_items: [ + { + prod_id: 'prod_1', + quantity: 1, + }, + ], + }; + + const expectedOutput = true; + const output = await checkAndUpdateCartItems(input, null, metricMetadata); + expect(output).toEqual(expectedOutput); + }); + }); + + describe(' Test Cases -> set AnonymousId and sessionId without using Redis', () => { + it('Order Updated -> Properties containing cartToken', async () => { + const input = { + event: 'Order Updated', + properties: { + cart_token: '123', + }, + }; + const expectedOutput = { + anonymousId: 'b9b6607d-6974-594f-8e99-ac3de71c4d89', + sessionId: undefined, + }; + const output = await getAnonymousIdAndSessionId(input, {}, null); + expect(output).toEqual(expectedOutput); + }); + + it('Cart Update -> Properties contain `id` ', async () => { + const input = { + event: 'Cart Update', + properties: { + id: '123', + }, + }; + + const expectedOutput = { + anonymousId: 'b9b6607d-6974-594f-8e99-ac3de71c4d89', + sessionId: undefined, + }; + const output = await getAnonymousIdAndSessionId(input, {}, null); + + expect(output).toEqual(expectedOutput); + }); + + it('Customer event -> random AnonymousId', async () => { + const input = { + event: 'Customer Enabled', + properties: {}, + }; + + const output = await getAnonymousIdAndSessionId(input, {}, null); + expect(output).toEqual(output); // since it will be random + }); + + it('Order Delete -> No anonymousId is there', async () => { + const input = { + event: 'Order Deleted', + properties: { + order_id: 'Order_ID', + }, + }; + const expectedOutput = { anonymousId: undefined, sessionId: undefined }; + const output = await getAnonymousIdAndSessionId(input, {}, null); + expect(output).toEqual(expectedOutput); + }); + + it('Checkout Create -> rudderAnonymousId and rudderSessionId present in note_attributes', async () => { + const input = { + event: 'Checkout Create', + properties: { + cart_token: 'CART_TOKEN', + note_attributes: [ + { + name: 'rudderAnonymousId', + value: 'RUDDER_ANONYMOUSID', + }, + { + name: 'rudderSessionId', + value: 'RUDDER_SESSIONID', + }, + { + name: 'rudderUpdatedAt', + value: 'TIMESTAMP', + }, + ], + }, + }; + const expectedOutput = { anonymousId: 'RUDDER_ANONYMOUSID', sessionId: 'RUDDER_SESSIONID' }; + const output = await getAnonymousIdAndSessionId(input, {}, null); + expect(output).toEqual(expectedOutput); + }); + }); + + describe('set AnonymousId and sesssionId with Redis Test Cases', () => { + // Doing the following to enable redis mid test case file execution + process.env.USE_REDIS_DB = true; + jest.resetModules(); + const { getAnonymousIdAndSessionId } = require('./util'); + it('Properties containing cartToken but failed due redisError', async () => { + const input = { + event: 'Order Paid', + properties: { + cart_token: 'shopify_test2', + }, + }; + const expectedOutput = { + anonymousId: 'bcaf0473-fb11-562f-80a1-c83a35f053bc', + sessionId: undefined, + }; // cartToken hashed + const output = await getAnonymousIdAndSessionId(input, {}, null); + expect(output).toEqual(expectedOutput); + }); + + it('Order Paid- > Properties containing cartToken and fetched anonymousId and sessionId successfully', async () => { + const input = { + event: 'Order Paid', + properties: { + cart_token: 'shopify_test2', + note_attributes: [ + { + name: 'rudderUpdatedAt', + value: 'RUDDER_UPDTD_AT', + }, + ], + }, + }; + const expectedOutput = { anonymousId: 'anon_shopify_test2', sessionId: 'session_id_2' }; // fetched succesfully from redis + + const output = await getAnonymousIdAndSessionId(input, {}, null); + expect(output).toEqual(expectedOutput); + }); + + it('Cart Update -> Properties contain id and fetched anonymousId successfully', async () => { + const input = { + event: 'Cart Update', + properties: { + id: 'shopify_test_only_anon_id', + }, + }; + const expectedOutput = { + anonymousId: 'anon_shopify_test_only_anon_id', + sessionId: undefined, + }; + const output = await getAnonymousIdAndSessionId(input, {}, null); + expect(output).toEqual(expectedOutput); + }); + + it('No mapping not present in DB for given cartToken', async () => { + const input = { + event: 'Cart Update', + properties: { + id: 'unstored_id', + }, + }; + + const expectedOutput = { + anonymousId: '281a3e25-e603-5870-9cda-281c22940970', + sessionId: undefined, + }; + + const output = await getAnonymousIdAndSessionId(input, {}, null); + expect(output).toEqual(expectedOutput); + }); + + it('No cartToken for SHOPIFY_ADMIN_ONLY_EVENTS', async () => { + const input = { + event: 'Fulfillments Update', + properties: { + id: 'unstored_id', + }, + }; + const expectedOutput = { anonymousId: undefined, sessionId: undefined }; + + const output = await getAnonymousIdAndSessionId(input, {}, null); + expect(output).toEqual(expectedOutput); + }); + + it('No cartToken for Order paid', async () => { + const input = { + event: 'Order Paid', + properties: { + cart_token: 'shopify_test2', + }, + }; + const expectedOutput = 'RANDOM_ANONYMOUS_ID'; // fetched succesfully from redis + + const output = await getAnonymousIdAndSessionId(input, {}, null); + expect('RANDOM_ANONYMOUS_ID').toEqual(expectedOutput); + }); + + it('Only anonymousId fetched from note_attributes and no cartToken', async () => { + const input = { + event: 'Order Paid', + properties: { + note_attributes: [ + { + name: 'rudderAnonymousId', + value: 'RUDDER_ANON_ID', + }, + { + name: 'rudderUpdatedAt', + value: 'RUDDER_UPDTD_AT', + }, + ], + }, + }; + const expectedOutput = { anonymousId: 'RUDDER_ANON_ID', sessionId: null }; // fetched succesfully from redis + const output = await getAnonymousIdAndSessionId(input, {}, null); + + expect(output).toEqual(expectedOutput); + }); + }); +}); diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js new file mode 100644 index 0000000000..0f97237ddb --- /dev/null +++ b/src/v1/sources/shopify/transform.js @@ -0,0 +1,300 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +const lodash = require('lodash'); +const get = require('get-value'); +const { RedisError } = require('@rudderstack/integrations-lib'); +const stats = require('../../../util/stats'); +const { + getShopifyTopic, + createPropertiesForEcomEvent, + getProductsListFromLineItems, + extractEmailFromPayload, + getAnonymousIdAndSessionId, + checkAndUpdateCartItems, + getHashLineItems, + getDataFromRedis, +} = require('./util'); +const logger = require('../../../logger'); +const { RedisDB } = require('../../../util/redis/redisConnector'); +const { removeUndefinedAndNullValues, isDefinedAndNotNull } = require('../../../v0/util'); +const Message = require('../../../v0/sources/message'); +const { EventType } = require('../../../constants'); +const { + INTEGERATION, + MAPPING_CATEGORIES, + IDENTIFY_TOPICS, + ECOM_TOPICS, + RUDDER_ECOM_MAP, + SUPPORTED_TRACK_EVENTS, + SHOPIFY_TRACK_MAP, + useRedisDatabase, +} = require('./config'); + +const NO_OPERATION_SUCCESS = { + outputToSource: { + body: Buffer.from('OK').toString('base64'), + contentType: 'text/plain', + }, + statusCode: 200, +}; + +const identifyPayloadBuilder = (event) => { + const message = new Message(INTEGERATION); + message.setEventType(EventType.IDENTIFY); + message.setPropertiesV2(event, MAPPING_CATEGORIES[EventType.IDENTIFY]); + if (event.updated_at) { + // converting shopify updated_at timestamp to rudder timestamp format + message.setTimestamp(new Date(event.updated_at).toISOString()); + } + return message; +}; + +const ecomPayloadBuilder = (event, shopifyTopic) => { + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(RUDDER_ECOM_MAP[shopifyTopic]); + + let properties = createPropertiesForEcomEvent(event); + properties = removeUndefinedAndNullValues(properties); + Object.keys(properties).forEach((key) => + message.setProperty(`properties.${key}`, properties[key]), + ); + // Map Customer details if present + const customerDetails = get(event, 'customer'); + if (customerDetails) { + message.setPropertiesV2(customerDetails, MAPPING_CATEGORIES[EventType.IDENTIFY]); + } + if (event.updated_at) { + // TODO: look for created_at for checkout_create? + // converting shopify updated_at timestamp to rudder timestamp format + message.setTimestamp(new Date(event.updated_at).toISOString()); + } + if (event.customer) { + message.setPropertiesV2(event.customer, MAPPING_CATEGORIES[EventType.IDENTIFY]); + } + if (event.shipping_address) { + message.setProperty('traits.shippingAddress', event.shipping_address); + } + if (event.billing_address) { + message.setProperty('traits.billingAddress', event.billing_address); + } + if (!message.userId && event.user_id) { + message.setProperty('userId', event.user_id); + } + return message; +}; + +const trackPayloadBuilder = (event, shopifyTopic) => { + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(SHOPIFY_TRACK_MAP[shopifyTopic]); + + Object.keys(event) + .filter( + (key) => + ![ + 'type', + 'event', + 'line_items', + 'customer', + 'shipping_address', + 'billing_address', + ].includes(key), + ) + .forEach((key) => { + message.setProperty(`properties.${key}`, event[key]); + }); + // eslint-disable-next-line camelcase + const { line_items: lineItems, billing_address, user_id, shipping_address, customer } = event; + const productsList = getProductsListFromLineItems(lineItems); + message.setProperty('properties.products', productsList); + if (customer) { + message.setPropertiesV2(customer, MAPPING_CATEGORIES[EventType.IDENTIFY]); + } + // eslint-disable-next-line camelcase + if (shipping_address) { + message.setProperty('traits.shippingAddress', shipping_address); + } + // eslint-disable-next-line camelcase + if (billing_address) { + message.setProperty('traits.billingAddress', billing_address); + } + // eslint-disable-next-line camelcase + if (!message.userId && user_id) { + message.setProperty('userId', user_id); + } + return message; +}; + +const processEvent = async (inputEvent, metricMetadata) => { + let message; + const event = lodash.cloneDeep(inputEvent.event); + let redisData; + const shopifyTopic = getShopifyTopic(event); + delete event.query_parameters; + switch (shopifyTopic) { + case IDENTIFY_TOPICS.CUSTOMERS_CREATE: + case IDENTIFY_TOPICS.CUSTOMERS_UPDATE: + message = identifyPayloadBuilder(event); + break; + case ECOM_TOPICS.ORDERS_CREATE: + case ECOM_TOPICS.ORDERS_UPDATE: + case ECOM_TOPICS.CHECKOUTS_CREATE: + case ECOM_TOPICS.CHECKOUTS_UPDATE: + message = ecomPayloadBuilder(event, shopifyTopic); + break; + case 'carts_update': + if (useRedisDatabase) { + redisData = await getDataFromRedis(event.id || event.token, metricMetadata, 'Cart Update'); + const isValidEvent = await checkAndUpdateCartItems( + inputEvent, + redisData, + metricMetadata, + shopifyTopic, + ); + if (!isValidEvent) { + return NO_OPERATION_SUCCESS; + } + } + message = trackPayloadBuilder(event, shopifyTopic); + break; + default: + if (!SUPPORTED_TRACK_EVENTS.includes(shopifyTopic)) { + stats.increment('invalid_shopify_event', { + writeKey: metricMetadata.writeKey, + source: metricMetadata.source, + shopifyTopic: metricMetadata.shopifyTopic, + }); + return NO_OPERATION_SUCCESS; + } + message = trackPayloadBuilder(event, shopifyTopic); + break; + } + + if (message.userId) { + message.userId = String(message.userId); + } + if (!get(message, 'traits.email')) { + const email = extractEmailFromPayload(event); + if (email) { + message.setProperty('traits.email', email); + } + } + if (message.type !== EventType.IDENTIFY) { + const { anonymousId, sessionId } = await getAnonymousIdAndSessionId( + message, + { shopifyTopic, ...metricMetadata }, + redisData, + ); + if (isDefinedAndNotNull(anonymousId)) { + message.setProperty('anonymousId', anonymousId); + } else if (!message.userId) { + message.setProperty('userId', 'shopify-admin'); + } + if (isDefinedAndNotNull(sessionId)) { + message.setProperty('context.sessionId', sessionId); + } + } + message.setProperty(`integrations.${INTEGERATION}`, true); + message.setProperty('context.library', { + name: 'RudderStack Shopify Cloud', + version: '1.0.0', + }); + message.setProperty('context.topic', shopifyTopic); + // attaching cart, checkout and order tokens in context object + message.setProperty(`context.cart_token`, event.cart_token); + message.setProperty(`context.checkout_token`, event.checkout_token); + if (shopifyTopic === 'orders_updated') { + message.setProperty(`context.order_token`, event.token); + } + message = removeUndefinedAndNullValues(message); + return message; +}; +const isIdentifierEvent = (event) => + ['rudderIdentifier', 'rudderSessionIdentifier'].includes(event?.event); +const processIdentifierEvent = async (event, metricMetadata) => { + if (useRedisDatabase) { + const cartToken = + typeof event.cartToken === 'string' ? event.cartToken.split('?')[0] : event.cartToken; + logger.info(`{{SHOPIFY::}} writeKey: ${metricMetadata.writeKey}, cartToken: ${cartToken}`, { + type: 'set', + source: metricMetadata.source, + writeKey: metricMetadata.writeKey, + }); + let value; + let field; + if (event.event === 'rudderIdentifier') { + field = 'anonymousId'; + // eslint-disable-next-line unicorn/consistent-destructuring + const lineItemshash = getHashLineItems(event.cart); + // eslint-disable-next-line unicorn/consistent-destructuring + value = ['anonymousId', event.anonymousId, 'itemsHash', lineItemshash]; + stats.increment('shopify_redis_calls', { + type: 'set', + field: 'itemsHash', + source: metricMetadata.source, + writeKey: metricMetadata.writeKey, + }); + /* cart_token: { + anonymousId: 'anon_id1', + lineItemshash: '0943gh34pg' + } + */ + } else { + field = 'sessionId'; + // eslint-disable-next-line unicorn/consistent-destructuring + value = ['sessionId', event.sessionId]; + /* cart_token: { + anonymousId:'anon_id1', + lineItemshash:'90fg348fg83497u', + sessionId: 'session_id1' + } + */ + } + try { + stats.increment('shopify_redis_calls', { + type: 'set', + field, + source: metricMetadata.source, + writeKey: metricMetadata.writeKey, + }); + await RedisDB.setVal(`${cartToken}`, value); + } catch (e) { + logger.debug(`{{SHOPIFY::}} cartToken map set call Failed due redis error ${e}`, { + type: 'set', + source: metricMetadata.source, + writeKey: metricMetadata.writeKey, + }); + stats.increment('shopify_redis_failures', { + type: 'set', + source: metricMetadata.source, + writeKey: metricMetadata.writeKey, + }); + // returning 500 as status code in case of redis failure + throw new RedisError(`${e}`, 500); + } + } + return NO_OPERATION_SUCCESS; +}; + +const processEventV2 = async (event) => event; +const process = async (event) => { + const { source } = event; + if (source) { + const { version } = source.Config; + if (version === 'v2') { + const responseV2 = await processEventV2(event); + return responseV2; + } + } + const metricMetadata = { + writeKey: event.query_parameters?.writeKey?.[0], + source: 'SHOPIFY', + }; + if (isIdentifierEvent(event)) { + return processIdentifierEvent(event, metricMetadata); + } + const response = await processEvent(event, metricMetadata); + return response; +}; + +exports.process = process; diff --git a/src/v1/sources/shopify/util.js b/src/v1/sources/shopify/util.js new file mode 100644 index 0000000000..dc73553769 --- /dev/null +++ b/src/v1/sources/shopify/util.js @@ -0,0 +1,284 @@ +/* eslint-disable camelcase */ +/* eslint-disable @typescript-eslint/naming-convention */ +const { v5 } = require('uuid'); +const sha256 = require('sha256'); +const { TransformationError } = require('@rudderstack/integrations-lib'); +const stats = require('../../../util/stats'); +const { + constructPayload, + extractCustomFields, + flattenJson, + generateUUID, + isDefinedAndNotNull, +} = require('../../../v0/util'); +const { RedisDB } = require('../../../util/redis/redisConnector'); +const { + lineItemsMappingJSON, + productMappingJSON, + LINE_ITEM_EXCLUSION_FIELDS, + PRODUCT_MAPPING_EXCLUSION_FIELDS, + SHOPIFY_TRACK_MAP, + SHOPIFY_ADMIN_ONLY_EVENTS, + useRedisDatabase, + maxTimeToIdentifyRSGeneratedCall, +} = require('./config'); +const logger = require('../../../logger'); + +const getDataFromRedis = async (key, metricMetadata, event) => { + try { + stats.increment('shopify_redis_calls', { + type: 'get', + field: 'all', + writeKey: metricMetadata.writeKey, + source: metricMetadata.source, + }); + const redisData = await RedisDB.getVal(key); + if ( + redisData === null || + (typeof redisData === 'object' && Object.keys(redisData).length === 0) + ) { + stats.increment('shopify_redis_no_val', { + writeKey: metricMetadata.writeKey, + source: metricMetadata.source, + event, + }); + } + return redisData; + } catch (e) { + logger.debug(`{{SHOPIFY::}} Get call Failed due redis error ${e}`); + stats.increment('shopify_redis_failures', { + type: 'get', + writeKey: metricMetadata.writeKey, + source: metricMetadata.source, + }); + } + return null; +}; +/** + * query_parameters : { topic: [''], ...} + * Throws error otherwise + * @param {*} event + * @returns + */ +const getShopifyTopic = (event) => { + const { query_parameters: qParams } = event; + logger.debug(`[Shopify] Input event: query_params: ${JSON.stringify(qParams)}`); + if (!qParams) { + throw new TransformationError('Query_parameters is missing'); + } + const { topic } = qParams; + if (!topic || !Array.isArray(topic)) { + throw new TransformationError('Invalid topic in query_parameters'); + } + if (topic.length === 0) { + throw new TransformationError('Topic not found'); + } + return topic[0]; +}; +const getHashLineItems = (cart) => { + if (cart && cart?.line_items && cart.line_items.length > 0) { + return sha256(JSON.stringify(cart.line_items)); + } + return 'EMPTY'; +}; +const getVariantString = (lineItem) => { + const { variant_id, variant_price, variant_title } = lineItem; + return `${variant_id || ''} ${variant_price || ''} ${variant_title || ''}`; +}; + +const getProductsListFromLineItems = (lineItems) => { + if (!lineItems || lineItems.length === 0) { + return []; + } + const products = []; + lineItems.forEach((lineItem) => { + const product = constructPayload(lineItem, lineItemsMappingJSON); + extractCustomFields(lineItem, product, 'root', LINE_ITEM_EXCLUSION_FIELDS); + product.variant = getVariantString(lineItem); + products.push(product); + }); + return products; +}; + +const createPropertiesForEcomEvent = (message) => { + const { line_items: lineItems } = message; + const productsList = getProductsListFromLineItems(lineItems); + const mappedPayload = constructPayload(message, productMappingJSON); + extractCustomFields(message, mappedPayload, 'root', PRODUCT_MAPPING_EXCLUSION_FIELDS); + mappedPayload.products = productsList; + return mappedPayload; +}; + +const extractEmailFromPayload = (event) => { + const flattenedPayload = flattenJson(event); + let email; + const regex_email = /\bemail\b/i; + Object.entries(flattenedPayload).some(([key, value]) => { + if (regex_email.test(key)) { + email = value; + return true; + } + return false; + }); + return email; +}; + +const getCartToken = (message) => { + const { event, properties } = message; + if (event === SHOPIFY_TRACK_MAP.carts_update) { + return properties?.id || properties?.token; + } + return properties?.cart_token || null; +}; + +/** + * This function checks and returns rudderId from message if present + * returns null if not present or found + * @param {*} message + */ +const getRudderIdFromNoteAtrributes = (noteAttributes, field) => { + const rudderIdObj = noteAttributes.find((obj) => obj.name === field); + if (isDefinedAndNotNull(rudderIdObj)) { + return rudderIdObj.value; + } + return null; +}; +/** + * This function retrieves anonymousId and sessionId in folowing steps: + * 1. Checks for `rudderAnonymousId`and `rudderSessionId in `note_atrributes` + * 2. if redis is enabled checks in redis + * 3. This means we don't have `anonymousId` and hence events CAN NOT be stitched and we check for cartToken + * a. if cartToken is available we return its hash value + * b. else we check if the event is an SHOPIFY_ADMIN_ONLY_EVENT + * -> if true we return `null`; + * -> else we don't have any identifer (very edge case) we return `random anonymousId` + * No Random SessionId is generated as its not a required field + * @param {*} message + * @param {*} metricMetadata + * @returns + */ +const getAnonymousIdAndSessionId = async (message, metricMetadata, redisData = null) => { + let anonymousId; + let sessionId; + const noteAttributes = message.properties?.note_attributes; + // Giving Priority to note_attributes to fetch rudderAnonymousId over Redis due to better efficiency + if (isDefinedAndNotNull(noteAttributes)) { + anonymousId = getRudderIdFromNoteAtrributes(noteAttributes, 'rudderAnonymousId'); + sessionId = getRudderIdFromNoteAtrributes(noteAttributes, 'rudderSessionId'); + } + // falling back to cartToken mapping or its hash in case no rudderAnonymousId or rudderSessionId is found + if (isDefinedAndNotNull(anonymousId) && isDefinedAndNotNull(sessionId)) { + stats.increment('shopify_anon_id_resolve', { + method: 'note_attributes', + writeKey: metricMetadata.writeKey, + source: metricMetadata.source, + shopifyTopic: metricMetadata.shopifyTopic, + }); + return { anonymousId, sessionId }; + } + const cartToken = getCartToken(message); + if (!isDefinedAndNotNull(cartToken)) { + if (SHOPIFY_ADMIN_ONLY_EVENTS.includes(message.event)) { + return { anonymousId, sessionId }; + } + return { + anonymousId: isDefinedAndNotNull(anonymousId) ? anonymousId : generateUUID(), + sessionId, + }; + } + if (useRedisDatabase) { + if (!isDefinedAndNotNull(redisData)) { + const { event } = message; + // eslint-disable-next-line no-param-reassign + redisData = await getDataFromRedis(cartToken, metricMetadata, event); + } + anonymousId = redisData?.anonymousId; + sessionId = redisData?.sessionId; + } + if (!isDefinedAndNotNull(anonymousId)) { + /* anonymousId or sessionId not found from db as well + Hash the id and use it as anonymousId (limiting 256 -> 36 chars) and sessionId is not sent as its not required field + */ + anonymousId = v5(cartToken, v5.URL); + } else { + // This metric let us know how many events based on event name used redis for anonId resolution + // and for how many + stats.increment('shopify_anon_id_resolve', { + method: 'database', + writeKey: metricMetadata.writeKey, + source: metricMetadata.source, + shopifyTopic: metricMetadata.shopifyTopic, + }); + } + return { anonymousId, sessionId }; +}; +/** + * It checks if the event is valid or not based on previous cartItems + * @param {*} inputEvent + * @returns true if event is valid else false + */ +const isValidCartEvent = (newCartItems, prevCartItems) => !(prevCartItems === newCartItems); +const updateCartItemsInRedis = async (cartToken, newCartItemsHash, metricMetadata) => { + const value = ['itemsHash', newCartItemsHash]; + try { + stats.increment('shopify_redis_calls', { + type: 'set', + field: 'itemsHash', + writeKey: metricMetadata.writeKey, + source: metricMetadata.source, + }); + await RedisDB.setVal(`${cartToken}`, value); + } catch (e) { + logger.debug(`{{SHOPIFY::}} itemsHash set call Failed due redis error ${e}`); + stats.increment('shopify_redis_failures', { + type: 'set', + writeKey: metricMetadata.writeKey, + source: metricMetadata.source, + }); + } +}; +/** + * This function checks for duplicate cart update event by checking the lineItems hash of previous cart update event + * and comapre it with the received lineItems hash. + * Also if redis is down or there is no lineItems hash for the given cartToken we be default take it as a valid cart update event + * @param {*} inputEvent + * @param {*} metricMetadata + * @returns boolean + */ +const checkAndUpdateCartItems = async (inputEvent, redisData, metricMetadata, shopifyTopic) => { + const cartToken = inputEvent.token || inputEvent.id; + if (!isDefinedAndNotNull(redisData)) { + // eslint-disable-next-line no-param-reassign + redisData = await getDataFromRedis(cartToken, metricMetadata, SHOPIFY_TRACK_MAP[shopifyTopic]); + } + const itemsHash = redisData?.itemsHash; + if (isDefinedAndNotNull(itemsHash)) { + const newCartItemsHash = getHashLineItems(inputEvent); + const isCartValid = isValidCartEvent(newCartItemsHash, itemsHash); + if (!isCartValid) { + return false; + } + await updateCartItemsInRedis(cartToken, newCartItemsHash, metricMetadata); + } else { + const { created_at, updated_at, line_items } = inputEvent; + const timeDifference = Date.parse(updated_at) - Date.parse(created_at); + const isTimeWithinThreshold = timeDifference < maxTimeToIdentifyRSGeneratedCall; + const isLineItemsEmpty = line_items?.length === 0; + + if (isTimeWithinThreshold && isLineItemsEmpty) { + return false; + } + } + return true; +}; + +module.exports = { + getShopifyTopic, + getProductsListFromLineItems, + createPropertiesForEcomEvent, + extractEmailFromPayload, + getAnonymousIdAndSessionId, + checkAndUpdateCartItems, + getHashLineItems, + getDataFromRedis, +}; From 754d8a3761a6e8d0289c77e7b927ea7dce319583 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:16:27 +0530 Subject: [PATCH 02/22] chore: refactor, add pixel transformation definitions --- src/v1/sources/shopify/transform.js | 39 ++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index 0f97237ddb..da8b53159f 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -127,7 +127,7 @@ const trackPayloadBuilder = (event, shopifyTopic) => { const processEvent = async (inputEvent, metricMetadata) => { let message; - const event = lodash.cloneDeep(inputEvent.event); + const event = lodash.cloneDeep(inputEvent); let redisData; const shopifyTopic = getShopifyTopic(event); delete event.query_parameters; @@ -276,20 +276,41 @@ const processIdentifierEvent = async (event, metricMetadata) => { return NO_OPERATION_SUCCESS; }; -const processEventV2 = async (event) => event; -const process = async (event) => { - const { source } = event; +function processPixelEvent(inputEvent) { + const { name, data, context, clientId } = inputEvent; + const payload = { + type: 'track', + event: name, + properties: data, + anonymousId: clientId, + context, + }; + return payload; +} + +const processEventV2 = async (event, metricMetadata) => { + const { pixelEventLabel } = event; + if (pixelEventLabel) { + // this is a web pixel event fired from the browser + const pixelEvent = processPixelEvent(event); + return removeUndefinedAndNullValues(pixelEvent); + } + return processEvent(event, metricMetadata); +}; +const process = async (inputEvent) => { + const { event, source } = inputEvent; + const metricMetadata = { + // eslint-disable-next-line unicorn/consistent-destructuring + writeKey: event.query_parameters?.writeKey?.[0], + source: 'SHOPIFY', + }; if (source) { const { version } = source.Config; if (version === 'v2') { - const responseV2 = await processEventV2(event); + const responseV2 = await processEventV2(event, metricMetadata); return responseV2; } } - const metricMetadata = { - writeKey: event.query_parameters?.writeKey?.[0], - source: 'SHOPIFY', - }; if (isIdentifierEvent(event)) { return processIdentifierEvent(event, metricMetadata); } From 9bd9ef5898f9efafeda53214da93967a773cb358 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Sun, 1 Sep 2024 23:35:01 +0530 Subject: [PATCH 03/22] feat: add support for all pixel events in v1 shopify source --- src/v1/sources/shopify/config.js | 203 ++++++++++++++++++++++++++ src/v1/sources/shopify/transform.js | 212 ++++++++++++++++++++++++++-- src/v1/sources/shopify/util.js | 55 ++++++++ 3 files changed, 461 insertions(+), 9 deletions(-) diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js index b8b3cde284..d500dfdcb9 100644 --- a/src/v1/sources/shopify/config.js +++ b/src/v1/sources/shopify/config.js @@ -38,6 +38,201 @@ const SHOPIFY_TRACK_MAP = { orders_partially_fullfilled: 'Order Partially Fulfilled', }; +const PIXEL_EVENT_TOPICS = { + CART_VIEWED: 'cart_viewed', + PRODUCT_ADDED_TO_CART: 'product_added_to_cart', + PRODUCT_REMOVED_FROM_CART: 'product_removed_from_cart', + PAGE_VIEWED: 'page_viewed', + PRODUCT_VIEWED: 'product_viewed', + COLLECTION_VIEWED: 'collection_viewed', + CHECKOUT_STARTED: 'checkout_started', + CHECKOUT_COMPLETED: 'checkout_completed', + CHECKOUT_ADDRESS_INFO_SUBMITTED: 'checkout_address_info_submitted', + CHECKOUT_CONTACT_INFO_SUBMITTED: 'checkout_contact_info_submitted', + CHECKOUT_SHIPPING_INFO_SUBMITTED: 'checkout_shipping_info_submitted', + PAYMENT_INFO_SUBMITTED: 'payment_info_submitted', + SEARCH_SUBMITTED: 'search_submitted', +}; + +const PIXEL_EVENT_MAPPING = { + cart_viewed: 'Cart Viewed', + product_added_to_cart: 'Product Added', + product_removed_from_cart: 'Product Removed', + page_viewed: 'Page Viewed', + product_viewed: 'Product Viewed', + collection_viewed: 'Collection Viewed', + checkout_started: 'Checkout Started', + checkout_completed: 'Checkout Completed', + checkout_address_info_submitted: 'Checkout Address Info Submitted', + checkout_contact_info_submitted: 'Checkout Contact Info Submitted', + checkout_shipping_info_submitted: 'Checkout Shipping Info Submitted', + payment_info_submitted: 'Payment Info Submitted', + search_submitted: 'Search Submitted', +}; + +const contextualFieldMapping = [ + { + shopifyField: 'context.document.referrer', + rudderField: 'page.referrer', + }, + { + shopifyField: 'document.title', + rudderField: 'page.title', + }, + { + shopifyField: 'navigator.userAgent', + rudderField: 'userAgent', + }, + { + shopifyField: 'window.location.href', + rudderField: 'page.url', + }, + { + shopifyField: 'window.location.pathname', + rudderField: 'page.path', + }, + { + shopifyField: 'window.location.search', + rudderField: 'page.search', + }, + { + shopifyField: 'window.screen.height', + rudderField: 'screen.height', + }, + { + shopifyField: 'window.screen.width', + rudderField: 'screen.width', + }, +]; + +const cartViewedEventMapping = [ + { shopifyField: 'merchandise.product.id', rudderField: 'product_id' }, + { shopifyField: 'merchandise.product.title', rudderField: 'variant' }, + { shopifyField: 'merchandise.image.src', rudderField: 'image_url' }, + { shopifyField: 'merchandise.price.amount', rudderField: 'price' }, + { shopifyField: 'merchandise.product.type', rudderField: 'category' }, + { shopifyField: 'merchandise.product.url', rudderField: 'url' }, + { shopifyField: 'merchandise.product.vendor', rudderField: 'brand' }, + { shopifyField: 'merchandise.sku', rudderField: 'sku' }, + { shopifyField: 'merchandise.title', rudderField: 'name' }, + { shopifyField: 'quantity', rudderField: 'quantity' }, +]; + +const productListViewedEventMapping = [ + { shopifyField: 'image.src', rudderField: 'image_url' }, + { shopifyField: 'price.amount', rudderField: 'price' }, + { shopifyField: 'product.id', rudderField: 'product_id' }, + { shopifyField: 'product.title', rudderField: 'variant' }, + { shopifyField: 'product.type', rudderField: 'category' }, + { shopifyField: 'product.url', rudderField: 'url' }, + { shopifyField: 'product.vendor', rudderField: 'brand' }, + { shopifyField: 'sku', rudderField: 'sku' }, + { shopifyField: 'title', rudderField: 'name' }, +]; + +const productViewedEventMapping = [ + { + shopifyField: 'productVariant.product.id', + rudderField: 'product_id', + }, + { + shopifyField: 'productVariant.product.title', + rudderField: 'variant', + }, + { + shopifyField: 'productVariant.product.vendor', + rudderField: 'brand', + }, + { + shopifyField: 'productVariant.product.type', + rudderField: 'category', + }, + { + shopifyField: 'productVariant.product.image.src', + rudderField: 'image_url', + }, + { + shopifyField: 'productVariant.price.amount', + rudderField: 'price', + }, + { + shopifyField: 'productVariant.price.currencyCode', + rudderField: 'currency', + }, + { + shopifyField: 'productVariant.product.url', + rudderField: 'url', + }, + { + shopifyField: 'productVariant.product.sku', + rudderField: 'sku', + }, + { + shopifyField: 'productVariant.product.title', + rudderField: 'name', + }, + { + shopifyField: 'cartLine.quantity', + rudderField: 'quantity', + }, +]; + +const productToCartEventMapping = [ + { + shopifyField: 'cartLine.merchandise.image.src', + rudderField: 'image_url', + }, + { + shopifyField: 'cartLine.merchandise.price.amount', + rudderField: 'price', + }, + { + shopifyField: 'cartLine.merchandise.product.id', + rudderField: 'product_id', + }, + { + shopifyField: 'cartLine.merchandise.product.title', + rudderField: 'variant', + }, + { + shopifyField: 'cartLine.merchandise.product.type', + rudderField: 'category', + }, + { + shopifyField: 'cartLine.merchandise.product.vendor', + rudderField: 'brand', + }, + { + shopifyField: 'cartLine.merchandise.product.url', + rudderField: 'url', + }, + { + shopifyField: 'cartLine.merchandise.sku', + rudderField: 'sku', + }, + { + shopifyField: 'cartLine.merchandise.title', + rudderField: 'name', + }, + { + shopifyField: 'cartLine.quantity', + rudderField: 'quantity', + }, +]; + +const checkoutStartedCompletedEventMapping = [ + { shopifyField: 'quantity', rudderField: 'quantity' }, + { shopifyField: 'title', rudderField: 'name' }, + { shopifyField: 'variant.image.src', rudderField: 'image_url' }, + { shopifyField: 'variant.price.amount', rudderField: 'price' }, + { shopifyField: 'variant.sku', rudderField: 'sku' }, + { shopifyField: 'variant.product.id', rudderField: 'product_id' }, + { shopifyField: 'variant.product.title', rudderField: 'variant' }, + { shopifyField: 'variant.product.type', rudderField: 'category' }, + { shopifyField: 'variant.product.url', rudderField: 'url' }, + { shopifyField: 'variant.product.vendor', rudderField: 'brand' }, +]; + const identifyMappingJSON = JSON.parse( fs.readFileSync(path.resolve(__dirname, 'data', 'identifyMapping.json')), ); @@ -117,6 +312,14 @@ module.exports = { PRODUCT_MAPPING_EXCLUSION_FIELDS, SUPPORTED_TRACK_EVENTS, SHOPIFY_TRACK_MAP, + PIXEL_EVENT_TOPICS, + PIXEL_EVENT_MAPPING, + contextualFieldMapping, + cartViewedEventMapping, + productListViewedEventMapping, + productViewedEventMapping, + productToCartEventMapping, + checkoutStartedCompletedEventMapping, useRedisDatabase, SHOPIFY_ADMIN_ONLY_EVENTS, maxTimeToIdentifyRSGeneratedCall, diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index da8b53159f..62b3bebe72 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -12,6 +12,7 @@ const { checkAndUpdateCartItems, getHashLineItems, getDataFromRedis, + mapObjectKeys, } = require('./util'); const logger = require('../../../logger'); const { RedisDB } = require('../../../util/redis/redisConnector'); @@ -26,6 +27,14 @@ const { RUDDER_ECOM_MAP, SUPPORTED_TRACK_EVENTS, SHOPIFY_TRACK_MAP, + PIXEL_EVENT_TOPICS, + PIXEL_EVENT_MAPPING, + contextualFieldMapping, + cartViewedEventMapping, + productListViewedEventMapping, + productViewedEventMapping, + productToCartEventMapping, + checkoutStartedCompletedEventMapping, useRedisDatabase, } = require('./config'); @@ -125,6 +134,148 @@ const trackPayloadBuilder = (event, shopifyTopic) => { return message; }; +const pageViewedEventBuilder = (inputEvent) => { + const { data, context } = inputEvent; + const pageEventContextValues = mapObjectKeys(context, contextualFieldMapping); + const message = new Message(INTEGERATION); + message.name = 'Page View'; + message.setEventType(EventType.PAGE); + message.properties = { ...data }; + message.context = { ...pageEventContextValues }; + return message; +}; + +const cartViewedEventBuilder = (inputEvent) => { + const lines = inputEvent?.data?.cart?.lines; + const products = []; + if (lines) { + lines.forEach((line) => { + const product = mapObjectKeys(line, cartViewedEventMapping); + products.push(product); + }); + } + + const properties = { + products, + cart_id: inputEvent.data.cart.id, + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName('Cart Viewed'); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const productListViewedEventBuilder = (inputEvent) => { + const productVariants = inputEvent?.data?.collection?.productVariants; + const products = []; + + productVariants.forEach((productVariant) => { + const mappedProduct = mapObjectKeys(productVariant, productListViewedEventMapping); + products.push(mappedProduct); + }); + + const properties = { + cart_id: inputEvent.clientId, + list_id: inputEvent.id, + products, + }; + + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName('Product List Viewed'); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const productViewedEventBuilder = (inputEvent) => { + const properties = { + ...mapObjectKeys(inputEvent.data, productViewedEventMapping), + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName('Product Viewed'); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const productToCartEventBuilder = (inputEvent) => { + const properties = { + ...mapObjectKeys(inputEvent.data, productToCartEventMapping), + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const checkoutEventBuilder = (inputEvent) => { + const lineItems = inputEvent?.data?.checkout?.lineItems; + const products = []; + + lineItems.forEach((lineItem) => { + const mappedProduct = mapObjectKeys(lineItem, checkoutStartedCompletedEventMapping); + products.push(mappedProduct); + }); + + const properties = { + products, + order_id: inputEvent.id, + checkout_id: inputEvent?.data?.checkout?.token, + total: inputEvent?.data?.checkout?.totalPrice?.amount, + currency: inputEvent?.data?.checkout?.currencyCode, + discount: inputEvent?.data?.checkout?.discountsAmount?.amount, + shipping: inputEvent?.data?.checkout?.shippingLine?.price?.amount, + revenue: inputEvent?.data?.checkout?.subtotalPrice?.amount, + value: inputEvent?.data?.checkout?.totalPrice?.amount, + tax: inputEvent?.data?.checkout?.totalTax?.amount, + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const checkoutStepEventBuilder = (inputEvent) => { + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + const properties = { + ...inputEvent.data.checkout, + }; + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const searchEventBuilder = (inputEvent) => { + const properties = { + query: inputEvent.data.searchResult.query, + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + const processEvent = async (inputEvent, metricMetadata) => { let message; const event = lodash.cloneDeep(inputEvent); @@ -277,15 +428,58 @@ const processIdentifierEvent = async (event, metricMetadata) => { }; function processPixelEvent(inputEvent) { - const { name, data, context, clientId } = inputEvent; - const payload = { - type: 'track', - event: name, - properties: data, - anonymousId: clientId, - context, - }; - return payload; + const { name, query_parameters, clientId, data } = inputEvent; + let message; + switch (name) { + case PIXEL_EVENT_TOPICS.PAGE_VIEWED: + message = pageViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.CART_VIEWED: + message = cartViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.COLLECTION_VIEWED: + message = productListViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.PRODUCT_VIEWED: + message = productViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.PRODUCT_ADDED_TO_CART: + case PIXEL_EVENT_TOPICS.PRODUCT_REMOVED_FROM_CART: + message = productToCartEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.CHECKOUT_STARTED: + case PIXEL_EVENT_TOPICS.CHECKOUT_COMPLETED: + message.userId = data?.checkout?.order?.customer?.id || ''; + message = checkoutEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.CHECKOUT_ADDRESS_INFO_SUBMITTED: + case PIXEL_EVENT_TOPICS.CHECKOUT_CONTACT_INFO_SUBMITTED: + case PIXEL_EVENT_TOPICS.CHECKOUT_SHIPPING_INFO_SUBMITTED: + case PIXEL_EVENT_TOPICS.PAYMENT_INFO_SUBMITTED: + message.userId = data?.checkout?.order?.customer?.id || ''; + message = checkoutStepEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.SEARCH_SUBMITTED: + message = searchEventBuilder(inputEvent); + break; + default: + logger.debug(`{{SHOPIFY::}} Invalid pixel event ${name}`); + stats.increment('invalid_shopify_event', { + writeKey: query_parameters.writeKey, + source: 'SHOPIFY', + shopifyTopic: name, + }); + return NO_OPERATION_SUCCESS; + } + message.anonymousId = clientId; + message.setProperty(`integrations.${INTEGERATION}`, true); + message.setProperty('context.library', { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }); + message.setProperty('context.topic', name); + message = removeUndefinedAndNullValues(message); + return message; } const processEventV2 = async (event, metricMetadata) => { diff --git a/src/v1/sources/shopify/util.js b/src/v1/sources/shopify/util.js index dc73553769..e2645d54c4 100644 --- a/src/v1/sources/shopify/util.js +++ b/src/v1/sources/shopify/util.js @@ -272,6 +272,59 @@ const checkAndUpdateCartItems = async (inputEvent, redisData, metricMetadata, sh return true; }; +function getNestedValue(obj, path) { + const parts = path.split('.'); + return parts.reduce((acc, part) => acc && acc[part], obj); +} + +function setNestedValue(obj, path, value) { + const parts = path.split('.'); + const lastIndex = parts.length - 1; + parts.reduce((acc, part, index) => { + if (index === lastIndex) { + acc[part] = value; + } else if (!acc[part]) { + acc[part] = {}; + } + return acc[part]; + }, obj); +} + +function mapObjectKeys(obj, mapping) { + if (!Array.isArray(mapping)) { + throw new TypeError('mapping should be an array'); + } + const acc = { ...obj }; + + return mapping.reduce((accumulator, { shopifyField, rudderField }) => { + const value = getNestedValue(obj, shopifyField); + if (value !== undefined) { + setNestedValue(accumulator, rudderField, value); + } + return acc; + }, acc); +} + +const pixelEventBuilder = (inputEvent) => { + const { event: eventName, properties } = inputEvent; + const { currency, value, content_ids, content_type } = properties; + const { value: propValue, currency: propCurrency } = properties; + const eventValue = isDefinedAndNotNull(value) ? value : propValue; + const eventCurrency = isDefinedAndNotNull(currency) ? currency : propCurrency; + const pixelEvent = { + event_name: eventName, + currency: eventCurrency, + value: eventValue, + }; + if (content_ids) { + pixelEvent.content_ids = content_ids; + } + if (content_type) { + pixelEvent.content_type = content_type; + } + return pixelEvent; +}; + module.exports = { getShopifyTopic, getProductsListFromLineItems, @@ -281,4 +334,6 @@ module.exports = { checkAndUpdateCartItems, getHashLineItems, getDataFromRedis, + pixelEventBuilder, + mapObjectKeys, }; From 39c81c1d9bc0476fc38cdcca28e7100ae6416975 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Sun, 1 Sep 2024 23:56:51 +0530 Subject: [PATCH 04/22] fix: add customer id check --- src/v1/sources/shopify/transform.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index 62b3bebe72..b0785bacc4 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -429,6 +429,9 @@ const processIdentifierEvent = async (event, metricMetadata) => { function processPixelEvent(inputEvent) { const { name, query_parameters, clientId, data } = inputEvent; + const { checkout } = data; + const { order } = checkout; + const { customer } = order; let message; switch (name) { case PIXEL_EVENT_TOPICS.PAGE_VIEWED: @@ -449,14 +452,14 @@ function processPixelEvent(inputEvent) { break; case PIXEL_EVENT_TOPICS.CHECKOUT_STARTED: case PIXEL_EVENT_TOPICS.CHECKOUT_COMPLETED: - message.userId = data?.checkout?.order?.customer?.id || ''; + if (customer.id) message.userId = customer.id || ''; message = checkoutEventBuilder(inputEvent); break; case PIXEL_EVENT_TOPICS.CHECKOUT_ADDRESS_INFO_SUBMITTED: case PIXEL_EVENT_TOPICS.CHECKOUT_CONTACT_INFO_SUBMITTED: case PIXEL_EVENT_TOPICS.CHECKOUT_SHIPPING_INFO_SUBMITTED: case PIXEL_EVENT_TOPICS.PAYMENT_INFO_SUBMITTED: - message.userId = data?.checkout?.order?.customer?.id || ''; + if (customer.id) message.userId = customer.id || ''; message = checkoutStepEventBuilder(inputEvent); break; case PIXEL_EVENT_TOPICS.SEARCH_SUBMITTED: From 63687614e84fc28b8c600de3d62bacdeef41ba66 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:02:49 +0530 Subject: [PATCH 05/22] chore: fix checks --- src/v1/sources/shopify/transform.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index b0785bacc4..e645d1b692 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -429,9 +429,9 @@ const processIdentifierEvent = async (event, metricMetadata) => { function processPixelEvent(inputEvent) { const { name, query_parameters, clientId, data } = inputEvent; - const { checkout } = data; - const { order } = checkout; - const { customer } = order; + const { checkout } = data ?? {}; + const { order } = checkout ?? {}; + const { customer } = order ?? {}; let message; switch (name) { case PIXEL_EVENT_TOPICS.PAGE_VIEWED: From 2c7291cd630de9bb666120d5d831d7f66745f800 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Tue, 3 Sep 2024 09:40:51 +0530 Subject: [PATCH 06/22] fix: add configs for new webhook topics and events from pixel app --- src/v1/sources/shopify/config.js | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js index d500dfdcb9..97a187a133 100644 --- a/src/v1/sources/shopify/config.js +++ b/src/v1/sources/shopify/config.js @@ -36,6 +36,31 @@ const SHOPIFY_TRACK_MAP = { orders_fulfilled: 'Order Fulfilled', orders_paid: 'Order Paid', orders_partially_fullfilled: 'Order Partially Fulfilled', + 'customer.tags_added': 'Customer Tags Added', + 'customer.tags_removed': 'Customer Tags Removed', + 'customer.email_updated': 'Customer Email Updated', + collections_create: 'Collection Created', + collections_update: 'Collection Updated', + collections_delete: 'Collection Deleted', + collection_listings_add: 'Collection Listings Added', + collection_listings_remove: 'Collection Listings Removed', + collection_listings_update: 'Collection Listings Updated', + collection_publications_create: 'Collection Publications Created', + collection_publications_delete: 'Collection Publications Deleted', + collection_publications_update: 'Collection Publications Updated', + discounts_create: 'Discount Created', + discounts_delete: 'Discount Deleted', + discounts_update: 'Discount Updated', + draft_orders_create: 'Draft Order Created', + draft_orders_delete: 'Draft Order Deleted', + draft_orders_update: 'Draft Order Updated', + fulfillment_order_split: 'Fulfillment Order Split', + inventory_items_create: 'Inventory Items Created', + inventory_items_delete: 'Inventory Items Deleted', + inventory_items_update: 'Inventory Items Updated', + inventory_levels_connect: 'Inventory Levels Connected', + inventory_levels_disconnect: 'Inventory Levels Disconnected', + inventory_levels_update: 'Inventory Levels Updated', }; const PIXEL_EVENT_TOPICS = { @@ -281,13 +306,38 @@ const PRODUCT_MAPPING_EXCLUSION_FIELDS = [ * be discarded. */ const SUPPORTED_TRACK_EVENTS = [ + 'customer.tags_added', + 'customer.tags_removed', + 'customer.email_updated', 'checkouts_delete', 'checkouts_update', 'customers_disable', 'customers_enable', + 'collections_create', + 'collections_update', + 'collections_delete', + 'collection_listings_add', + 'collection_listings_remove', + 'collection_listings_update', + 'collection_publications_create', + 'collection_publications_delete', + 'collection_publications_update', + 'discounts_create', + 'discounts_delete', + 'discounts_update', + 'draft_orders_create', + 'draft_orders_delete', + 'draft_orders_update', 'carts_update', 'fulfillments_create', 'fulfillments_update', + 'fulfillment_order_split', + 'inventory_items_create', + 'inventory_items_delete', + 'inventory_items_update', + 'inventory_levels_connect', + 'inventory_levels_disconnect', + 'inventory_levels_update', 'orders_create', 'orders_delete', 'orders_edited', From a17a9cb3d15a94e09da734f1b61775a1260ceb71 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Wed, 4 Sep 2024 00:53:18 +0530 Subject: [PATCH 07/22] chore: update webhook event topic in mapping --- src/v1/sources/shopify/config.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js index 97a187a133..c02d7881f8 100644 --- a/src/v1/sources/shopify/config.js +++ b/src/v1/sources/shopify/config.js @@ -36,9 +36,9 @@ const SHOPIFY_TRACK_MAP = { orders_fulfilled: 'Order Fulfilled', orders_paid: 'Order Paid', orders_partially_fullfilled: 'Order Partially Fulfilled', - 'customer.tags_added': 'Customer Tags Added', - 'customer.tags_removed': 'Customer Tags Removed', - 'customer.email_updated': 'Customer Email Updated', + customer_tags_added: 'Customer Tags Added', + customer_tags_removed: 'Customer Tags Removed', + customer_email_updated: 'Customer Email Updated', collections_create: 'Collection Created', collections_update: 'Collection Updated', collections_delete: 'Collection Deleted', @@ -306,9 +306,9 @@ const PRODUCT_MAPPING_EXCLUSION_FIELDS = [ * be discarded. */ const SUPPORTED_TRACK_EVENTS = [ - 'customer.tags_added', - 'customer.tags_removed', - 'customer.email_updated', + 'customer_tags_added', + 'customer_tags_removed', + 'customer_email_updated', 'checkouts_delete', 'checkouts_update', 'customers_disable', From 8ad646870ae192c5b61ea869e964dcc2b4326062 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 9 Sep 2024 07:40:55 +0530 Subject: [PATCH 08/22] chore: refactor --- src/v1/sources/shopify/transform.js | 160 ++------------------------ src/v1/sources/shopify/utilsV2.js | 167 ++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 150 deletions(-) create mode 100644 src/v1/sources/shopify/utilsV2.js diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index e645d1b692..0c3df95ac7 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -12,13 +12,22 @@ const { checkAndUpdateCartItems, getHashLineItems, getDataFromRedis, - mapObjectKeys, } = require('./util'); const logger = require('../../../logger'); const { RedisDB } = require('../../../util/redis/redisConnector'); const { removeUndefinedAndNullValues, isDefinedAndNotNull } = require('../../../v0/util'); const Message = require('../../../v0/sources/message'); const { EventType } = require('../../../constants'); +const { + pageViewedEventBuilder, + cartViewedEventBuilder, + productListViewedEventBuilder, + productViewedEventBuilder, + productToCartEventBuilder, + checkoutEventBuilder, + checkoutStepEventBuilder, + searchEventBuilder, +} = require('./utilsV2'); const { INTEGERATION, MAPPING_CATEGORIES, @@ -28,13 +37,6 @@ const { SUPPORTED_TRACK_EVENTS, SHOPIFY_TRACK_MAP, PIXEL_EVENT_TOPICS, - PIXEL_EVENT_MAPPING, - contextualFieldMapping, - cartViewedEventMapping, - productListViewedEventMapping, - productViewedEventMapping, - productToCartEventMapping, - checkoutStartedCompletedEventMapping, useRedisDatabase, } = require('./config'); @@ -134,148 +136,6 @@ const trackPayloadBuilder = (event, shopifyTopic) => { return message; }; -const pageViewedEventBuilder = (inputEvent) => { - const { data, context } = inputEvent; - const pageEventContextValues = mapObjectKeys(context, contextualFieldMapping); - const message = new Message(INTEGERATION); - message.name = 'Page View'; - message.setEventType(EventType.PAGE); - message.properties = { ...data }; - message.context = { ...pageEventContextValues }; - return message; -}; - -const cartViewedEventBuilder = (inputEvent) => { - const lines = inputEvent?.data?.cart?.lines; - const products = []; - if (lines) { - lines.forEach((line) => { - const product = mapObjectKeys(line, cartViewedEventMapping); - products.push(product); - }); - } - - const properties = { - products, - cart_id: inputEvent.data.cart.id, - }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName('Cart Viewed'); - message.properties = properties; - message.context = contextualPayload; - return message; -}; - -const productListViewedEventBuilder = (inputEvent) => { - const productVariants = inputEvent?.data?.collection?.productVariants; - const products = []; - - productVariants.forEach((productVariant) => { - const mappedProduct = mapObjectKeys(productVariant, productListViewedEventMapping); - products.push(mappedProduct); - }); - - const properties = { - cart_id: inputEvent.clientId, - list_id: inputEvent.id, - products, - }; - - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName('Product List Viewed'); - message.properties = properties; - message.context = contextualPayload; - return message; -}; - -const productViewedEventBuilder = (inputEvent) => { - const properties = { - ...mapObjectKeys(inputEvent.data, productViewedEventMapping), - }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName('Product Viewed'); - message.properties = properties; - message.context = contextualPayload; - return message; -}; - -const productToCartEventBuilder = (inputEvent) => { - const properties = { - ...mapObjectKeys(inputEvent.data, productToCartEventMapping), - }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); - message.properties = properties; - message.context = contextualPayload; - return message; -}; - -const checkoutEventBuilder = (inputEvent) => { - const lineItems = inputEvent?.data?.checkout?.lineItems; - const products = []; - - lineItems.forEach((lineItem) => { - const mappedProduct = mapObjectKeys(lineItem, checkoutStartedCompletedEventMapping); - products.push(mappedProduct); - }); - - const properties = { - products, - order_id: inputEvent.id, - checkout_id: inputEvent?.data?.checkout?.token, - total: inputEvent?.data?.checkout?.totalPrice?.amount, - currency: inputEvent?.data?.checkout?.currencyCode, - discount: inputEvent?.data?.checkout?.discountsAmount?.amount, - shipping: inputEvent?.data?.checkout?.shippingLine?.price?.amount, - revenue: inputEvent?.data?.checkout?.subtotalPrice?.amount, - value: inputEvent?.data?.checkout?.totalPrice?.amount, - tax: inputEvent?.data?.checkout?.totalTax?.amount, - }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); - message.properties = properties; - message.context = contextualPayload; - return message; -}; - -const checkoutStepEventBuilder = (inputEvent) => { - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - const properties = { - ...inputEvent.data.checkout, - }; - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); - message.properties = properties; - message.context = contextualPayload; - return message; -}; - -const searchEventBuilder = (inputEvent) => { - const properties = { - query: inputEvent.data.searchResult.query, - }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); - message.properties = properties; - message.context = contextualPayload; - return message; -}; - const processEvent = async (inputEvent, metricMetadata) => { let message; const event = lodash.cloneDeep(inputEvent); diff --git a/src/v1/sources/shopify/utilsV2.js b/src/v1/sources/shopify/utilsV2.js new file mode 100644 index 0000000000..f88d480f96 --- /dev/null +++ b/src/v1/sources/shopify/utilsV2.js @@ -0,0 +1,167 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +const { mapObjectKeys } = require('./util'); +const Message = require('../../../v0/sources/message'); +const { EventType } = require('../../../constants'); +const { + INTEGERATION, + PIXEL_EVENT_MAPPING, + contextualFieldMapping, + cartViewedEventMapping, + productListViewedEventMapping, + productViewedEventMapping, + productToCartEventMapping, + checkoutStartedCompletedEventMapping, +} = require('./config'); + +const pageViewedEventBuilder = (inputEvent) => { + const { data, context } = inputEvent; + const pageEventContextValues = mapObjectKeys(context, contextualFieldMapping); + const message = new Message(INTEGERATION); + message.name = 'Page View'; + message.setEventType(EventType.PAGE); + message.properties = { ...data }; + message.context = { ...pageEventContextValues }; + return message; +}; + +const cartViewedEventBuilder = (inputEvent) => { + const lines = inputEvent?.data?.cart?.lines; + const products = []; + if (lines) { + lines.forEach((line) => { + const product = mapObjectKeys(line, cartViewedEventMapping); + products.push(product); + }); + } + + const properties = { + products, + cart_id: inputEvent.data.cart.id, + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName('Cart Viewed'); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const productListViewedEventBuilder = (inputEvent) => { + const productVariants = inputEvent?.data?.collection?.productVariants; + const products = []; + + productVariants.forEach((productVariant) => { + const mappedProduct = mapObjectKeys(productVariant, productListViewedEventMapping); + products.push(mappedProduct); + }); + + const properties = { + cart_id: inputEvent.clientId, + list_id: inputEvent.id, + products, + }; + + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName('Product List Viewed'); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const productViewedEventBuilder = (inputEvent) => { + const properties = { + ...mapObjectKeys(inputEvent.data, productViewedEventMapping), + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName('Product Viewed'); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const productToCartEventBuilder = (inputEvent) => { + const properties = { + ...mapObjectKeys(inputEvent.data, productToCartEventMapping), + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const checkoutEventBuilder = (inputEvent) => { + const lineItems = inputEvent?.data?.checkout?.lineItems; + const products = []; + + lineItems.forEach((lineItem) => { + const mappedProduct = mapObjectKeys(lineItem, checkoutStartedCompletedEventMapping); + products.push(mappedProduct); + }); + + const properties = { + products, + order_id: inputEvent.id, + checkout_id: inputEvent?.data?.checkout?.token, + total: inputEvent?.data?.checkout?.totalPrice?.amount, + currency: inputEvent?.data?.checkout?.currencyCode, + discount: inputEvent?.data?.checkout?.discountsAmount?.amount, + shipping: inputEvent?.data?.checkout?.shippingLine?.price?.amount, + revenue: inputEvent?.data?.checkout?.subtotalPrice?.amount, + value: inputEvent?.data?.checkout?.totalPrice?.amount, + tax: inputEvent?.data?.checkout?.totalTax?.amount, + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const checkoutStepEventBuilder = (inputEvent) => { + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + const properties = { + ...inputEvent.data.checkout, + }; + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +const searchEventBuilder = (inputEvent) => { + const properties = { + query: inputEvent.data.searchResult.query, + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + const message = new Message(INTEGERATION); + message.setEventType(EventType.TRACK); + message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); + message.properties = properties; + message.context = contextualPayload; + return message; +}; + +module.exports = { + pageViewedEventBuilder, + cartViewedEventBuilder, + productListViewedEventBuilder, + productViewedEventBuilder, + productToCartEventBuilder, + checkoutEventBuilder, + checkoutStepEventBuilder, + searchEventBuilder, +}; From 103b2ab502298ff71db62b34365de8ace5c7f389 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:55:45 +0530 Subject: [PATCH 09/22] chore: update cart viewed logic --- src/v1/sources/shopify/utilsV2.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/v1/sources/shopify/utilsV2.js b/src/v1/sources/shopify/utilsV2.js index f88d480f96..856d49a3d2 100644 --- a/src/v1/sources/shopify/utilsV2.js +++ b/src/v1/sources/shopify/utilsV2.js @@ -27,16 +27,19 @@ const pageViewedEventBuilder = (inputEvent) => { const cartViewedEventBuilder = (inputEvent) => { const lines = inputEvent?.data?.cart?.lines; const products = []; + let total; if (lines) { lines.forEach((line) => { const product = mapObjectKeys(line, cartViewedEventMapping); products.push(product); + total = line.cost.totalAmount.amount; }); } const properties = { products, cart_id: inputEvent.data.cart.id, + total, }; const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); const message = new Message(INTEGERATION); From 5051ca3a3ced4a62a05551979fa584141b25e2d5 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 16 Sep 2024 09:14:19 +0530 Subject: [PATCH 10/22] chore: refactor pixel code logic and tests --- src/v1/sources/shopify/config.js | 191 +- .../shopify/data/cartViewedEventMapping.json | 42 + .../checkoutStartedCompletedEventMapping.json | 42 + .../shopify/data/contextualFieldMapping.json | 34 + .../data/productListViewedEventMapping.json | 38 + .../data/productToCartEventMapping.json | 42 + .../data/productViewedEventMapping.json | 46 + src/v1/sources/shopify/pixelTransform.js | 98 + src/v1/sources/shopify/shopify.util.test.js | 243 + src/v1/sources/shopify/transform.js | 92 +- src/v1/sources/shopify/util.js | 35 +- .../sources/shopify/{utilsV2.js => utilV2.js} | 155 +- test/integrations/sources/shopify/data.ts | 4479 ++++++++++++++++- 13 files changed, 5187 insertions(+), 350 deletions(-) create mode 100644 src/v1/sources/shopify/data/cartViewedEventMapping.json create mode 100644 src/v1/sources/shopify/data/checkoutStartedCompletedEventMapping.json create mode 100644 src/v1/sources/shopify/data/contextualFieldMapping.json create mode 100644 src/v1/sources/shopify/data/productListViewedEventMapping.json create mode 100644 src/v1/sources/shopify/data/productToCartEventMapping.json create mode 100644 src/v1/sources/shopify/data/productViewedEventMapping.json create mode 100644 src/v1/sources/shopify/pixelTransform.js rename src/v1/sources/shopify/{utilsV2.js => utilV2.js} (56%) diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js index c02d7881f8..2a288a31d5 100644 --- a/src/v1/sources/shopify/config.js +++ b/src/v1/sources/shopify/config.js @@ -95,171 +95,32 @@ const PIXEL_EVENT_MAPPING = { search_submitted: 'Search Submitted', }; -const contextualFieldMapping = [ - { - shopifyField: 'context.document.referrer', - rudderField: 'page.referrer', - }, - { - shopifyField: 'document.title', - rudderField: 'page.title', - }, - { - shopifyField: 'navigator.userAgent', - rudderField: 'userAgent', - }, - { - shopifyField: 'window.location.href', - rudderField: 'page.url', - }, - { - shopifyField: 'window.location.pathname', - rudderField: 'page.path', - }, - { - shopifyField: 'window.location.search', - rudderField: 'page.search', - }, - { - shopifyField: 'window.screen.height', - rudderField: 'screen.height', - }, - { - shopifyField: 'window.screen.width', - rudderField: 'screen.width', - }, -]; +const identifyMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'data', 'identifyMapping.json')), +); -const cartViewedEventMapping = [ - { shopifyField: 'merchandise.product.id', rudderField: 'product_id' }, - { shopifyField: 'merchandise.product.title', rudderField: 'variant' }, - { shopifyField: 'merchandise.image.src', rudderField: 'image_url' }, - { shopifyField: 'merchandise.price.amount', rudderField: 'price' }, - { shopifyField: 'merchandise.product.type', rudderField: 'category' }, - { shopifyField: 'merchandise.product.url', rudderField: 'url' }, - { shopifyField: 'merchandise.product.vendor', rudderField: 'brand' }, - { shopifyField: 'merchandise.sku', rudderField: 'sku' }, - { shopifyField: 'merchandise.title', rudderField: 'name' }, - { shopifyField: 'quantity', rudderField: 'quantity' }, -]; +const contextualFieldMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'data', 'contextualFieldMapping.json')), +); -const productListViewedEventMapping = [ - { shopifyField: 'image.src', rudderField: 'image_url' }, - { shopifyField: 'price.amount', rudderField: 'price' }, - { shopifyField: 'product.id', rudderField: 'product_id' }, - { shopifyField: 'product.title', rudderField: 'variant' }, - { shopifyField: 'product.type', rudderField: 'category' }, - { shopifyField: 'product.url', rudderField: 'url' }, - { shopifyField: 'product.vendor', rudderField: 'brand' }, - { shopifyField: 'sku', rudderField: 'sku' }, - { shopifyField: 'title', rudderField: 'name' }, -]; +const cartViewedEventMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'data', 'cartViewedEventMapping.json')), +); -const productViewedEventMapping = [ - { - shopifyField: 'productVariant.product.id', - rudderField: 'product_id', - }, - { - shopifyField: 'productVariant.product.title', - rudderField: 'variant', - }, - { - shopifyField: 'productVariant.product.vendor', - rudderField: 'brand', - }, - { - shopifyField: 'productVariant.product.type', - rudderField: 'category', - }, - { - shopifyField: 'productVariant.product.image.src', - rudderField: 'image_url', - }, - { - shopifyField: 'productVariant.price.amount', - rudderField: 'price', - }, - { - shopifyField: 'productVariant.price.currencyCode', - rudderField: 'currency', - }, - { - shopifyField: 'productVariant.product.url', - rudderField: 'url', - }, - { - shopifyField: 'productVariant.product.sku', - rudderField: 'sku', - }, - { - shopifyField: 'productVariant.product.title', - rudderField: 'name', - }, - { - shopifyField: 'cartLine.quantity', - rudderField: 'quantity', - }, -]; +const productListViewedEventMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'data', 'productListViewedEventMapping.json')), +); -const productToCartEventMapping = [ - { - shopifyField: 'cartLine.merchandise.image.src', - rudderField: 'image_url', - }, - { - shopifyField: 'cartLine.merchandise.price.amount', - rudderField: 'price', - }, - { - shopifyField: 'cartLine.merchandise.product.id', - rudderField: 'product_id', - }, - { - shopifyField: 'cartLine.merchandise.product.title', - rudderField: 'variant', - }, - { - shopifyField: 'cartLine.merchandise.product.type', - rudderField: 'category', - }, - { - shopifyField: 'cartLine.merchandise.product.vendor', - rudderField: 'brand', - }, - { - shopifyField: 'cartLine.merchandise.product.url', - rudderField: 'url', - }, - { - shopifyField: 'cartLine.merchandise.sku', - rudderField: 'sku', - }, - { - shopifyField: 'cartLine.merchandise.title', - rudderField: 'name', - }, - { - shopifyField: 'cartLine.quantity', - rudderField: 'quantity', - }, -]; +const productViewedEventMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'data', 'productViewedEventMapping.json')), +); -const checkoutStartedCompletedEventMapping = [ - { shopifyField: 'quantity', rudderField: 'quantity' }, - { shopifyField: 'title', rudderField: 'name' }, - { shopifyField: 'variant.image.src', rudderField: 'image_url' }, - { shopifyField: 'variant.price.amount', rudderField: 'price' }, - { shopifyField: 'variant.sku', rudderField: 'sku' }, - { shopifyField: 'variant.product.id', rudderField: 'product_id' }, - { shopifyField: 'variant.product.title', rudderField: 'variant' }, - { shopifyField: 'variant.product.type', rudderField: 'category' }, - { shopifyField: 'variant.product.url', rudderField: 'url' }, - { shopifyField: 'variant.product.vendor', rudderField: 'brand' }, -]; +const productToCartEventMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'data', 'productToCartEventMapping.json')), +); -const identifyMappingJSON = JSON.parse( - fs.readFileSync(path.resolve(__dirname, 'data', 'identifyMapping.json')), +const checkoutStartedCompletedEventMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'data', 'checkoutStartedCompletedEventMapping.json')), ); const productMappingJSON = JSON.parse( @@ -364,13 +225,13 @@ module.exports = { SHOPIFY_TRACK_MAP, PIXEL_EVENT_TOPICS, PIXEL_EVENT_MAPPING, - contextualFieldMapping, - cartViewedEventMapping, - productListViewedEventMapping, - productViewedEventMapping, - productToCartEventMapping, - checkoutStartedCompletedEventMapping, useRedisDatabase, SHOPIFY_ADMIN_ONLY_EVENTS, maxTimeToIdentifyRSGeneratedCall, + contextualFieldMappingJSON, + cartViewedEventMappingJSON, + productListViewedEventMappingJSON, + productViewedEventMappingJSON, + productToCartEventMappingJSON, + checkoutStartedCompletedEventMappingJSON, }; diff --git a/src/v1/sources/shopify/data/cartViewedEventMapping.json b/src/v1/sources/shopify/data/cartViewedEventMapping.json new file mode 100644 index 0000000000..b74320c758 --- /dev/null +++ b/src/v1/sources/shopify/data/cartViewedEventMapping.json @@ -0,0 +1,42 @@ +[ + { + "sourceKeys": "merchandise.product.id", + "destKeys": "product_id" + }, + { + "sourceKeys": "merchandise.product.title", + "destKeys": "variant" + }, + { + "sourceKeys": "merchandise.image.src", + "destKeys": "image_url" + }, + { + "sourceKeys": "merchandise.price.amount", + "destKeys": "price" + }, + { + "sourceKeys": "merchandise.product.type", + "destKeys": "category" + }, + { + "sourceKeys": "merchandise.product.url", + "destKeys": "url" + }, + { + "sourceKeys": "merchandise.product.vendor", + "destKeys": "brand" + }, + { + "sourceKeys": "merchandise.sku", + "destKeys": "sku" + }, + { + "sourceKeys": "merchandise.title", + "destKeys": "name" + }, + { + "sourceKeys": "quantity", + "destKeys": "quantity" + } +] diff --git a/src/v1/sources/shopify/data/checkoutStartedCompletedEventMapping.json b/src/v1/sources/shopify/data/checkoutStartedCompletedEventMapping.json new file mode 100644 index 0000000000..478bcfc270 --- /dev/null +++ b/src/v1/sources/shopify/data/checkoutStartedCompletedEventMapping.json @@ -0,0 +1,42 @@ +[ + { + "sourceKeys": "quantity", + "destKeys": "quantity" + }, + { + "sourceKeys": "title", + "destKeys": "name" + }, + { + "sourceKeys": "variant.image.src", + "destKeys": "image_url" + }, + { + "sourceKeys": "variant.price.amount", + "destKeys": "price" + }, + { + "sourceKeys": "variant.sku", + "destKeys": "sku" + }, + { + "sourceKeys": "variant.product.id", + "destKeys": "product_id" + }, + { + "sourceKeys": "variant.product.title", + "destKeys": "variant" + }, + { + "sourceKeys": "variant.product.type", + "destKeys": "category" + }, + { + "sourceKeys": "variant.product.url", + "destKeys": "url" + }, + { + "sourceKeys": "variant.product.vendor", + "destKeys": "brand" + } +] diff --git a/src/v1/sources/shopify/data/contextualFieldMapping.json b/src/v1/sources/shopify/data/contextualFieldMapping.json new file mode 100644 index 0000000000..f314684948 --- /dev/null +++ b/src/v1/sources/shopify/data/contextualFieldMapping.json @@ -0,0 +1,34 @@ +[ + { + "sourceKeys": "context.document.referrer", + "destKeys": "page.referrer" + }, + { + "sourceKeys": "document.title", + "destKeys": "page.title" + }, + { + "sourceKeys": "navigator.userAgent", + "destKeys": "userAgent" + }, + { + "sourceKeys": "window.location.href", + "destKeys": "page.url" + }, + { + "sourceKeys": "window.location.pathname", + "destKeys": "page.path" + }, + { + "sourceKeys": "window.location.search", + "destKeys": "page.search" + }, + { + "sourceKeys": "window.screen.height", + "destKeys": "screen.height" + }, + { + "sourceKeys": "window.screen.width", + "destKeys": "screen.width" + } +] diff --git a/src/v1/sources/shopify/data/productListViewedEventMapping.json b/src/v1/sources/shopify/data/productListViewedEventMapping.json new file mode 100644 index 0000000000..fb8e8a4567 --- /dev/null +++ b/src/v1/sources/shopify/data/productListViewedEventMapping.json @@ -0,0 +1,38 @@ +[ + { + "sourceKeys": "image.src", + "destKeys": "image_url" + }, + { + "sourceKeys": "price.amount", + "destKeys": "price" + }, + { + "sourceKeys": "product.id", + "destKeys": "product_id" + }, + { + "sourceKeys": "product.title", + "destKeys": "variant" + }, + { + "sourceKeys": "product.type", + "destKeys": "category" + }, + { + "sourceKeys": "product.url", + "destKeys": "url" + }, + { + "sourceKeys": "product.vendor", + "destKeys": "brand" + }, + { + "sourceKeys": "sku", + "destKeys": "sku" + }, + { + "sourceKeys": "title", + "destKeys": "name" + } +] diff --git a/src/v1/sources/shopify/data/productToCartEventMapping.json b/src/v1/sources/shopify/data/productToCartEventMapping.json new file mode 100644 index 0000000000..2f9d71bc03 --- /dev/null +++ b/src/v1/sources/shopify/data/productToCartEventMapping.json @@ -0,0 +1,42 @@ +[ + { + "sourceKeys": "cartLine.merchandise.image.src", + "destKeys": "image_url" + }, + { + "sourceKeys": "cartLine.merchandise.price.amount", + "destKeys": "price" + }, + { + "sourceKeys": "cartLine.merchandise.product.id", + "destKeys": "product_id" + }, + { + "sourceKeys": "cartLine.merchandise.product.title", + "destKeys": "variant" + }, + { + "sourceKeys": "cartLine.merchandise.product.type", + "destKeys": "category" + }, + { + "sourceKeys": "cartLine.merchandise.product.vendor", + "destKeys": "brand" + }, + { + "sourceKeys": "cartLine.merchandise.product.url", + "destKeys": "url" + }, + { + "sourceKeys": "cartLine.merchandise.sku", + "destKeys": "sku" + }, + { + "sourceKeys": "cartLine.merchandise.title", + "destKeys": "name" + }, + { + "sourceKeys": "cartLine.quantity", + "destKeys": "quantity" + } +] diff --git a/src/v1/sources/shopify/data/productViewedEventMapping.json b/src/v1/sources/shopify/data/productViewedEventMapping.json new file mode 100644 index 0000000000..becb15acfc --- /dev/null +++ b/src/v1/sources/shopify/data/productViewedEventMapping.json @@ -0,0 +1,46 @@ +[ + { + "sourceKeys": "productVariant.product.id", + "destKeys": "product_id" + }, + { + "sourceKeys": "productVariant.product.title", + "destKeys": "variant" + }, + { + "sourceKeys": "productVariant.product.vendor", + "destKeys": "brand" + }, + { + "sourceKeys": "productVariant.product.type", + "destKeys": "category" + }, + { + "sourceKeys": "productVariant.product.image.src", + "destKeys": "image_url" + }, + { + "sourceKeys": "productVariant.price.amount", + "destKeys": "price" + }, + { + "sourceKeys": "productVariant.price.currencyCode", + "destKeys": "currency" + }, + { + "sourceKeys": "productVariant.product.url", + "destKeys": "url" + }, + { + "sourceKeys": "productVariant.product.sku", + "destKeys": "sku" + }, + { + "sourceKeys": "productVariant.product.title", + "destKeys": "name" + }, + { + "sourceKeys": "cartLine.quantity", + "destKeys": "quantity" + } +] diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/pixelTransform.js new file mode 100644 index 0000000000..a5799c5e96 --- /dev/null +++ b/src/v1/sources/shopify/pixelTransform.js @@ -0,0 +1,98 @@ +const stats = require('../../../util/stats'); +const logger = require('../../../logger'); +const { processEvent } = require('./transform'); +const { removeUndefinedAndNullValues } = require('../../../v0/util'); +const { + pageViewedEventBuilder, + cartViewedEventBuilder, + productListViewedEventBuilder, + productViewedEventBuilder, + productToCartEventBuilder, + checkoutEventBuilder, + checkoutStepEventBuilder, + searchEventBuilder, +} = require('./utilV2'); +const { INTEGERATION, PIXEL_EVENT_TOPICS } = require('./config'); + +const NO_OPERATION_SUCCESS = { + outputToSource: { + body: Buffer.from('OK').toString('base64'), + contentType: 'text/plain', + }, + statusCode: 200, +}; + +function processPixelEvent(inputEvent) { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { name, query_parameters, clientId, data } = inputEvent; + const { checkout } = data ?? {}; + const { order } = checkout ?? {}; + const { customer } = order ?? {}; + let message; + switch (name) { + case PIXEL_EVENT_TOPICS.PAGE_VIEWED: + message = pageViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.CART_VIEWED: + message = cartViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.COLLECTION_VIEWED: + message = productListViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.PRODUCT_VIEWED: + message = productViewedEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.PRODUCT_ADDED_TO_CART: + case PIXEL_EVENT_TOPICS.PRODUCT_REMOVED_FROM_CART: + message = productToCartEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.CHECKOUT_STARTED: + case PIXEL_EVENT_TOPICS.CHECKOUT_COMPLETED: + if (customer.id) message.userId = customer.id || ''; + message = checkoutEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.CHECKOUT_ADDRESS_INFO_SUBMITTED: + case PIXEL_EVENT_TOPICS.CHECKOUT_CONTACT_INFO_SUBMITTED: + case PIXEL_EVENT_TOPICS.CHECKOUT_SHIPPING_INFO_SUBMITTED: + case PIXEL_EVENT_TOPICS.PAYMENT_INFO_SUBMITTED: + if (customer.id) message.userId = customer.id || ''; + message = checkoutStepEventBuilder(inputEvent); + break; + case PIXEL_EVENT_TOPICS.SEARCH_SUBMITTED: + message = searchEventBuilder(inputEvent); + break; + default: + logger.debug(`{{SHOPIFY::}} Invalid pixel event ${name}`); + stats.increment('invalid_shopify_event', { + writeKey: query_parameters.writeKey, + source: 'SHOPIFY', + shopifyTopic: name, + }); + return NO_OPERATION_SUCCESS; + } + message.anonymousId = clientId; + message.setProperty(`integrations.${INTEGERATION}`, true); + message.setProperty('context.library', { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }); + message.setProperty('context.topic', name); + message = removeUndefinedAndNullValues(message); + return message; +} + +const processEventV2 = async (event, metricMetadata) => { + const { pixelEventLabel } = event; + if (pixelEventLabel) { + // this is a event fired from the web pixel loaded on the browser + // by the user interactions with the store. + const pixelEvent = processPixelEvent(event); + return removeUndefinedAndNullValues(pixelEvent); + } + return processEvent(event, metricMetadata); +}; + +module.exports = { + processEventV2, + processPixelEvent, +}; diff --git a/src/v1/sources/shopify/shopify.util.test.js b/src/v1/sources/shopify/shopify.util.test.js index d058db36b5..318464c051 100644 --- a/src/v1/sources/shopify/shopify.util.test.js +++ b/src/v1/sources/shopify/shopify.util.test.js @@ -1,5 +1,18 @@ const { getShopifyTopic } = require('./util'); +const { + pageViewedEventBuilder, + cartViewedEventBuilder, + productListViewedEventBuilder, + productViewedEventBuilder, + productToCartEventBuilder, + checkoutEventBuilder, + checkoutStepEventBuilder, + searchEventBuilder, +} = require('./utilV2'); +const { EventType } = require('../../../constants'); +const Message = require('../../../v0/sources/message'); jest.mock('ioredis', () => require('../../../../test/__mocks__/redis')); +jest.mock('../../../v0/sources/message'); describe('Shopify Utils Test', () => { describe('Fetching Shopify Topic Test Cases', () => { it('Invalid Topic Test', () => { @@ -58,3 +71,233 @@ describe('Shopify Utils Test', () => { }); }); }); + +describe('utilV2.js', () => { + beforeEach(() => { + Message.mockClear(); + }); + + describe('pageViewedEventBuilder', () => { + it('should build a page viewed event message', () => { + const inputEvent = { + data: { url: 'https://example.com' }, + context: { userAgent: 'Mozilla/5.0' }, + }; + const message = pageViewedEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.name).toBe('Page View'); + expect(message.properties).toEqual(inputEvent.data); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('cartViewedEventBuilder', () => { + it('should build a cart viewed event message', () => { + const inputEvent = { + data: { + cart: { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + lines: [ + { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + merchandise: { + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + title: 'The Multi-managed Snowboard', + }, + id: '41327143157873', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + quantity: 2, + }, + ], + totalQuantity: 2, + attributes: [], + id: '123', + }, + }, + context: { userAgent: 'Mozilla/5.0' }, + }; + const message = cartViewedEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ + products: [ + { + name: 'Default Title', + price: 629.95, + quantity: 2, + variant: 'The Multi-managed Snowboard', + merchandise: { + id: '41327143157873', + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + title: 'The Multi-managed Snowboard', + }, + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + cost: { + totalAmount: { amount: 1259.9, currencyCode: 'USD' }, + }, + }, + ], + cart_id: '123', + total: 1259.9, + }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('productListViewedEventBuilder', () => { + it('should build a product list viewed event message', () => { + const inputEvent = { + data: { + collection: { + productVariants: [ + { id: 'product123', name: 'Product 123' }, + { id: 'product456', name: 'Product 456' }, + ], + }, + }, + clientId: 'client123', + id: 'list123', + context: { userAgent: 'Mozilla/5.0' }, + }; + const message = productListViewedEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ + cart_id: 'client123', + list_id: 'list123', + products: [ + { id: 'product123', name: 'Product 123' }, + { id: 'product456', name: 'Product 456' }, + ], + }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('productViewedEventBuilder', () => { + it('should build a product viewed event message', () => { + const inputEvent = { + data: { id: 'product123', name: 'Product 123' }, + context: { userAgent: 'Mozilla/5.0' }, + }; + const message = productViewedEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ id: 'product123', name: 'Product 123' }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('productToCartEventBuilder', () => { + it('should build a product to cart event message', () => { + const inputEvent = { + data: { id: 'product123', name: 'Product 123' }, + context: { userAgent: 'Mozilla/5.0' }, + name: 'add_to_cart', + }; + const message = productToCartEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ id: 'product123', name: 'Product 123' }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('checkoutEventBuilder', () => { + it('should build a checkout event message', () => { + const inputEvent = { + data: { + checkout: { + lineItems: [ + { id: 'product123', name: 'Product 123' }, + { id: 'product456', name: 'Product 456' }, + ], + token: 'checkout123', + totalPrice: { amount: 200 }, + currencyCode: 'USD', + discountsAmount: { amount: 10 }, + shippingLine: { price: { amount: 5 } }, + subtotalPrice: { amount: 185 }, + totalTax: { amount: 15 }, + }, + }, + id: 'order123', + context: { userAgent: 'Mozilla/5.0' }, + name: 'checkout_started', + }; + const message = checkoutEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ + products: [ + { id: 'product123', name: 'Product 123' }, + { id: 'product456', name: 'Product 456' }, + ], + order_id: 'order123', + checkout_id: 'checkout123', + total: 200, + currency: 'USD', + discount: 10, + shipping: 5, + revenue: 185, + value: 200, + tax: 15, + }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('checkoutStepEventBuilder', () => { + it('should build a checkout step event message', () => { + const inputEvent = { + data: { + checkout: { + step: 1, + action: 'shipping_info_submitted', + }, + }, + context: { userAgent: 'Mozilla/5.0' }, + name: 'checkout_step', + }; + const message = checkoutStepEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ step: 1, action: 'shipping_info_submitted' }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); + + describe('searchEventBuilder', () => { + it('should build a search event message', () => { + const inputEvent = { + data: { + searchResult: { + query: 'test query', + }, + }, + context: { userAgent: 'Mozilla/5.0' }, + name: 'search_submitted', + }; + const message = searchEventBuilder(inputEvent); + expect(message).toBeInstanceOf(Message); + expect(message.properties).toEqual({ query: 'test query' }); + expect(message.context).toEqual({ userAgent: 'Mozilla/5.0' }); + }); + }); +}); diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index 0c3df95ac7..2e22ffbfea 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -18,16 +18,7 @@ const { RedisDB } = require('../../../util/redis/redisConnector'); const { removeUndefinedAndNullValues, isDefinedAndNotNull } = require('../../../v0/util'); const Message = require('../../../v0/sources/message'); const { EventType } = require('../../../constants'); -const { - pageViewedEventBuilder, - cartViewedEventBuilder, - productListViewedEventBuilder, - productViewedEventBuilder, - productToCartEventBuilder, - checkoutEventBuilder, - checkoutStepEventBuilder, - searchEventBuilder, -} = require('./utilsV2'); +const { processEventV2 } = require('./pixelTransform'); const { INTEGERATION, MAPPING_CATEGORIES, @@ -36,7 +27,6 @@ const { RUDDER_ECOM_MAP, SUPPORTED_TRACK_EVENTS, SHOPIFY_TRACK_MAP, - PIXEL_EVENT_TOPICS, useRedisDatabase, } = require('./config'); @@ -287,73 +277,6 @@ const processIdentifierEvent = async (event, metricMetadata) => { return NO_OPERATION_SUCCESS; }; -function processPixelEvent(inputEvent) { - const { name, query_parameters, clientId, data } = inputEvent; - const { checkout } = data ?? {}; - const { order } = checkout ?? {}; - const { customer } = order ?? {}; - let message; - switch (name) { - case PIXEL_EVENT_TOPICS.PAGE_VIEWED: - message = pageViewedEventBuilder(inputEvent); - break; - case PIXEL_EVENT_TOPICS.CART_VIEWED: - message = cartViewedEventBuilder(inputEvent); - break; - case PIXEL_EVENT_TOPICS.COLLECTION_VIEWED: - message = productListViewedEventBuilder(inputEvent); - break; - case PIXEL_EVENT_TOPICS.PRODUCT_VIEWED: - message = productViewedEventBuilder(inputEvent); - break; - case PIXEL_EVENT_TOPICS.PRODUCT_ADDED_TO_CART: - case PIXEL_EVENT_TOPICS.PRODUCT_REMOVED_FROM_CART: - message = productToCartEventBuilder(inputEvent); - break; - case PIXEL_EVENT_TOPICS.CHECKOUT_STARTED: - case PIXEL_EVENT_TOPICS.CHECKOUT_COMPLETED: - if (customer.id) message.userId = customer.id || ''; - message = checkoutEventBuilder(inputEvent); - break; - case PIXEL_EVENT_TOPICS.CHECKOUT_ADDRESS_INFO_SUBMITTED: - case PIXEL_EVENT_TOPICS.CHECKOUT_CONTACT_INFO_SUBMITTED: - case PIXEL_EVENT_TOPICS.CHECKOUT_SHIPPING_INFO_SUBMITTED: - case PIXEL_EVENT_TOPICS.PAYMENT_INFO_SUBMITTED: - if (customer.id) message.userId = customer.id || ''; - message = checkoutStepEventBuilder(inputEvent); - break; - case PIXEL_EVENT_TOPICS.SEARCH_SUBMITTED: - message = searchEventBuilder(inputEvent); - break; - default: - logger.debug(`{{SHOPIFY::}} Invalid pixel event ${name}`); - stats.increment('invalid_shopify_event', { - writeKey: query_parameters.writeKey, - source: 'SHOPIFY', - shopifyTopic: name, - }); - return NO_OPERATION_SUCCESS; - } - message.anonymousId = clientId; - message.setProperty(`integrations.${INTEGERATION}`, true); - message.setProperty('context.library', { - name: 'RudderStack Shopify Cloud', - version: '2.0.0', - }); - message.setProperty('context.topic', name); - message = removeUndefinedAndNullValues(message); - return message; -} - -const processEventV2 = async (event, metricMetadata) => { - const { pixelEventLabel } = event; - if (pixelEventLabel) { - // this is a web pixel event fired from the browser - const pixelEvent = processPixelEvent(event); - return removeUndefinedAndNullValues(pixelEvent); - } - return processEvent(event, metricMetadata); -}; const process = async (inputEvent) => { const { event, source } = inputEvent; const metricMetadata = { @@ -361,12 +284,11 @@ const process = async (inputEvent) => { writeKey: event.query_parameters?.writeKey?.[0], source: 'SHOPIFY', }; - if (source) { - const { version } = source.Config; - if (version === 'v2') { - const responseV2 = await processEventV2(event, metricMetadata); - return responseV2; - } + // check on the source Config to identify the event is from the tracker-based (legacy) + // or the pixel-based (latest) implementation. + if (source && isDefinedAndNotNull(source.Config) && source?.Config?.version === 'v2') { + const responseV2 = await processEventV2(event, metricMetadata); + return responseV2; } if (isIdentifierEvent(event)) { return processIdentifierEvent(event, metricMetadata); @@ -375,4 +297,4 @@ const process = async (inputEvent) => { return response; }; -exports.process = process; +module.exports = { process, processEvent }; diff --git a/src/v1/sources/shopify/util.js b/src/v1/sources/shopify/util.js index e2645d54c4..70f541f6aa 100644 --- a/src/v1/sources/shopify/util.js +++ b/src/v1/sources/shopify/util.js @@ -1,3 +1,4 @@ +/* eslint-disable no-param-reassign */ /* eslint-disable camelcase */ /* eslint-disable @typescript-eslint/naming-convention */ const { v5 } = require('uuid'); @@ -272,39 +273,6 @@ const checkAndUpdateCartItems = async (inputEvent, redisData, metricMetadata, sh return true; }; -function getNestedValue(obj, path) { - const parts = path.split('.'); - return parts.reduce((acc, part) => acc && acc[part], obj); -} - -function setNestedValue(obj, path, value) { - const parts = path.split('.'); - const lastIndex = parts.length - 1; - parts.reduce((acc, part, index) => { - if (index === lastIndex) { - acc[part] = value; - } else if (!acc[part]) { - acc[part] = {}; - } - return acc[part]; - }, obj); -} - -function mapObjectKeys(obj, mapping) { - if (!Array.isArray(mapping)) { - throw new TypeError('mapping should be an array'); - } - const acc = { ...obj }; - - return mapping.reduce((accumulator, { shopifyField, rudderField }) => { - const value = getNestedValue(obj, shopifyField); - if (value !== undefined) { - setNestedValue(accumulator, rudderField, value); - } - return acc; - }, acc); -} - const pixelEventBuilder = (inputEvent) => { const { event: eventName, properties } = inputEvent; const { currency, value, content_ids, content_type } = properties; @@ -335,5 +303,4 @@ module.exports = { getHashLineItems, getDataFromRedis, pixelEventBuilder, - mapObjectKeys, }; diff --git a/src/v1/sources/shopify/utilsV2.js b/src/v1/sources/shopify/utilV2.js similarity index 56% rename from src/v1/sources/shopify/utilsV2.js rename to src/v1/sources/shopify/utilV2.js index 856d49a3d2..92197a558b 100644 --- a/src/v1/sources/shopify/utilsV2.js +++ b/src/v1/sources/shopify/utilV2.js @@ -1,21 +1,63 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -const { mapObjectKeys } = require('./util'); +/* eslint-disable no-param-reassign */ const Message = require('../../../v0/sources/message'); const { EventType } = require('../../../constants'); const { INTEGERATION, PIXEL_EVENT_MAPPING, - contextualFieldMapping, - cartViewedEventMapping, - productListViewedEventMapping, - productViewedEventMapping, - productToCartEventMapping, - checkoutStartedCompletedEventMapping, + contextualFieldMappingJSON, + cartViewedEventMappingJSON, + productListViewedEventMappingJSON, + productViewedEventMappingJSON, + productToCartEventMappingJSON, + checkoutStartedCompletedEventMappingJSON, } = require('./config'); +function getNestedValue(object, path) { + const keys = path.split('.'); + return keys.reduce((nestedObject, key) => nestedObject && nestedObject[key], object); +} + +function setNestedValue(object, path, value) { + const keys = path.split('.'); + const lastKeyIndex = keys.length - 1; + keys.reduce((nestedObject, key, index) => { + if (index === lastKeyIndex) { + nestedObject[key] = value; + } else if (!nestedObject[key]) { + nestedObject[key] = {}; + } + return nestedObject[key]; + }, object); +} + +function mapObjectKeys(sourceObject, keyMappings) { + if (!Array.isArray(keyMappings)) { + throw new TypeError('keyMappings should be an array'); + } + const resultObject = { ...sourceObject }; + + // eslint-disable-next-line @typescript-eslint/no-shadow + return keyMappings.reduce((resultObject, { sourceKeys, destKeys }) => { + const value = getNestedValue(sourceObject, sourceKeys); + if (value !== undefined) { + setNestedValue(resultObject, destKeys, value); + } + return resultObject; + }, resultObject); +} + +const createMessage = (eventType, eventName, properties, context) => { + const message = new Message(INTEGERATION); + message.setEventType(eventType); + message.setEventName(eventName); + message.properties = properties; + message.context = context; + return message; +}; + const pageViewedEventBuilder = (inputEvent) => { const { data, context } = inputEvent; - const pageEventContextValues = mapObjectKeys(context, contextualFieldMapping); + const pageEventContextValues = mapObjectKeys(context, contextualFieldMappingJSON); const message = new Message(INTEGERATION); message.name = 'Page View'; message.setEventType(EventType.PAGE); @@ -30,7 +72,7 @@ const cartViewedEventBuilder = (inputEvent) => { let total; if (lines) { lines.forEach((line) => { - const product = mapObjectKeys(line, cartViewedEventMapping); + const product = mapObjectKeys(line, cartViewedEventMappingJSON); products.push(product); total = line.cost.totalAmount.amount; }); @@ -41,13 +83,8 @@ const cartViewedEventBuilder = (inputEvent) => { cart_id: inputEvent.data.cart.id, total, }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName('Cart Viewed'); - message.properties = properties; - message.context = contextualPayload; - return message; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage(EventType.TRACK, 'Cart Viewed', properties, contextualPayload); }; const productListViewedEventBuilder = (inputEvent) => { @@ -55,7 +92,7 @@ const productListViewedEventBuilder = (inputEvent) => { const products = []; productVariants.forEach((productVariant) => { - const mappedProduct = mapObjectKeys(productVariant, productListViewedEventMapping); + const mappedProduct = mapObjectKeys(productVariant, productListViewedEventMappingJSON); products.push(mappedProduct); }); @@ -65,40 +102,29 @@ const productListViewedEventBuilder = (inputEvent) => { products, }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName('Product List Viewed'); - message.properties = properties; - message.context = contextualPayload; - return message; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage(EventType.TRACK, 'Product List Viewed', properties, contextualPayload); }; const productViewedEventBuilder = (inputEvent) => { const properties = { - ...mapObjectKeys(inputEvent.data, productViewedEventMapping), + ...mapObjectKeys(inputEvent.data, productViewedEventMappingJSON), }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName('Product Viewed'); - message.properties = properties; - message.context = contextualPayload; - return message; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage(EventType.TRACK, 'Product Viewed', properties, contextualPayload); }; const productToCartEventBuilder = (inputEvent) => { const properties = { - ...mapObjectKeys(inputEvent.data, productToCartEventMapping), + ...mapObjectKeys(inputEvent.data, productToCartEventMappingJSON), }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); - message.properties = properties; - message.context = contextualPayload; - return message; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage( + EventType.TRACK, + PIXEL_EVENT_MAPPING[inputEvent.name], + properties, + contextualPayload, + ); }; const checkoutEventBuilder = (inputEvent) => { @@ -106,7 +132,7 @@ const checkoutEventBuilder = (inputEvent) => { const products = []; lineItems.forEach((lineItem) => { - const mappedProduct = mapObjectKeys(lineItem, checkoutStartedCompletedEventMapping); + const mappedProduct = mapObjectKeys(lineItem, checkoutStartedCompletedEventMappingJSON); products.push(mappedProduct); }); @@ -122,40 +148,39 @@ const checkoutEventBuilder = (inputEvent) => { value: inputEvent?.data?.checkout?.totalPrice?.amount, tax: inputEvent?.data?.checkout?.totalTax?.amount, }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); - message.properties = properties; - message.context = contextualPayload; - return message; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage( + EventType.TRACK, + PIXEL_EVENT_MAPPING[inputEvent.name], + properties, + contextualPayload, + ); }; const checkoutStepEventBuilder = (inputEvent) => { - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); const properties = { ...inputEvent.data.checkout, }; - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); - message.properties = properties; - message.context = contextualPayload; - return message; + return createMessage( + EventType.TRACK, + PIXEL_EVENT_MAPPING[inputEvent.name], + properties, + contextualPayload, + ); }; const searchEventBuilder = (inputEvent) => { const properties = { query: inputEvent.data.searchResult.query, }; - const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMapping); - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName(PIXEL_EVENT_MAPPING[inputEvent.name]); - message.properties = properties; - message.context = contextualPayload; - return message; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage( + EventType.TRACK, + PIXEL_EVENT_MAPPING[inputEvent.name], + properties, + contextualPayload, + ); }; module.exports = { diff --git a/test/integrations/sources/shopify/data.ts b/test/integrations/sources/shopify/data.ts index f5eb3c148b..2bee61ca5b 100644 --- a/test/integrations/sources/shopify/data.ts +++ b/test/integrations/sources/shopify/data.ts @@ -1,6 +1,4481 @@ import { skip } from 'node:test'; -export const data = [ +const dummySourceConfig = { + ID: 'dummy-source-id', + OriginalID: '', + Name: 'Shopify v2', + Config: { + disableClientSideIdentifier: false, + eventUpload: false, + version: 'v2', + }, + Enabled: true, + WorkspaceID: 'dummy-workspace-id', + Destinations: null, + WriteKey: 'dummy-write-key', +}; + +const pixelEventsTestScenarios = [ + { + name: 'shopify', + description: 'Page Call -> page_view event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6b6f548-5FEF-4DAE-9CAB-39EE6F94E09B', + name: 'page_viewed', + data: {}, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T17:24:30.373Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + characterSet: 'UTF-8', + title: 'pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['page_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/', + port: '', + protocol: 'https:', + search: '', + }, + referrer: + 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + characterSet: 'UTF-8', + title: 'pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'pixel-testing-rs', + url: 'https://store.myshopify.com/', + path: '/', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'page_viewed', + }, + integrations: { + SHOPIFY: true, + }, + name: 'Page View', + type: 'page', + properties: {}, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> product_viewed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6c07b5a-D20A-4E5F-812E-337299B56C34', + name: 'product_viewed', + data: { + productVariant: { + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + id: '7234590834801', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + type: 'snowboard', + }, + id: '41327143321713', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + sku: '', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T17:34:54.889Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/products/the-collection-snowboard-liquid', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/', + characterSet: 'UTF-8', + title: 'The Collection Snowboard: Liquid – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/products/the-collection-snowboard-liquid', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['product_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/products/the-collection-snowboard-liquid', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/', + characterSet: 'UTF-8', + title: 'The Collection Snowboard: Liquid – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/products/the-collection-snowboard-liquid', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'The Collection Snowboard: Liquid – pixel-testing-rs', + url: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + path: '/products/the-collection-snowboard-liquid', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'product_viewed', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product Viewed', + properties: { + productVariant: { + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + id: '7234590834801', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + type: 'snowboard', + }, + id: '41327143321713', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + sku: '', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + product_id: '7234590834801', + variant: 'The Collection Snowboard: Liquid', + brand: 'Hydrogen Vendor', + category: 'snowboard', + price: 749.95, + currency: 'USD', + url: '/products/the-collection-snowboard-liquid', + name: 'The Collection Snowboard: Liquid', + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> cart_viewed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'shu-f6eecef1-4132-459F-CDB5-681DA3DD61CD', + name: 'cart_viewed', + data: { + cart: { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + lines: [ + { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + merchandise: { + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + id: '7234590736497', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + type: 'snowboard', + }, + id: '41327143157873', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', + }, + sku: 'sku-managed-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + quantity: 2, + }, + ], + totalQuantity: 2, + attributes: [], + id: 'Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T18:25:30.125Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/cart', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/cart', + port: '', + protocol: 'https:', + search: '', + }, + referrer: '', + characterSet: 'UTF-8', + title: 'Your Shopping Cart – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/cart', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/cart', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['cart_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/cart', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/cart', + port: '', + protocol: 'https:', + search: '', + }, + referrer: '', + characterSet: 'UTF-8', + title: 'Your Shopping Cart – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/cart', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/cart', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Your Shopping Cart – pixel-testing-rs', + url: 'https://store.myshopify.com/cart', + path: '/cart', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'cart_viewed', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Cart Viewed', + properties: { + products: [ + { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + merchandise: { + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + id: '7234590736497', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + type: 'snowboard', + }, + id: '41327143157873', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', + }, + sku: 'sku-managed-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + quantity: 2, + product_id: '7234590736497', + variant: 'The Multi-managed Snowboard', + image_url: + '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', + price: 629.95, + category: 'snowboard', + url: '/products/the-multi-managed-snowboard', + brand: 'Multi-managed Vendor', + sku: 'sku-managed-1', + name: 'Default Title', + }, + ], + cart_id: 'Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + total: 1259.9, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> collection_viewed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6f0c6be-43F8-47D2-5F94-C22AD5ED3E79', + name: 'collection_viewed', + data: { + collection: { + id: '', + title: 'Products', + productVariants: [ + { + price: { + amount: 10, + currencyCode: 'USD', + }, + product: { + title: 'Gift Card', + vendor: 'Snowboard Vendor', + id: '7234590605425', + untranslatedTitle: 'Gift Card', + url: '/products/gift-card', + type: 'giftcard', + }, + id: '41327142895729', + image: { + src: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + }, + sku: '', + title: '$10', + untranslatedTitle: '$10', + }, + { + price: { + amount: 24.95, + currencyCode: 'USD', + }, + product: { + title: 'Selling Plans Ski Wax', + vendor: 'pixel-testing-rs', + id: '7234590802033', + untranslatedTitle: 'Selling Plans Ski Wax', + url: '/products/selling-plans-ski-wax', + type: 'accessories', + }, + id: '41327143223409', + image: { + src: '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', + }, + sku: '', + title: 'Selling Plans Ski Wax', + untranslatedTitle: 'Selling Plans Ski Wax', + }, + { + price: { + amount: 2629.95, + currencyCode: 'USD', + }, + product: { + title: 'The 3p Fulfilled Snowboard', + vendor: 'pixel-testing-rs', + id: '7234590703729', + untranslatedTitle: 'The 3p Fulfilled Snowboard', + url: '/products/the-3p-fulfilled-snowboard', + type: 'snowboard', + }, + id: '41327143125105', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', + }, + sku: 'sku-hosted-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + ], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T18:27:39.197Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/collections/all', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/collections/all', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Products – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/collections/all', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/collections/all', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['collection_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/collections/all', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/collections/all', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Products – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/collections/all', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/collections/all', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Products – pixel-testing-rs', + url: 'https://store.myshopify.com/collections/all', + path: '/collections/all', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'collection_viewed', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product List Viewed', + properties: { + cart_id: 'c7b3f99b-4d34-463b-835f-c879482a7750', + list_id: 'sh-f6f0c6be-43F8-47D2-5F94-C22AD5ED3E79', + products: [ + { + price: 10, + product: { + title: 'Gift Card', + vendor: 'Snowboard Vendor', + id: '7234590605425', + untranslatedTitle: 'Gift Card', + url: '/products/gift-card', + type: 'giftcard', + }, + id: '41327142895729', + image: { + src: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + }, + sku: '', + title: '$10', + untranslatedTitle: '$10', + image_url: + '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + product_id: '7234590605425', + variant: 'Gift Card', + category: 'giftcard', + url: '/products/gift-card', + brand: 'Snowboard Vendor', + name: '$10', + }, + { + price: 24.95, + product: { + title: 'Selling Plans Ski Wax', + vendor: 'pixel-testing-rs', + id: '7234590802033', + untranslatedTitle: 'Selling Plans Ski Wax', + url: '/products/selling-plans-ski-wax', + type: 'accessories', + }, + id: '41327143223409', + image: { + src: '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', + }, + sku: '', + title: 'Selling Plans Ski Wax', + untranslatedTitle: 'Selling Plans Ski Wax', + image_url: + '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', + product_id: '7234590802033', + variant: 'Selling Plans Ski Wax', + category: 'accessories', + url: '/products/selling-plans-ski-wax', + brand: 'pixel-testing-rs', + name: 'Selling Plans Ski Wax', + }, + { + price: 2629.95, + product: { + title: 'The 3p Fulfilled Snowboard', + vendor: 'pixel-testing-rs', + id: '7234590703729', + untranslatedTitle: 'The 3p Fulfilled Snowboard', + url: '/products/the-3p-fulfilled-snowboard', + type: 'snowboard', + }, + id: '41327143125105', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', + }, + sku: 'sku-hosted-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + image_url: + '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', + product_id: '7234590703729', + variant: 'The 3p Fulfilled Snowboard', + category: 'snowboard', + url: '/products/the-3p-fulfilled-snowboard', + brand: 'pixel-testing-rs', + name: 'Default Title', + }, + ], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> product_added_to_cart event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6f828db-F77B-43E8-96C4-1D51DACD52A3', + name: 'product_added_to_cart', + data: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T18:34:42.625Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/products/the-collection-snowboard-liquid', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/collections/all', + characterSet: 'UTF-8', + title: 'The Collection Snowboard: Liquid – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/products/the-collection-snowboard-liquid', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['carts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/products/the-collection-snowboard-liquid', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/collections/all', + characterSet: 'UTF-8', + title: 'The Collection Snowboard: Liquid – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/products/the-collection-snowboard-liquid', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'The Collection Snowboard: Liquid – pixel-testing-rs', + url: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', + path: '/products/the-collection-snowboard-liquid', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'product_added_to_cart', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product Added', + properties: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + price: 749.95, + product_id: '7234590834801', + variant: 'The Collection Snowboard: Liquid', + category: 'snowboard', + brand: 'Hydrogen Vendor', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + sku: '', + name: null, + quantity: 1, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> product_removed_from_cart event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'shu-f778d1eb-9B83-4832-9DC0-5C3B33A809F0', + name: 'product_removed_from_cart', + data: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T20:56:00.125Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/cart', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/cart', + port: '', + protocol: 'https:', + search: '', + }, + referrer: '', + characterSet: 'UTF-8', + title: 'Your Shopping Cart – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/cart', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/cart', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['carts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/cart', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/cart', + port: '', + protocol: 'https:', + search: '', + }, + referrer: '', + characterSet: 'UTF-8', + title: 'Your Shopping Cart – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/cart', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/cart', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Your Shopping Cart – pixel-testing-rs', + url: 'https://store.myshopify.com/cart', + path: '/cart', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'product_removed_from_cart', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product Removed', + properties: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + price: 749.95, + product_id: '7234590834801', + variant: 'The Collection Snowboard: Liquid', + category: 'snowboard', + brand: 'Hydrogen Vendor', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + sku: '', + name: null, + quantity: 1, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> checkout_started event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + name: 'checkout_started', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: '', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T20:57:59.674Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'checkout_started', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Started', + properties: { + products: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: 'The Collection Snowboard: Liquid', + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + name: 'The Collection Snowboard: Liquid', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + price: 749.95, + sku: null, + product_id: '7234590834801', + category: 'snowboard', + url: '/products/the-collection-snowboard-liquid', + brand: 'Hydrogen Vendor', + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: 'The Multi-managed Snowboard', + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + name: 'The Multi-managed Snowboard', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + price: 629.95, + sku: 'sku-managed-1', + product_id: '7234590736497', + category: 'snowboard', + url: '/products/the-multi-managed-snowboard', + brand: 'Multi-managed Vendor', + }, + ], + order_id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + checkout_id: '5f7028e0bd5225c17b24bdaa0c09f914', + total: 2759.8, + currency: 'USD', + discount: 0, + shipping: 0, + revenue: 2759.8, + value: 2759.8, + tax: 0, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> address_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d2154d-7525-47A4-87FA-E54D2322E129', + name: 'checkout_address_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:45:50.523Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'checkout_address_info_submitted', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Address Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> contact_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7c8416f-1D35-4304-EF29-78666678C4E9', + name: 'checkout_contact_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:40:28.498Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'checkout_contact_info_submitted', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Contact Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> shipping_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d5618e-404A-4E6D-4662-599A4BCC9E7C', + name: 'checkout_shipping_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:47:38.576Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 433, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 433, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 433, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 433, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'checkout_shipping_info_submitted', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Shipping Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> payment_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d843ea-ED11-4A12-F32F-C5A45BED0413', + name: 'payment_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:49:13.092Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'payment_info_submitted', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Payment Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> checkout_completed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + name: 'checkout_completed', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: '', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T20:57:59.674Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'checkout_completed', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Completed', + properties: { + products: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: 'The Collection Snowboard: Liquid', + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + name: 'The Collection Snowboard: Liquid', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + price: 749.95, + sku: null, + product_id: '7234590834801', + category: 'snowboard', + url: '/products/the-collection-snowboard-liquid', + brand: 'Hydrogen Vendor', + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: 'The Multi-managed Snowboard', + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + name: 'The Multi-managed Snowboard', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + price: 629.95, + sku: 'sku-managed-1', + product_id: '7234590736497', + category: 'snowboard', + url: '/products/the-multi-managed-snowboard', + brand: 'Multi-managed Vendor', + }, + ], + order_id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + checkout_id: '5f7028e0bd5225c17b24bdaa0c09f914', + total: 2759.8, + currency: 'USD', + discount: 0, + shipping: 0, + revenue: 2759.8, + value: 2759.8, + tax: 0, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> search_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d599b4-D80F-4D05-C4CE-B980D5444596', + name: 'search_submitted', + data: { + searchResult: { + query: 'skate', + productVariants: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T22:37:35.869Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/search', + port: '', + protocol: 'https:', + search: '?q=skate&options%5Bprefix%5D=last', + }, + referrer: 'https://store.myshopify.com/', + characterSet: 'UTF-8', + title: 'Search: 0 results found for "skate" – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/search', + port: '', + protocol: 'https:', + search: '?q=skate&options%5Bprefix%5D=last', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['search_submitted'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/search', + port: '', + protocol: 'https:', + search: '?q=skate&options%5Bprefix%5D=last', + }, + referrer: 'https://store.myshopify.com/', + characterSet: 'UTF-8', + title: 'Search: 0 results found for "skate" – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/search', + port: '', + protocol: 'https:', + search: '?q=skate&options%5Bprefix%5D=last', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Search: 0 results found for "skate" – pixel-testing-rs', + url: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', + path: '/search', + search: '?q=skate&options%5Bprefix%5D=last', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + topic: 'search_submitted', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Search Submitted', + properties: { + query: 'skate', + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, +]; + +const serverSideEventsScenarios = [ { name: 'shopify', description: 'Track Call -> carts_create ', @@ -607,3 +5082,5 @@ export const data = [ }, }, ]; + +export const data = [...pixelEventsTestScenarios, ...serverSideEventsScenarios]; From ab3bd67a495c1a3e32f959fc30ea8efc6c64a6ba Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 16 Sep 2024 09:33:26 +0530 Subject: [PATCH 11/22] fix: library version for old and new serverside events --- src/v1/sources/shopify/pixelTransform.js | 12 +++------ src/v1/sources/shopify/transform.js | 32 +++++++++++++++++------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/pixelTransform.js index a5799c5e96..437a49bf98 100644 --- a/src/v1/sources/shopify/pixelTransform.js +++ b/src/v1/sources/shopify/pixelTransform.js @@ -1,6 +1,5 @@ const stats = require('../../../util/stats'); const logger = require('../../../logger'); -const { processEvent } = require('./transform'); const { removeUndefinedAndNullValues } = require('../../../v0/util'); const { pageViewedEventBuilder, @@ -81,15 +80,10 @@ function processPixelEvent(inputEvent) { return message; } +// eslint-disable-next-line @typescript-eslint/no-unused-vars const processEventV2 = async (event, metricMetadata) => { - const { pixelEventLabel } = event; - if (pixelEventLabel) { - // this is a event fired from the web pixel loaded on the browser - // by the user interactions with the store. - const pixelEvent = processPixelEvent(event); - return removeUndefinedAndNullValues(pixelEvent); - } - return processEvent(event, metricMetadata); + const pixelEvent = processPixelEvent(event); + return removeUndefinedAndNullValues(pixelEvent); }; module.exports = { diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index 2e22ffbfea..45cba07ed5 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -126,7 +126,7 @@ const trackPayloadBuilder = (event, shopifyTopic) => { return message; }; -const processEvent = async (inputEvent, metricMetadata) => { +const processEvent = async (inputEvent, metricMetadata, source) => { let message; const event = lodash.cloneDeep(inputEvent); let redisData; @@ -196,10 +196,17 @@ const processEvent = async (inputEvent, metricMetadata) => { } } message.setProperty(`integrations.${INTEGERATION}`, true); - message.setProperty('context.library', { - name: 'RudderStack Shopify Cloud', - version: '1.0.0', - }); + if (source && source.Config && source.Config.version === 'v2') { + message.setProperty('context.library', { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }); + } else { + message.setProperty('context.library', { + name: 'RudderStack Shopify Cloud', + version: '1.0.0', + }); + } message.setProperty('context.topic', shopifyTopic); // attaching cart, checkout and order tokens in context object message.setProperty(`context.cart_token`, event.cart_token); @@ -287,14 +294,21 @@ const process = async (inputEvent) => { // check on the source Config to identify the event is from the tracker-based (legacy) // or the pixel-based (latest) implementation. if (source && isDefinedAndNotNull(source.Config) && source?.Config?.version === 'v2') { - const responseV2 = await processEventV2(event, metricMetadata); - return responseV2; + const { pixelEventLabel } = event; + if (pixelEventLabel) { + // this is a event fired from the web pixel loaded on the browser + // by the user interactions with the store. + const responseV2 = await processEventV2(event, metricMetadata); + return responseV2; + } + const webhookEvent = processEvent(event, metricMetadata, source); + return webhookEvent; } if (isIdentifierEvent(event)) { return processIdentifierEvent(event, metricMetadata); } - const response = await processEvent(event, metricMetadata); + const response = await processEvent(event, metricMetadata, source); return response; }; -module.exports = { process, processEvent }; +module.exports = { process }; From f556096fe78e775c145680f3cc7077295f6f1f30 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Tue, 17 Sep 2024 12:42:51 +0530 Subject: [PATCH 12/22] chore: address comments, refactorx1 --- src/v1/sources/shopify/pixelTransform.js | 3 +- src/v1/sources/shopify/transform.js | 28 +++------------- src/v1/sources/shopify/util.js | 41 ++++++++++++++---------- 3 files changed, 30 insertions(+), 42 deletions(-) diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/pixelTransform.js index 437a49bf98..5cabbde1eb 100644 --- a/src/v1/sources/shopify/pixelTransform.js +++ b/src/v1/sources/shopify/pixelTransform.js @@ -80,8 +80,7 @@ function processPixelEvent(inputEvent) { return message; } -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const processEventV2 = async (event, metricMetadata) => { +const processEventV2 = async (event) => { const pixelEvent = processPixelEvent(event); return removeUndefinedAndNullValues(pixelEvent); }; diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index 45cba07ed5..a799a3f159 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -12,6 +12,7 @@ const { checkAndUpdateCartItems, getHashLineItems, getDataFromRedis, + mapCustomerDetails, } = require('./util'); const logger = require('../../../logger'); const { RedisDB } = require('../../../util/redis/redisConnector'); @@ -60,27 +61,7 @@ const ecomPayloadBuilder = (event, shopifyTopic) => { message.setProperty(`properties.${key}`, properties[key]), ); // Map Customer details if present - const customerDetails = get(event, 'customer'); - if (customerDetails) { - message.setPropertiesV2(customerDetails, MAPPING_CATEGORIES[EventType.IDENTIFY]); - } - if (event.updated_at) { - // TODO: look for created_at for checkout_create? - // converting shopify updated_at timestamp to rudder timestamp format - message.setTimestamp(new Date(event.updated_at).toISOString()); - } - if (event.customer) { - message.setPropertiesV2(event.customer, MAPPING_CATEGORIES[EventType.IDENTIFY]); - } - if (event.shipping_address) { - message.setProperty('traits.shippingAddress', event.shipping_address); - } - if (event.billing_address) { - message.setProperty('traits.billingAddress', event.billing_address); - } - if (!message.userId && event.user_id) { - message.setProperty('userId', event.user_id); - } + mapCustomerDetails(event, message); return message; }; @@ -288,7 +269,8 @@ const process = async (inputEvent) => { const { event, source } = inputEvent; const metricMetadata = { // eslint-disable-next-line unicorn/consistent-destructuring - writeKey: event.query_parameters?.writeKey?.[0], + writeKey: source?.WriteKey || event.query_parameters?.writeKey?.[0], + sourceId: source?.ID, source: 'SHOPIFY', }; // check on the source Config to identify the event is from the tracker-based (legacy) @@ -298,7 +280,7 @@ const process = async (inputEvent) => { if (pixelEventLabel) { // this is a event fired from the web pixel loaded on the browser // by the user interactions with the store. - const responseV2 = await processEventV2(event, metricMetadata); + const responseV2 = await processEventV2(event); return responseV2; } const webhookEvent = processEvent(event, metricMetadata, source); diff --git a/src/v1/sources/shopify/util.js b/src/v1/sources/shopify/util.js index 70f541f6aa..28f07fc3de 100644 --- a/src/v1/sources/shopify/util.js +++ b/src/v1/sources/shopify/util.js @@ -2,6 +2,7 @@ /* eslint-disable camelcase */ /* eslint-disable @typescript-eslint/naming-convention */ const { v5 } = require('uuid'); +const get = require('get-value'); const sha256 = require('sha256'); const { TransformationError } = require('@rudderstack/integrations-lib'); const stats = require('../../../util/stats'); @@ -12,8 +13,10 @@ const { generateUUID, isDefinedAndNotNull, } = require('../../../v0/util'); +const { EventType } = require('../../../constants'); const { RedisDB } = require('../../../util/redis/redisConnector'); const { + MAPPING_CATEGORIES, lineItemsMappingJSON, productMappingJSON, LINE_ITEM_EXCLUSION_FIELDS, @@ -273,24 +276,28 @@ const checkAndUpdateCartItems = async (inputEvent, redisData, metricMetadata, sh return true; }; -const pixelEventBuilder = (inputEvent) => { - const { event: eventName, properties } = inputEvent; - const { currency, value, content_ids, content_type } = properties; - const { value: propValue, currency: propCurrency } = properties; - const eventValue = isDefinedAndNotNull(value) ? value : propValue; - const eventCurrency = isDefinedAndNotNull(currency) ? currency : propCurrency; - const pixelEvent = { - event_name: eventName, - currency: eventCurrency, - value: eventValue, - }; - if (content_ids) { - pixelEvent.content_ids = content_ids; +const mapCustomerDetails = (event, message) => { + const customerDetails = get(event, 'customer'); + if (customerDetails) { + message.setPropertiesV2(customerDetails, MAPPING_CATEGORIES[EventType.IDENTIFY]); } - if (content_type) { - pixelEvent.content_type = content_type; + if (event.updated_at) { + // TODO: look for created_at for checkout_create? + // converting shopify updated_at timestamp to rudder timestamp format + message.setTimestamp(new Date(event.updated_at).toISOString()); + } + if (event.customer) { + message.setPropertiesV2(event.customer, MAPPING_CATEGORIES[EventType.IDENTIFY]); + } + if (event.shipping_address) { + message.setProperty('traits.shippingAddress', event.shipping_address); + } + if (event.billing_address) { + message.setProperty('traits.billingAddress', event.billing_address); + } + if (!message.userId && event.user_id) { + message.setProperty('userId', event.user_id); } - return pixelEvent; }; module.exports = { @@ -302,5 +309,5 @@ module.exports = { checkAndUpdateCartItems, getHashLineItems, getDataFromRedis, - pixelEventBuilder, + mapCustomerDetails, }; From dfa2d695842a1f6f2ce96e5bd647a64b0967f1a4 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Tue, 17 Sep 2024 13:29:02 +0530 Subject: [PATCH 13/22] chore: add test --- test/integrations/sources/shopify/data.ts | 377 +++++++++++++++++++++- 1 file changed, 376 insertions(+), 1 deletion(-) diff --git a/test/integrations/sources/shopify/data.ts b/test/integrations/sources/shopify/data.ts index 2bee61ca5b..accbcb67a7 100644 --- a/test/integrations/sources/shopify/data.ts +++ b/test/integrations/sources/shopify/data.ts @@ -5083,4 +5083,379 @@ const serverSideEventsScenarios = [ }, ]; -export const data = [...pixelEventsTestScenarios, ...serverSideEventsScenarios]; +const v1ServerSideEventsScenarios = [ + { + name: 'shopify', + description: 'Track Call -> Checkout Updated event', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 35374569160817, + token: 'e89d4437003b6b8480f8bc7f8036a659', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + email: 'AJAIKUMARBAJPAI1962@GMAIL.COM', + gateway: null, + buyer_accepts_marketing: false, + buyer_accepts_sms_marketing: false, + sms_marketing_phone: null, + created_at: '2024-09-16T03:50:15+00:00', + updated_at: '2024-09-17T03:29:02-04:00', + landing_site: '/', + note: '', + note_attributes: [], + referring_site: '', + shipping_lines: [ + { + code: 'Standard', + price: '6.90', + original_shop_price: '6.90', + original_shop_markup: '0.00', + source: 'shopify', + title: 'Standard', + presentment_title: 'Standard', + phone: null, + tax_lines: [], + custom_tax_lines: null, + markup: '0.00', + carrier_identifier: null, + carrier_service_id: null, + api_client_id: '580111', + delivery_option_group: { + token: '26492692a443ee35c30eb82073bacaa8', + type: 'one_time_purchase', + }, + delivery_expectation_range: null, + delivery_expectation_type: null, + id: null, + requested_fulfillment_service_id: null, + delivery_category: null, + validation_context: null, + applied_discounts: [], + }, + ], + shipping_address: { + first_name: 'Yashasvi', + address1: '103 Block B', + phone: null, + city: 'Kanpur', + zip: '85003', + province: 'Arizona', + country: 'United States', + last_name: 'Bajpai', + address2: 'Shyam Nagar', + company: null, + latitude: null, + longitude: null, + name: 'Yashasvi Bajpai', + country_code: 'US', + province_code: 'AZ', + }, + taxes_included: false, + total_weight: 0, + currency: 'USD', + completed_at: null, + phone: null, + customer_locale: 'en-US', + line_items: [ + { + key: '41327143059569', + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + presentment_title: 'The Multi-location Snowboard', + presentment_variant_title: '', + product_id: 7234590638193, + quantity: 1, + requires_shipping: true, + sku: '', + tax_lines: [], + taxable: true, + title: 'The Multi-location Snowboard', + variant_id: 41327143059569, + variant_title: '', + variant_price: '729.95', + vendor: 'pixel-testing-rs', + unit_price_measurement: { + measured_type: null, + quantity_value: null, + quantity_unit: null, + reference_value: null, + reference_unit: null, + }, + compare_at_price: null, + line_price: '729.95', + price: '729.95', + applied_discounts: [], + destination_location_id: null, + user_id: null, + rank: null, + origin_location_id: null, + properties: {}, + }, + ], + name: '#35374569160817', + abandoned_checkout_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', + discount_codes: [], + tax_lines: [], + presentment_currency: 'USD', + source_name: 'web', + total_line_items_price: '729.95', + total_tax: '0.00', + total_discounts: '0.00', + subtotal_price: '729.95', + total_price: '736.85', + total_duties: '0.00', + device_id: null, + user_id: null, + location_id: null, + source_identifier: null, + source_url: null, + source: null, + closed_at: null, + customer: { + id: 7188389789809, + email: 'ajaikumarbajpai1962@gmail.com', + accepts_marketing: false, + created_at: null, + updated_at: null, + first_name: 'Yashasvi', + last_name: 'Bajpai', + orders_count: 0, + state: 'disabled', + total_spent: '0.00', + last_order_id: null, + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + phone: null, + tags: '', + currency: 'USD', + accepts_marketing_updated_at: null, + admin_graphql_api_id: 'gid://shopify/Customer/7188389789809', + default_address: { + id: null, + customer_id: 7188389789809, + first_name: 'Yashasvi', + last_name: 'Bajpai', + company: null, + address1: '103 Block B', + address2: 'Shyam Nagar', + city: 'Kanpur', + province: 'Arizona', + country: 'United States', + zip: '85003', + phone: null, + name: 'Yashasvi Bajpai', + province_code: 'AZ', + country_code: 'US', + country_name: 'United States', + default: true, + }, + last_order_name: null, + marketing_opt_in_level: null, + }, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['2l9QoM7KRMJLMcYhXNUVDT0Mqbd'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + integration: { + name: 'SHOPIFY', + }, + topic: 'checkouts_update', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Updated', + properties: { + order_id: 35374569160817, + value: '736.85', + tax: '0.00', + currency: 'USD', + token: 'e89d4437003b6b8480f8bc7f8036a659', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + email: 'AJAIKUMARBAJPAI1962@GMAIL.COM', + buyer_accepts_marketing: false, + buyer_accepts_sms_marketing: false, + created_at: '2024-09-16T03:50:15+00:00', + updated_at: '2024-09-17T03:29:02-04:00', + landing_site: '/', + note: '', + note_attributes: [], + referring_site: '', + shipping_lines: [ + { + code: 'Standard', + price: '6.90', + original_shop_price: '6.90', + original_shop_markup: '0.00', + source: 'shopify', + title: 'Standard', + presentment_title: 'Standard', + phone: null, + tax_lines: [], + custom_tax_lines: null, + markup: '0.00', + carrier_identifier: null, + carrier_service_id: null, + api_client_id: '580111', + delivery_option_group: { + token: '26492692a443ee35c30eb82073bacaa8', + type: 'one_time_purchase', + }, + delivery_expectation_range: null, + delivery_expectation_type: null, + id: null, + requested_fulfillment_service_id: null, + delivery_category: null, + validation_context: null, + applied_discounts: [], + }, + ], + taxes_included: false, + total_weight: 0, + customer_locale: 'en-US', + name: '#35374569160817', + abandoned_checkout_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', + discount_codes: [], + tax_lines: [], + presentment_currency: 'USD', + source_name: 'web', + total_line_items_price: '729.95', + total_discounts: '0.00', + subtotal_price: '729.95', + total_duties: '0.00', + products: [ + { + product_id: 7234590638193, + price: '729.95', + brand: 'pixel-testing-rs', + quantity: 1, + key: '41327143059569', + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + presentment_title: 'The Multi-location Snowboard', + presentment_variant_title: '', + requires_shipping: true, + tax_lines: [], + taxable: true, + title: 'The Multi-location Snowboard', + unit_price_measurement: { + measured_type: null, + quantity_value: null, + quantity_unit: null, + reference_value: null, + reference_unit: null, + }, + compare_at_price: null, + line_price: '729.95', + applied_discounts: [], + destination_location_id: null, + user_id: null, + rank: null, + origin_location_id: null, + properties: {}, + variant: '41327143059569 729.95 ', + }, + ], + }, + userId: '7188389789809', + traits: { + email: 'ajaikumarbajpai1962@gmail.com', + firstName: 'Yashasvi', + lastName: 'Bajpai', + address: { + id: null, + customer_id: 7188389789809, + first_name: 'Yashasvi', + last_name: 'Bajpai', + company: null, + address1: '103 Block B', + address2: 'Shyam Nagar', + city: 'Kanpur', + province: 'Arizona', + country: 'United States', + zip: '85003', + phone: null, + name: 'Yashasvi Bajpai', + province_code: 'AZ', + country_code: 'US', + country_name: 'United States', + default: true, + }, + acceptsMarketing: false, + orderCount: 0, + state: 'disabled', + totalSpent: '0.00', + verifiedEmail: true, + taxExempt: false, + tags: '', + currency: 'USD', + adminGraphqlApiId: 'gid://shopify/Customer/7188389789809', + shippingAddress: { + first_name: 'Yashasvi', + address1: '103 Block B', + phone: null, + city: 'Kanpur', + zip: '85003', + province: 'Arizona', + country: 'United States', + last_name: 'Bajpai', + address2: 'Shyam Nagar', + company: null, + latitude: null, + longitude: null, + name: 'Yashasvi Bajpai', + country_code: 'US', + province_code: 'AZ', + }, + }, + timestamp: '2024-09-17T07:29:02.000Z', + anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + }, + ], + }, + }, + ], + }, + }, + }, +]; + +export const data = [ + ...pixelEventsTestScenarios, + ...serverSideEventsScenarios, + ...v1ServerSideEventsScenarios, +]; From c7ccf0d5157d16a577adfb1a821c4b6354cc108a Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:40:45 +0530 Subject: [PATCH 14/22] chore: add testsx2 --- test/integrations/sources/shopify/data.ts | 315 ++++++++++++++++++++++ 1 file changed, 315 insertions(+) diff --git a/test/integrations/sources/shopify/data.ts b/test/integrations/sources/shopify/data.ts index accbcb67a7..b371527387 100644 --- a/test/integrations/sources/shopify/data.ts +++ b/test/integrations/sources/shopify/data.ts @@ -4473,6 +4473,109 @@ const pixelEventsTestScenarios = [ }, }, }, + { + name: 'shopify', + description: 'Track Call -> unknown event from web pixel, should not be sent to Shopify', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d599b4-D80F-4D05-C4CE-B980D5444596', + name: 'unknown_event', + data: { + searchResult: { + query: 'skate', + productVariants: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T22:37:35.869Z', + context: { + document: { + location: { + href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/search', + port: '', + protocol: 'https:', + search: '?q=skate&options%5Bprefix%5D=last', + }, + referrer: 'https://store.myshopify.com/', + characterSet: 'UTF-8', + title: 'Search: 0 results found for "skate" – pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/search', + port: '', + protocol: 'https:', + search: '?q=skate&options%5Bprefix%5D=last', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + }, + pixelEventLabel: true, + query_parameters: { + topic: ['search_submitted'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + outputToSource: { + body: 'T0s=', + contentType: 'text/plain', + }, + statusCode: 200, + }, + ], + }, + }, + }, ]; const serverSideEventsScenarios = [ @@ -5452,6 +5555,218 @@ const v1ServerSideEventsScenarios = [ }, }, }, + { + name: 'shopify', + description: 'Track Call -> Cart Update event', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + line_items: [ + { + id: 41327143059569, + properties: null, + quantity: 3, + variant_id: 41327143059569, + key: '41327143059569:90562f18109e0e6484b0c297e7981b30', + discounted_price: '729.95', + discounts: [], + gift_card: false, + grams: 0, + line_price: '2189.85', + original_line_price: '2189.85', + original_price: '729.95', + price: '729.95', + product_id: 7234590638193, + sku: '', + taxable: true, + title: 'The Multi-location Snowboard', + total_discount: '0.00', + vendor: 'pixel-testing-rs', + discounted_price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + original_line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + total_discount_set: { + shop_money: { + amount: '0.0', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.0', + currency_code: 'USD', + }, + }, + }, + ], + note: '', + updated_at: '2024-09-17T08:15:13.280Z', + created_at: '2024-09-16T03:50:15.478Z', + query_parameters: { + topic: ['carts_update'], + writeKey: ['2l9QoM7KRMJLMcYhXNUVDT0Mqbd'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }, + integration: { + name: 'SHOPIFY', + }, + topic: 'carts_update', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Cart Update', + properties: { + id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + note: '', + updated_at: '2024-09-17T08:15:13.280Z', + created_at: '2024-09-16T03:50:15.478Z', + products: [ + { + product_id: 7234590638193, + price: '729.95', + brand: 'pixel-testing-rs', + quantity: 3, + id: 41327143059569, + properties: null, + key: '41327143059569:90562f18109e0e6484b0c297e7981b30', + discounted_price: '729.95', + discounts: [], + gift_card: false, + grams: 0, + line_price: '2189.85', + original_line_price: '2189.85', + original_price: '729.95', + taxable: true, + title: 'The Multi-location Snowboard', + total_discount: '0.00', + discounted_price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + original_line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + total_discount_set: { + shop_money: { + amount: '0.0', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.0', + currency_code: 'USD', + }, + }, + variant: '41327143059569 ', + }, + ], + }, + anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + }, + ], + }, + }, + ], + }, + }, + }, ]; export const data = [ From cf0efa8321937d7b72c49b56c1e11ebc3ce59080 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:17:16 +0530 Subject: [PATCH 15/22] chore: update version naming from config --- src/v1/sources/shopify/transform.js | 4 ++-- test/integrations/sources/shopify/data.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index a799a3f159..72a387f4f3 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -177,7 +177,7 @@ const processEvent = async (inputEvent, metricMetadata, source) => { } } message.setProperty(`integrations.${INTEGERATION}`, true); - if (source && source.Config && source.Config.version === 'v2') { + if (source && source.Config && source.Config.version === 'pixel') { message.setProperty('context.library', { name: 'RudderStack Shopify Cloud', version: '2.0.0', @@ -275,7 +275,7 @@ const process = async (inputEvent) => { }; // check on the source Config to identify the event is from the tracker-based (legacy) // or the pixel-based (latest) implementation. - if (source && isDefinedAndNotNull(source.Config) && source?.Config?.version === 'v2') { + if (source && isDefinedAndNotNull(source.Config) && source?.Config?.version === 'pixel') { const { pixelEventLabel } = event; if (pixelEventLabel) { // this is a event fired from the web pixel loaded on the browser diff --git a/test/integrations/sources/shopify/data.ts b/test/integrations/sources/shopify/data.ts index b371527387..2c30fd0aa0 100644 --- a/test/integrations/sources/shopify/data.ts +++ b/test/integrations/sources/shopify/data.ts @@ -7,7 +7,7 @@ const dummySourceConfig = { Config: { disableClientSideIdentifier: false, eventUpload: false, - version: 'v2', + version: 'pixel', }, Enabled: true, WorkspaceID: 'dummy-workspace-id', From d6688c72a6082945e5835e3da082abc4ba142640 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:45:03 +0530 Subject: [PATCH 16/22] chore: keep old v0 logic intact, refactor --- src/v0/sources/shopify/config.js | 52 +++ src/v0/sources/shopify/transform.js | 7 +- src/v1/sources/shopify/config.js | 181 +--------- .../sources/shopify/data/identifyMapping.json | 112 ------- .../shopify/data/lineItemsMapping.json | 26 -- src/v1/sources/shopify/data/mapping.json | 10 - .../sources/shopify/data/productMapping.json | 18 - .../cartViewedEventMapping.json | 0 .../checkoutStartedCompletedEventMapping.json | 0 .../contextualFieldMapping.json | 0 .../productListViewedEventMapping.json | 0 .../productToCartEventMapping.json | 0 .../productViewedEventMapping.json | 0 src/v1/sources/shopify/shopify.util.test.js | 59 ---- .../shopify/shopify_redis.util.test.js | 289 ---------------- src/v1/sources/shopify/transform.js | 276 +-------------- src/v1/sources/shopify/util.js | 313 ------------------ 17 files changed, 79 insertions(+), 1264 deletions(-) delete mode 100644 src/v1/sources/shopify/data/identifyMapping.json delete mode 100644 src/v1/sources/shopify/data/lineItemsMapping.json delete mode 100644 src/v1/sources/shopify/data/mapping.json delete mode 100644 src/v1/sources/shopify/data/productMapping.json rename src/v1/sources/shopify/{data => pixelEventsMappings}/cartViewedEventMapping.json (100%) rename src/v1/sources/shopify/{data => pixelEventsMappings}/checkoutStartedCompletedEventMapping.json (100%) rename src/v1/sources/shopify/{data => pixelEventsMappings}/contextualFieldMapping.json (100%) rename src/v1/sources/shopify/{data => pixelEventsMappings}/productListViewedEventMapping.json (100%) rename src/v1/sources/shopify/{data => pixelEventsMappings}/productToCartEventMapping.json (100%) rename src/v1/sources/shopify/{data => pixelEventsMappings}/productViewedEventMapping.json (100%) delete mode 100644 src/v1/sources/shopify/shopify_redis.util.test.js delete mode 100644 src/v1/sources/shopify/util.js diff --git a/src/v0/sources/shopify/config.js b/src/v0/sources/shopify/config.js index b8b3cde284..a5ededf9da 100644 --- a/src/v0/sources/shopify/config.js +++ b/src/v0/sources/shopify/config.js @@ -36,6 +36,32 @@ const SHOPIFY_TRACK_MAP = { orders_fulfilled: 'Order Fulfilled', orders_paid: 'Order Paid', orders_partially_fullfilled: 'Order Partially Fulfilled', + // following are the events that supported by rudderstack pixel app as generic track events + customer_tags_added: 'Customer Tags Added', + customer_tags_removed: 'Customer Tags Removed', + customer_email_updated: 'Customer Email Updated', + collections_create: 'Collection Created', + collections_update: 'Collection Updated', + collections_delete: 'Collection Deleted', + collection_listings_add: 'Collection Listings Added', + collection_listings_remove: 'Collection Listings Removed', + collection_listings_update: 'Collection Listings Updated', + collection_publications_create: 'Collection Publications Created', + collection_publications_delete: 'Collection Publications Deleted', + collection_publications_update: 'Collection Publications Updated', + discounts_create: 'Discount Created', + discounts_delete: 'Discount Deleted', + discounts_update: 'Discount Updated', + draft_orders_create: 'Draft Order Created', + draft_orders_delete: 'Draft Order Deleted', + draft_orders_update: 'Draft Order Updated', + fulfillment_order_split: 'Fulfillment Order Split', + inventory_items_create: 'Inventory Items Created', + inventory_items_delete: 'Inventory Items Deleted', + inventory_items_update: 'Inventory Items Updated', + inventory_levels_connect: 'Inventory Levels Connected', + inventory_levels_disconnect: 'Inventory Levels Disconnected', + inventory_levels_update: 'Inventory Levels Updated', }; const identifyMappingJSON = JSON.parse( @@ -100,6 +126,32 @@ const SUPPORTED_TRACK_EVENTS = [ 'orders_fulfilled', 'orders_paid', 'orders_partially_fullfilled', + // following are the events that supported by rudderstack pixel app as generic track events + 'customer_tags_added', + 'customer_tags_removed', + 'customer_email_updated', + 'collections_create', + 'collections_update', + 'collections_delete', + 'collection_listings_add', + 'collection_listings_remove', + 'collection_listings_update', + 'collection_publications_create', + 'collection_publications_delete', + 'collection_publications_update', + 'discounts_create', + 'discounts_delete', + 'discounts_update', + 'draft_orders_create', + 'draft_orders_delete', + 'draft_orders_update', + 'fulfillment_order_split', + 'inventory_items_create', + 'inventory_items_delete', + 'inventory_items_update', + 'inventory_levels_connect', + 'inventory_levels_disconnect', + 'inventory_levels_update', ]; const maxTimeToIdentifyRSGeneratedCall = 10000; // in ms diff --git a/src/v0/sources/shopify/transform.js b/src/v0/sources/shopify/transform.js index b55fc61327..584d8810af 100644 --- a/src/v0/sources/shopify/transform.js +++ b/src/v0/sources/shopify/transform.js @@ -287,4 +287,9 @@ const process = async (event) => { return response; }; -exports.process = process; +module.exports = { + process, + processEvent, + isIdentifierEvent, + processIdentifierEvent, +}; diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js index 2a288a31d5..5a3ce99b40 100644 --- a/src/v1/sources/shopify/config.js +++ b/src/v1/sources/shopify/config.js @@ -1,67 +1,5 @@ const path = require('path'); const fs = require('fs'); -const { EventType } = require('../../../constants'); - -const IDENTIFY_TOPICS = { - CUSTOMERS_CREATE: 'customers_create', - CUSTOMERS_UPDATE: 'customers_update', -}; - -// Mapping from shopify_topic name for ecom events -const ECOM_TOPICS = { - CHECKOUTS_CREATE: 'checkouts_create', - CHECKOUTS_UPDATE: 'checkouts_update', - ORDERS_UPDATE: 'orders_updated', - ORDERS_CREATE: 'orders_create', -}; - -const RUDDER_ECOM_MAP = { - checkouts_create: 'Checkout Started', - checkouts_update: 'Checkout Updated', - orders_updated: 'Order Updated', - orders_create: 'Order Created', -}; -const SHOPIFY_ADMIN_ONLY_EVENTS = ['Order Deleted', 'Fulfillments Create', 'Fulfillments Update']; - -const SHOPIFY_TRACK_MAP = { - checkouts_delete: 'Checkout Deleted', - carts_update: 'Cart Update', - customers_enable: 'Customer Enabled', - customers_disable: 'Customer Disabled', - fulfillments_create: 'Fulfillments Create', - fulfillments_update: 'Fulfillments Update', - orders_delete: 'Order Deleted', - orders_edited: 'Order Edited', - orders_cancelled: 'Order Cancelled', - orders_fulfilled: 'Order Fulfilled', - orders_paid: 'Order Paid', - orders_partially_fullfilled: 'Order Partially Fulfilled', - customer_tags_added: 'Customer Tags Added', - customer_tags_removed: 'Customer Tags Removed', - customer_email_updated: 'Customer Email Updated', - collections_create: 'Collection Created', - collections_update: 'Collection Updated', - collections_delete: 'Collection Deleted', - collection_listings_add: 'Collection Listings Added', - collection_listings_remove: 'Collection Listings Removed', - collection_listings_update: 'Collection Listings Updated', - collection_publications_create: 'Collection Publications Created', - collection_publications_delete: 'Collection Publications Deleted', - collection_publications_update: 'Collection Publications Updated', - discounts_create: 'Discount Created', - discounts_delete: 'Discount Deleted', - discounts_update: 'Discount Updated', - draft_orders_create: 'Draft Order Created', - draft_orders_delete: 'Draft Order Deleted', - draft_orders_update: 'Draft Order Updated', - fulfillment_order_split: 'Fulfillment Order Split', - inventory_items_create: 'Inventory Items Created', - inventory_items_delete: 'Inventory Items Deleted', - inventory_items_update: 'Inventory Items Updated', - inventory_levels_connect: 'Inventory Levels Connected', - inventory_levels_disconnect: 'Inventory Levels Disconnected', - inventory_levels_update: 'Inventory Levels Updated', -}; const PIXEL_EVENT_TOPICS = { CART_VIEWED: 'cart_viewed', @@ -95,139 +33,40 @@ const PIXEL_EVENT_MAPPING = { search_submitted: 'Search Submitted', }; -const identifyMappingJSON = JSON.parse( - fs.readFileSync(path.resolve(__dirname, 'data', 'identifyMapping.json')), -); - const contextualFieldMappingJSON = JSON.parse( - fs.readFileSync(path.resolve(__dirname, 'data', 'contextualFieldMapping.json')), + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'contextualFieldMapping.json')), ); const cartViewedEventMappingJSON = JSON.parse( - fs.readFileSync(path.resolve(__dirname, 'data', 'cartViewedEventMapping.json')), + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'cartViewedEventMapping.json')), ); const productListViewedEventMappingJSON = JSON.parse( - fs.readFileSync(path.resolve(__dirname, 'data', 'productListViewedEventMapping.json')), + fs.readFileSync( + path.resolve(__dirname, 'pixelEventsMappings', 'productListViewedEventMapping.json'), + ), ); const productViewedEventMappingJSON = JSON.parse( - fs.readFileSync(path.resolve(__dirname, 'data', 'productViewedEventMapping.json')), + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'productViewedEventMapping.json')), ); const productToCartEventMappingJSON = JSON.parse( - fs.readFileSync(path.resolve(__dirname, 'data', 'productToCartEventMapping.json')), + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'productToCartEventMapping.json')), ); const checkoutStartedCompletedEventMappingJSON = JSON.parse( - fs.readFileSync(path.resolve(__dirname, 'data', 'checkoutStartedCompletedEventMapping.json')), -); - -const productMappingJSON = JSON.parse( - fs.readFileSync(path.resolve(__dirname, 'data', 'productMapping.json')), -); - -const lineItemsMappingJSON = JSON.parse( - fs.readFileSync(path.resolve(__dirname, 'data', 'lineItemsMapping.json')), + fs.readFileSync( + path.resolve(__dirname, 'pixelEventsMappings', 'checkoutStartedCompletedEventMapping.json'), + ), ); const INTEGERATION = 'SHOPIFY'; -const MAPPING_CATEGORIES = { - [EventType.IDENTIFY]: identifyMappingJSON, - [EventType.TRACK]: productMappingJSON, -}; - -const LINE_ITEM_EXCLUSION_FIELDS = [ - 'product_id', - 'sku', - 'name', - 'price', - 'vendor', - 'quantity', - 'variant_id', - 'variant_price', - 'variant_title', -]; - -const PRODUCT_MAPPING_EXCLUSION_FIELDS = [ - 'id', - 'total_price', - 'total_tax', - 'currency', - 'line_items', - 'customer', - 'shipping_address', - 'billing_address', -]; - -/** - * list of events name supported as generic track calls - * track events not belonging to this list or ecom events will - * be discarded. - */ -const SUPPORTED_TRACK_EVENTS = [ - 'customer_tags_added', - 'customer_tags_removed', - 'customer_email_updated', - 'checkouts_delete', - 'checkouts_update', - 'customers_disable', - 'customers_enable', - 'collections_create', - 'collections_update', - 'collections_delete', - 'collection_listings_add', - 'collection_listings_remove', - 'collection_listings_update', - 'collection_publications_create', - 'collection_publications_delete', - 'collection_publications_update', - 'discounts_create', - 'discounts_delete', - 'discounts_update', - 'draft_orders_create', - 'draft_orders_delete', - 'draft_orders_update', - 'carts_update', - 'fulfillments_create', - 'fulfillments_update', - 'fulfillment_order_split', - 'inventory_items_create', - 'inventory_items_delete', - 'inventory_items_update', - 'inventory_levels_connect', - 'inventory_levels_disconnect', - 'inventory_levels_update', - 'orders_create', - 'orders_delete', - 'orders_edited', - 'orders_cancelled', - 'orders_fulfilled', - 'orders_paid', - 'orders_partially_fullfilled', -]; - -const maxTimeToIdentifyRSGeneratedCall = 10000; // in ms -const useRedisDatabase = process.env.USE_REDIS_DB === 'true' || false; - module.exports = { - ECOM_TOPICS, - IDENTIFY_TOPICS, INTEGERATION, - MAPPING_CATEGORIES, - RUDDER_ECOM_MAP, - lineItemsMappingJSON, - productMappingJSON, - LINE_ITEM_EXCLUSION_FIELDS, - PRODUCT_MAPPING_EXCLUSION_FIELDS, - SUPPORTED_TRACK_EVENTS, - SHOPIFY_TRACK_MAP, PIXEL_EVENT_TOPICS, PIXEL_EVENT_MAPPING, - useRedisDatabase, - SHOPIFY_ADMIN_ONLY_EVENTS, - maxTimeToIdentifyRSGeneratedCall, contextualFieldMappingJSON, cartViewedEventMappingJSON, productListViewedEventMappingJSON, diff --git a/src/v1/sources/shopify/data/identifyMapping.json b/src/v1/sources/shopify/data/identifyMapping.json deleted file mode 100644 index 0367267502..0000000000 --- a/src/v1/sources/shopify/data/identifyMapping.json +++ /dev/null @@ -1,112 +0,0 @@ -[ - { - "sourceKeys": "id", - "destKeys": "userId" - }, - { - "sourceKeys": "email", - "destKeys": "traits.email" - }, - - { - "sourceKeys": "first_name", - "destKeys": "traits.firstName" - }, - - { - "sourceKeys": "last_name", - "destKeys": "traits.lastName" - }, - - { - "sourceKeys": "phone", - "destKeys": "traits.phone" - }, - - { - "sourceKeys": "addresses", - "destKeys": "traits.addressList" - }, - - { - "sourceKeys": "default_address", - "destKeys": "traits.address" - }, - - { - "sourceKeys": "shipping_address", - "destKeys": "traits.shippingAddress" - }, - - { - "sourceKeys": "billing_address", - "destKeys": "traits.billingAddress" - }, - - { - "sourceKeys": "accepts_marketing", - "destKeys": "traits.acceptsMarketing" - }, - - { - "sourceKeys": "orders_count", - "destKeys": "traits.orderCount" - }, - - { - "sourceKeys": "state", - "destKeys": "traits.state" - }, - { - "sourceKeys": "total_spent", - "destKeys": "traits.totalSpent" - }, - { - "sourceKeys": "note", - "destKeys": "traits.note" - }, - { - "sourceKeys": "verified_email", - "destKeys": "traits.verifiedEmail" - }, - { - "sourceKeys": "multipass_identifier", - "destKeys": "traits.multipassIdentifier" - }, - { - "sourceKeys": "tax_exempt", - "destKeys": "traits.taxExempt" - }, - { - "sourceKeys": "tags", - "destKeys": "traits.tags" - }, - { - "sourceKeys": "last_order_name", - "destKeys": "traits.lastOrderName" - }, - { - "sourceKeys": "currency", - "destKeys": "traits.currency" - }, - { - "sourceKeys": "marketing_opt_in_level", - "destKeys": "traits.marketingOptInLevel" - }, - { - "sourceKeys": "tax_exemptions", - "destKeys": "traits.taxExemptions" - }, - { - "sourceKeys": "sms_marketing_consent", - "destKeys": "traits.smsMarketingConsent" - }, - { - "sourceKeys": "admin_graphql_api_id", - "destKeys": "traits.adminGraphqlApiId" - }, - { - "sourceKeys": "accepts_marketing_updated_at", - "destKeys": "traits.acceptsMarketingUpdatedAt" - } -] diff --git a/src/v1/sources/shopify/data/lineItemsMapping.json b/src/v1/sources/shopify/data/lineItemsMapping.json deleted file mode 100644 index eb6e41834e..0000000000 --- a/src/v1/sources/shopify/data/lineItemsMapping.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "sourceKeys": "product_id", - "destKey": "product_id" - }, - { - "sourceKeys": "sku", - "destKey": "sku" - }, - { - "sourceKeys": "name", - "destKey": "title" - }, - { - "sourceKeys": "price", - "destKey": "price" - }, - { - "sourceKeys": "vendor", - "destKey": "brand" - }, - { - "sourceKeys": "quantity", - "destKey": "quantity" - } -] diff --git a/src/v1/sources/shopify/data/mapping.json b/src/v1/sources/shopify/data/mapping.json deleted file mode 100644 index 6c268ef13c..0000000000 --- a/src/v1/sources/shopify/data/mapping.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "sourceKeys": "line_items", - "destKeys": "products" - }, - { - "sourceKeys": "id", - "destKeys": "properties.order_id" - } -] diff --git a/src/v1/sources/shopify/data/productMapping.json b/src/v1/sources/shopify/data/productMapping.json deleted file mode 100644 index 1cf75a44c4..0000000000 --- a/src/v1/sources/shopify/data/productMapping.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "sourceKeys": "id", - "destKey": "order_id" - }, - { - "sourceKeys": "total_price", - "destKey": "value" - }, - { - "sourceKeys": "total_tax", - "destKey": "tax" - }, - { - "sourceKeys": "currency", - "destKey": "currency" - } -] diff --git a/src/v1/sources/shopify/data/cartViewedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/cartViewedEventMapping.json similarity index 100% rename from src/v1/sources/shopify/data/cartViewedEventMapping.json rename to src/v1/sources/shopify/pixelEventsMappings/cartViewedEventMapping.json diff --git a/src/v1/sources/shopify/data/checkoutStartedCompletedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/checkoutStartedCompletedEventMapping.json similarity index 100% rename from src/v1/sources/shopify/data/checkoutStartedCompletedEventMapping.json rename to src/v1/sources/shopify/pixelEventsMappings/checkoutStartedCompletedEventMapping.json diff --git a/src/v1/sources/shopify/data/contextualFieldMapping.json b/src/v1/sources/shopify/pixelEventsMappings/contextualFieldMapping.json similarity index 100% rename from src/v1/sources/shopify/data/contextualFieldMapping.json rename to src/v1/sources/shopify/pixelEventsMappings/contextualFieldMapping.json diff --git a/src/v1/sources/shopify/data/productListViewedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/productListViewedEventMapping.json similarity index 100% rename from src/v1/sources/shopify/data/productListViewedEventMapping.json rename to src/v1/sources/shopify/pixelEventsMappings/productListViewedEventMapping.json diff --git a/src/v1/sources/shopify/data/productToCartEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/productToCartEventMapping.json similarity index 100% rename from src/v1/sources/shopify/data/productToCartEventMapping.json rename to src/v1/sources/shopify/pixelEventsMappings/productToCartEventMapping.json diff --git a/src/v1/sources/shopify/data/productViewedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/productViewedEventMapping.json similarity index 100% rename from src/v1/sources/shopify/data/productViewedEventMapping.json rename to src/v1/sources/shopify/pixelEventsMappings/productViewedEventMapping.json diff --git a/src/v1/sources/shopify/shopify.util.test.js b/src/v1/sources/shopify/shopify.util.test.js index 318464c051..6202d4ec88 100644 --- a/src/v1/sources/shopify/shopify.util.test.js +++ b/src/v1/sources/shopify/shopify.util.test.js @@ -1,4 +1,3 @@ -const { getShopifyTopic } = require('./util'); const { pageViewedEventBuilder, cartViewedEventBuilder, @@ -13,64 +12,6 @@ const { EventType } = require('../../../constants'); const Message = require('../../../v0/sources/message'); jest.mock('ioredis', () => require('../../../../test/__mocks__/redis')); jest.mock('../../../v0/sources/message'); -describe('Shopify Utils Test', () => { - describe('Fetching Shopify Topic Test Cases', () => { - it('Invalid Topic Test', () => { - const input = { - query_parameters: {}, - }; - const expectedOutput = { - error: 'Invalid topic in query_parameters', - }; - try { - getShopifyTopic(input); - } catch (error) { - expect(error.message).toEqual(expectedOutput.error); - } - }); - - it('No Topic Found Test', () => { - const input = { - query_parameters: { - topic: [], - }, - }; - const expectedOutput = { - error: 'Topic not found', - }; - try { - getShopifyTopic(input); - } catch (error) { - expect(error.message).toEqual(expectedOutput.error); - } - }); - - it('Successfully fetched topic Test', () => { - const input = { - query_parameters: { - topic: [''], - }, - }; - const expectedOutput = ''; - const actualOutput = getShopifyTopic(input); - expect(actualOutput).toEqual(expectedOutput); - }); - - it('Empty Query Params Test', () => { - const input = { - randomKey: 'randomValue', - }; - const expectedOutput = { - error: 'Query_parameters is missing', - }; - try { - getShopifyTopic(input); - } catch (error) { - expect(error.message).toEqual(expectedOutput.error); - } - }); - }); -}); describe('utilV2.js', () => { beforeEach(() => { diff --git a/src/v1/sources/shopify/shopify_redis.util.test.js b/src/v1/sources/shopify/shopify_redis.util.test.js deleted file mode 100644 index fb99837932..0000000000 --- a/src/v1/sources/shopify/shopify_redis.util.test.js +++ /dev/null @@ -1,289 +0,0 @@ -const { getAnonymousIdAndSessionId, checkAndUpdateCartItems } = require('./util'); -jest.mock('ioredis', () => require('../../../../test/__mocks__/redis')); -const metricMetadata = { - writeKey: 'dummyKey', - source: 'src', -}; -describe('Shopify Utils Test', () => { - describe('Check for valid cart update event test cases', () => { - it('Event containing token and nothing is retreived from redis and less than req. time difference between created_at and uadated_at', async () => { - const input = { - query_parameters: { - topic: ['carts_update'], - }, - id: 'cartTokenTest1', - line_items: [], - note: null, - updated_at: '2023-02-10T12:05:07.251Z', - created_at: '2023-02-10T12:05:04.402Z', - }; - const expectedOutput = false; - const output = await checkAndUpdateCartItems(input, null, metricMetadata); - expect(output).toEqual(expectedOutput); - }); - it('Event containing token and nothing is retreived from redis', async () => { - const input = { - token: 'token_not_in_redis', - line_items: [ - { - prod_id: 'prod_1', - quantity: 1, - }, - ], - }; - const expectedOutput = true; - const output = await checkAndUpdateCartItems(input, null, metricMetadata); - expect(output).toEqual(expectedOutput); - }); - - it('Event contain id for cart_update event and isValid', async () => { - const input = { - id: 'shopify_test2', - line_items: [ - { - prod_id: 'prod_1', - quantity: 1, - }, - ], - }; - - const expectedOutput = true; - const output = await checkAndUpdateCartItems(input, null, metricMetadata); - expect(output).toEqual(expectedOutput); - }); - - it('Event contain id for cart_update event and isInValid', async () => { - const input = { - id: 'shopify_test_duplicate_cart', - line_items: [ - { - prod_id: 'prod_1', - quantity: 1, - }, - ], - }; - - const expectedOutput = false; - const output = await checkAndUpdateCartItems(input, null, metricMetadata); - expect(output).toEqual(expectedOutput); - }); - - it('Valid Cart Event but not able to set data due to redis error', async () => { - const input = { - id: 'shopify_test_set_redis_error', - line_items: [ - { - prod_id: 'prod_1', - quantity: 1, - }, - ], - }; - - const expectedOutput = true; - const output = await checkAndUpdateCartItems(input, null, metricMetadata); - expect(output).toEqual(expectedOutput); - }); - }); - - describe(' Test Cases -> set AnonymousId and sessionId without using Redis', () => { - it('Order Updated -> Properties containing cartToken', async () => { - const input = { - event: 'Order Updated', - properties: { - cart_token: '123', - }, - }; - const expectedOutput = { - anonymousId: 'b9b6607d-6974-594f-8e99-ac3de71c4d89', - sessionId: undefined, - }; - const output = await getAnonymousIdAndSessionId(input, {}, null); - expect(output).toEqual(expectedOutput); - }); - - it('Cart Update -> Properties contain `id` ', async () => { - const input = { - event: 'Cart Update', - properties: { - id: '123', - }, - }; - - const expectedOutput = { - anonymousId: 'b9b6607d-6974-594f-8e99-ac3de71c4d89', - sessionId: undefined, - }; - const output = await getAnonymousIdAndSessionId(input, {}, null); - - expect(output).toEqual(expectedOutput); - }); - - it('Customer event -> random AnonymousId', async () => { - const input = { - event: 'Customer Enabled', - properties: {}, - }; - - const output = await getAnonymousIdAndSessionId(input, {}, null); - expect(output).toEqual(output); // since it will be random - }); - - it('Order Delete -> No anonymousId is there', async () => { - const input = { - event: 'Order Deleted', - properties: { - order_id: 'Order_ID', - }, - }; - const expectedOutput = { anonymousId: undefined, sessionId: undefined }; - const output = await getAnonymousIdAndSessionId(input, {}, null); - expect(output).toEqual(expectedOutput); - }); - - it('Checkout Create -> rudderAnonymousId and rudderSessionId present in note_attributes', async () => { - const input = { - event: 'Checkout Create', - properties: { - cart_token: 'CART_TOKEN', - note_attributes: [ - { - name: 'rudderAnonymousId', - value: 'RUDDER_ANONYMOUSID', - }, - { - name: 'rudderSessionId', - value: 'RUDDER_SESSIONID', - }, - { - name: 'rudderUpdatedAt', - value: 'TIMESTAMP', - }, - ], - }, - }; - const expectedOutput = { anonymousId: 'RUDDER_ANONYMOUSID', sessionId: 'RUDDER_SESSIONID' }; - const output = await getAnonymousIdAndSessionId(input, {}, null); - expect(output).toEqual(expectedOutput); - }); - }); - - describe('set AnonymousId and sesssionId with Redis Test Cases', () => { - // Doing the following to enable redis mid test case file execution - process.env.USE_REDIS_DB = true; - jest.resetModules(); - const { getAnonymousIdAndSessionId } = require('./util'); - it('Properties containing cartToken but failed due redisError', async () => { - const input = { - event: 'Order Paid', - properties: { - cart_token: 'shopify_test2', - }, - }; - const expectedOutput = { - anonymousId: 'bcaf0473-fb11-562f-80a1-c83a35f053bc', - sessionId: undefined, - }; // cartToken hashed - const output = await getAnonymousIdAndSessionId(input, {}, null); - expect(output).toEqual(expectedOutput); - }); - - it('Order Paid- > Properties containing cartToken and fetched anonymousId and sessionId successfully', async () => { - const input = { - event: 'Order Paid', - properties: { - cart_token: 'shopify_test2', - note_attributes: [ - { - name: 'rudderUpdatedAt', - value: 'RUDDER_UPDTD_AT', - }, - ], - }, - }; - const expectedOutput = { anonymousId: 'anon_shopify_test2', sessionId: 'session_id_2' }; // fetched succesfully from redis - - const output = await getAnonymousIdAndSessionId(input, {}, null); - expect(output).toEqual(expectedOutput); - }); - - it('Cart Update -> Properties contain id and fetched anonymousId successfully', async () => { - const input = { - event: 'Cart Update', - properties: { - id: 'shopify_test_only_anon_id', - }, - }; - const expectedOutput = { - anonymousId: 'anon_shopify_test_only_anon_id', - sessionId: undefined, - }; - const output = await getAnonymousIdAndSessionId(input, {}, null); - expect(output).toEqual(expectedOutput); - }); - - it('No mapping not present in DB for given cartToken', async () => { - const input = { - event: 'Cart Update', - properties: { - id: 'unstored_id', - }, - }; - - const expectedOutput = { - anonymousId: '281a3e25-e603-5870-9cda-281c22940970', - sessionId: undefined, - }; - - const output = await getAnonymousIdAndSessionId(input, {}, null); - expect(output).toEqual(expectedOutput); - }); - - it('No cartToken for SHOPIFY_ADMIN_ONLY_EVENTS', async () => { - const input = { - event: 'Fulfillments Update', - properties: { - id: 'unstored_id', - }, - }; - const expectedOutput = { anonymousId: undefined, sessionId: undefined }; - - const output = await getAnonymousIdAndSessionId(input, {}, null); - expect(output).toEqual(expectedOutput); - }); - - it('No cartToken for Order paid', async () => { - const input = { - event: 'Order Paid', - properties: { - cart_token: 'shopify_test2', - }, - }; - const expectedOutput = 'RANDOM_ANONYMOUS_ID'; // fetched succesfully from redis - - const output = await getAnonymousIdAndSessionId(input, {}, null); - expect('RANDOM_ANONYMOUS_ID').toEqual(expectedOutput); - }); - - it('Only anonymousId fetched from note_attributes and no cartToken', async () => { - const input = { - event: 'Order Paid', - properties: { - note_attributes: [ - { - name: 'rudderAnonymousId', - value: 'RUDDER_ANON_ID', - }, - { - name: 'rudderUpdatedAt', - value: 'RUDDER_UPDTD_AT', - }, - ], - }, - }; - const expectedOutput = { anonymousId: 'RUDDER_ANON_ID', sessionId: null }; // fetched succesfully from redis - const output = await getAnonymousIdAndSessionId(input, {}, null); - - expect(output).toEqual(expectedOutput); - }); - }); -}); diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index 72a387f4f3..e0cf4dbb32 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -1,269 +1,11 @@ /* eslint-disable @typescript-eslint/naming-convention */ -const lodash = require('lodash'); -const get = require('get-value'); -const { RedisError } = require('@rudderstack/integrations-lib'); -const stats = require('../../../util/stats'); -const { - getShopifyTopic, - createPropertiesForEcomEvent, - getProductsListFromLineItems, - extractEmailFromPayload, - getAnonymousIdAndSessionId, - checkAndUpdateCartItems, - getHashLineItems, - getDataFromRedis, - mapCustomerDetails, -} = require('./util'); -const logger = require('../../../logger'); -const { RedisDB } = require('../../../util/redis/redisConnector'); -const { removeUndefinedAndNullValues, isDefinedAndNotNull } = require('../../../v0/util'); -const Message = require('../../../v0/sources/message'); -const { EventType } = require('../../../constants'); +const { isDefinedAndNotNull } = require('../../../v0/util'); const { processEventV2 } = require('./pixelTransform'); const { - INTEGERATION, - MAPPING_CATEGORIES, - IDENTIFY_TOPICS, - ECOM_TOPICS, - RUDDER_ECOM_MAP, - SUPPORTED_TRACK_EVENTS, - SHOPIFY_TRACK_MAP, - useRedisDatabase, -} = require('./config'); - -const NO_OPERATION_SUCCESS = { - outputToSource: { - body: Buffer.from('OK').toString('base64'), - contentType: 'text/plain', - }, - statusCode: 200, -}; - -const identifyPayloadBuilder = (event) => { - const message = new Message(INTEGERATION); - message.setEventType(EventType.IDENTIFY); - message.setPropertiesV2(event, MAPPING_CATEGORIES[EventType.IDENTIFY]); - if (event.updated_at) { - // converting shopify updated_at timestamp to rudder timestamp format - message.setTimestamp(new Date(event.updated_at).toISOString()); - } - return message; -}; - -const ecomPayloadBuilder = (event, shopifyTopic) => { - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName(RUDDER_ECOM_MAP[shopifyTopic]); - - let properties = createPropertiesForEcomEvent(event); - properties = removeUndefinedAndNullValues(properties); - Object.keys(properties).forEach((key) => - message.setProperty(`properties.${key}`, properties[key]), - ); - // Map Customer details if present - mapCustomerDetails(event, message); - return message; -}; - -const trackPayloadBuilder = (event, shopifyTopic) => { - const message = new Message(INTEGERATION); - message.setEventType(EventType.TRACK); - message.setEventName(SHOPIFY_TRACK_MAP[shopifyTopic]); - - Object.keys(event) - .filter( - (key) => - ![ - 'type', - 'event', - 'line_items', - 'customer', - 'shipping_address', - 'billing_address', - ].includes(key), - ) - .forEach((key) => { - message.setProperty(`properties.${key}`, event[key]); - }); - // eslint-disable-next-line camelcase - const { line_items: lineItems, billing_address, user_id, shipping_address, customer } = event; - const productsList = getProductsListFromLineItems(lineItems); - message.setProperty('properties.products', productsList); - if (customer) { - message.setPropertiesV2(customer, MAPPING_CATEGORIES[EventType.IDENTIFY]); - } - // eslint-disable-next-line camelcase - if (shipping_address) { - message.setProperty('traits.shippingAddress', shipping_address); - } - // eslint-disable-next-line camelcase - if (billing_address) { - message.setProperty('traits.billingAddress', billing_address); - } - // eslint-disable-next-line camelcase - if (!message.userId && user_id) { - message.setProperty('userId', user_id); - } - return message; -}; - -const processEvent = async (inputEvent, metricMetadata, source) => { - let message; - const event = lodash.cloneDeep(inputEvent); - let redisData; - const shopifyTopic = getShopifyTopic(event); - delete event.query_parameters; - switch (shopifyTopic) { - case IDENTIFY_TOPICS.CUSTOMERS_CREATE: - case IDENTIFY_TOPICS.CUSTOMERS_UPDATE: - message = identifyPayloadBuilder(event); - break; - case ECOM_TOPICS.ORDERS_CREATE: - case ECOM_TOPICS.ORDERS_UPDATE: - case ECOM_TOPICS.CHECKOUTS_CREATE: - case ECOM_TOPICS.CHECKOUTS_UPDATE: - message = ecomPayloadBuilder(event, shopifyTopic); - break; - case 'carts_update': - if (useRedisDatabase) { - redisData = await getDataFromRedis(event.id || event.token, metricMetadata, 'Cart Update'); - const isValidEvent = await checkAndUpdateCartItems( - inputEvent, - redisData, - metricMetadata, - shopifyTopic, - ); - if (!isValidEvent) { - return NO_OPERATION_SUCCESS; - } - } - message = trackPayloadBuilder(event, shopifyTopic); - break; - default: - if (!SUPPORTED_TRACK_EVENTS.includes(shopifyTopic)) { - stats.increment('invalid_shopify_event', { - writeKey: metricMetadata.writeKey, - source: metricMetadata.source, - shopifyTopic: metricMetadata.shopifyTopic, - }); - return NO_OPERATION_SUCCESS; - } - message = trackPayloadBuilder(event, shopifyTopic); - break; - } - - if (message.userId) { - message.userId = String(message.userId); - } - if (!get(message, 'traits.email')) { - const email = extractEmailFromPayload(event); - if (email) { - message.setProperty('traits.email', email); - } - } - if (message.type !== EventType.IDENTIFY) { - const { anonymousId, sessionId } = await getAnonymousIdAndSessionId( - message, - { shopifyTopic, ...metricMetadata }, - redisData, - ); - if (isDefinedAndNotNull(anonymousId)) { - message.setProperty('anonymousId', anonymousId); - } else if (!message.userId) { - message.setProperty('userId', 'shopify-admin'); - } - if (isDefinedAndNotNull(sessionId)) { - message.setProperty('context.sessionId', sessionId); - } - } - message.setProperty(`integrations.${INTEGERATION}`, true); - if (source && source.Config && source.Config.version === 'pixel') { - message.setProperty('context.library', { - name: 'RudderStack Shopify Cloud', - version: '2.0.0', - }); - } else { - message.setProperty('context.library', { - name: 'RudderStack Shopify Cloud', - version: '1.0.0', - }); - } - message.setProperty('context.topic', shopifyTopic); - // attaching cart, checkout and order tokens in context object - message.setProperty(`context.cart_token`, event.cart_token); - message.setProperty(`context.checkout_token`, event.checkout_token); - if (shopifyTopic === 'orders_updated') { - message.setProperty(`context.order_token`, event.token); - } - message = removeUndefinedAndNullValues(message); - return message; -}; -const isIdentifierEvent = (event) => - ['rudderIdentifier', 'rudderSessionIdentifier'].includes(event?.event); -const processIdentifierEvent = async (event, metricMetadata) => { - if (useRedisDatabase) { - const cartToken = - typeof event.cartToken === 'string' ? event.cartToken.split('?')[0] : event.cartToken; - logger.info(`{{SHOPIFY::}} writeKey: ${metricMetadata.writeKey}, cartToken: ${cartToken}`, { - type: 'set', - source: metricMetadata.source, - writeKey: metricMetadata.writeKey, - }); - let value; - let field; - if (event.event === 'rudderIdentifier') { - field = 'anonymousId'; - // eslint-disable-next-line unicorn/consistent-destructuring - const lineItemshash = getHashLineItems(event.cart); - // eslint-disable-next-line unicorn/consistent-destructuring - value = ['anonymousId', event.anonymousId, 'itemsHash', lineItemshash]; - stats.increment('shopify_redis_calls', { - type: 'set', - field: 'itemsHash', - source: metricMetadata.source, - writeKey: metricMetadata.writeKey, - }); - /* cart_token: { - anonymousId: 'anon_id1', - lineItemshash: '0943gh34pg' - } - */ - } else { - field = 'sessionId'; - // eslint-disable-next-line unicorn/consistent-destructuring - value = ['sessionId', event.sessionId]; - /* cart_token: { - anonymousId:'anon_id1', - lineItemshash:'90fg348fg83497u', - sessionId: 'session_id1' - } - */ - } - try { - stats.increment('shopify_redis_calls', { - type: 'set', - field, - source: metricMetadata.source, - writeKey: metricMetadata.writeKey, - }); - await RedisDB.setVal(`${cartToken}`, value); - } catch (e) { - logger.debug(`{{SHOPIFY::}} cartToken map set call Failed due redis error ${e}`, { - type: 'set', - source: metricMetadata.source, - writeKey: metricMetadata.writeKey, - }); - stats.increment('shopify_redis_failures', { - type: 'set', - source: metricMetadata.source, - writeKey: metricMetadata.writeKey, - }); - // returning 500 as status code in case of redis failure - throw new RedisError(`${e}`, 500); - } - } - return NO_OPERATION_SUCCESS; -}; + processEvent, + isIdentifierEvent, + processIdentifierEvent, +} = require('../../../v0/sources/shopify/transform'); const process = async (inputEvent) => { const { event, source } = inputEvent; @@ -283,8 +25,12 @@ const process = async (inputEvent) => { const responseV2 = await processEventV2(event); return responseV2; } - const webhookEvent = processEvent(event, metricMetadata, source); - return webhookEvent; + const webhookEventResponse = await processEvent(event, metricMetadata, source); + webhookEventResponse.context.library = { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }; + return webhookEventResponse; } if (isIdentifierEvent(event)) { return processIdentifierEvent(event, metricMetadata); diff --git a/src/v1/sources/shopify/util.js b/src/v1/sources/shopify/util.js deleted file mode 100644 index 28f07fc3de..0000000000 --- a/src/v1/sources/shopify/util.js +++ /dev/null @@ -1,313 +0,0 @@ -/* eslint-disable no-param-reassign */ -/* eslint-disable camelcase */ -/* eslint-disable @typescript-eslint/naming-convention */ -const { v5 } = require('uuid'); -const get = require('get-value'); -const sha256 = require('sha256'); -const { TransformationError } = require('@rudderstack/integrations-lib'); -const stats = require('../../../util/stats'); -const { - constructPayload, - extractCustomFields, - flattenJson, - generateUUID, - isDefinedAndNotNull, -} = require('../../../v0/util'); -const { EventType } = require('../../../constants'); -const { RedisDB } = require('../../../util/redis/redisConnector'); -const { - MAPPING_CATEGORIES, - lineItemsMappingJSON, - productMappingJSON, - LINE_ITEM_EXCLUSION_FIELDS, - PRODUCT_MAPPING_EXCLUSION_FIELDS, - SHOPIFY_TRACK_MAP, - SHOPIFY_ADMIN_ONLY_EVENTS, - useRedisDatabase, - maxTimeToIdentifyRSGeneratedCall, -} = require('./config'); -const logger = require('../../../logger'); - -const getDataFromRedis = async (key, metricMetadata, event) => { - try { - stats.increment('shopify_redis_calls', { - type: 'get', - field: 'all', - writeKey: metricMetadata.writeKey, - source: metricMetadata.source, - }); - const redisData = await RedisDB.getVal(key); - if ( - redisData === null || - (typeof redisData === 'object' && Object.keys(redisData).length === 0) - ) { - stats.increment('shopify_redis_no_val', { - writeKey: metricMetadata.writeKey, - source: metricMetadata.source, - event, - }); - } - return redisData; - } catch (e) { - logger.debug(`{{SHOPIFY::}} Get call Failed due redis error ${e}`); - stats.increment('shopify_redis_failures', { - type: 'get', - writeKey: metricMetadata.writeKey, - source: metricMetadata.source, - }); - } - return null; -}; -/** - * query_parameters : { topic: [''], ...} - * Throws error otherwise - * @param {*} event - * @returns - */ -const getShopifyTopic = (event) => { - const { query_parameters: qParams } = event; - logger.debug(`[Shopify] Input event: query_params: ${JSON.stringify(qParams)}`); - if (!qParams) { - throw new TransformationError('Query_parameters is missing'); - } - const { topic } = qParams; - if (!topic || !Array.isArray(topic)) { - throw new TransformationError('Invalid topic in query_parameters'); - } - if (topic.length === 0) { - throw new TransformationError('Topic not found'); - } - return topic[0]; -}; -const getHashLineItems = (cart) => { - if (cart && cart?.line_items && cart.line_items.length > 0) { - return sha256(JSON.stringify(cart.line_items)); - } - return 'EMPTY'; -}; -const getVariantString = (lineItem) => { - const { variant_id, variant_price, variant_title } = lineItem; - return `${variant_id || ''} ${variant_price || ''} ${variant_title || ''}`; -}; - -const getProductsListFromLineItems = (lineItems) => { - if (!lineItems || lineItems.length === 0) { - return []; - } - const products = []; - lineItems.forEach((lineItem) => { - const product = constructPayload(lineItem, lineItemsMappingJSON); - extractCustomFields(lineItem, product, 'root', LINE_ITEM_EXCLUSION_FIELDS); - product.variant = getVariantString(lineItem); - products.push(product); - }); - return products; -}; - -const createPropertiesForEcomEvent = (message) => { - const { line_items: lineItems } = message; - const productsList = getProductsListFromLineItems(lineItems); - const mappedPayload = constructPayload(message, productMappingJSON); - extractCustomFields(message, mappedPayload, 'root', PRODUCT_MAPPING_EXCLUSION_FIELDS); - mappedPayload.products = productsList; - return mappedPayload; -}; - -const extractEmailFromPayload = (event) => { - const flattenedPayload = flattenJson(event); - let email; - const regex_email = /\bemail\b/i; - Object.entries(flattenedPayload).some(([key, value]) => { - if (regex_email.test(key)) { - email = value; - return true; - } - return false; - }); - return email; -}; - -const getCartToken = (message) => { - const { event, properties } = message; - if (event === SHOPIFY_TRACK_MAP.carts_update) { - return properties?.id || properties?.token; - } - return properties?.cart_token || null; -}; - -/** - * This function checks and returns rudderId from message if present - * returns null if not present or found - * @param {*} message - */ -const getRudderIdFromNoteAtrributes = (noteAttributes, field) => { - const rudderIdObj = noteAttributes.find((obj) => obj.name === field); - if (isDefinedAndNotNull(rudderIdObj)) { - return rudderIdObj.value; - } - return null; -}; -/** - * This function retrieves anonymousId and sessionId in folowing steps: - * 1. Checks for `rudderAnonymousId`and `rudderSessionId in `note_atrributes` - * 2. if redis is enabled checks in redis - * 3. This means we don't have `anonymousId` and hence events CAN NOT be stitched and we check for cartToken - * a. if cartToken is available we return its hash value - * b. else we check if the event is an SHOPIFY_ADMIN_ONLY_EVENT - * -> if true we return `null`; - * -> else we don't have any identifer (very edge case) we return `random anonymousId` - * No Random SessionId is generated as its not a required field - * @param {*} message - * @param {*} metricMetadata - * @returns - */ -const getAnonymousIdAndSessionId = async (message, metricMetadata, redisData = null) => { - let anonymousId; - let sessionId; - const noteAttributes = message.properties?.note_attributes; - // Giving Priority to note_attributes to fetch rudderAnonymousId over Redis due to better efficiency - if (isDefinedAndNotNull(noteAttributes)) { - anonymousId = getRudderIdFromNoteAtrributes(noteAttributes, 'rudderAnonymousId'); - sessionId = getRudderIdFromNoteAtrributes(noteAttributes, 'rudderSessionId'); - } - // falling back to cartToken mapping or its hash in case no rudderAnonymousId or rudderSessionId is found - if (isDefinedAndNotNull(anonymousId) && isDefinedAndNotNull(sessionId)) { - stats.increment('shopify_anon_id_resolve', { - method: 'note_attributes', - writeKey: metricMetadata.writeKey, - source: metricMetadata.source, - shopifyTopic: metricMetadata.shopifyTopic, - }); - return { anonymousId, sessionId }; - } - const cartToken = getCartToken(message); - if (!isDefinedAndNotNull(cartToken)) { - if (SHOPIFY_ADMIN_ONLY_EVENTS.includes(message.event)) { - return { anonymousId, sessionId }; - } - return { - anonymousId: isDefinedAndNotNull(anonymousId) ? anonymousId : generateUUID(), - sessionId, - }; - } - if (useRedisDatabase) { - if (!isDefinedAndNotNull(redisData)) { - const { event } = message; - // eslint-disable-next-line no-param-reassign - redisData = await getDataFromRedis(cartToken, metricMetadata, event); - } - anonymousId = redisData?.anonymousId; - sessionId = redisData?.sessionId; - } - if (!isDefinedAndNotNull(anonymousId)) { - /* anonymousId or sessionId not found from db as well - Hash the id and use it as anonymousId (limiting 256 -> 36 chars) and sessionId is not sent as its not required field - */ - anonymousId = v5(cartToken, v5.URL); - } else { - // This metric let us know how many events based on event name used redis for anonId resolution - // and for how many - stats.increment('shopify_anon_id_resolve', { - method: 'database', - writeKey: metricMetadata.writeKey, - source: metricMetadata.source, - shopifyTopic: metricMetadata.shopifyTopic, - }); - } - return { anonymousId, sessionId }; -}; -/** - * It checks if the event is valid or not based on previous cartItems - * @param {*} inputEvent - * @returns true if event is valid else false - */ -const isValidCartEvent = (newCartItems, prevCartItems) => !(prevCartItems === newCartItems); -const updateCartItemsInRedis = async (cartToken, newCartItemsHash, metricMetadata) => { - const value = ['itemsHash', newCartItemsHash]; - try { - stats.increment('shopify_redis_calls', { - type: 'set', - field: 'itemsHash', - writeKey: metricMetadata.writeKey, - source: metricMetadata.source, - }); - await RedisDB.setVal(`${cartToken}`, value); - } catch (e) { - logger.debug(`{{SHOPIFY::}} itemsHash set call Failed due redis error ${e}`); - stats.increment('shopify_redis_failures', { - type: 'set', - writeKey: metricMetadata.writeKey, - source: metricMetadata.source, - }); - } -}; -/** - * This function checks for duplicate cart update event by checking the lineItems hash of previous cart update event - * and comapre it with the received lineItems hash. - * Also if redis is down or there is no lineItems hash for the given cartToken we be default take it as a valid cart update event - * @param {*} inputEvent - * @param {*} metricMetadata - * @returns boolean - */ -const checkAndUpdateCartItems = async (inputEvent, redisData, metricMetadata, shopifyTopic) => { - const cartToken = inputEvent.token || inputEvent.id; - if (!isDefinedAndNotNull(redisData)) { - // eslint-disable-next-line no-param-reassign - redisData = await getDataFromRedis(cartToken, metricMetadata, SHOPIFY_TRACK_MAP[shopifyTopic]); - } - const itemsHash = redisData?.itemsHash; - if (isDefinedAndNotNull(itemsHash)) { - const newCartItemsHash = getHashLineItems(inputEvent); - const isCartValid = isValidCartEvent(newCartItemsHash, itemsHash); - if (!isCartValid) { - return false; - } - await updateCartItemsInRedis(cartToken, newCartItemsHash, metricMetadata); - } else { - const { created_at, updated_at, line_items } = inputEvent; - const timeDifference = Date.parse(updated_at) - Date.parse(created_at); - const isTimeWithinThreshold = timeDifference < maxTimeToIdentifyRSGeneratedCall; - const isLineItemsEmpty = line_items?.length === 0; - - if (isTimeWithinThreshold && isLineItemsEmpty) { - return false; - } - } - return true; -}; - -const mapCustomerDetails = (event, message) => { - const customerDetails = get(event, 'customer'); - if (customerDetails) { - message.setPropertiesV2(customerDetails, MAPPING_CATEGORIES[EventType.IDENTIFY]); - } - if (event.updated_at) { - // TODO: look for created_at for checkout_create? - // converting shopify updated_at timestamp to rudder timestamp format - message.setTimestamp(new Date(event.updated_at).toISOString()); - } - if (event.customer) { - message.setPropertiesV2(event.customer, MAPPING_CATEGORIES[EventType.IDENTIFY]); - } - if (event.shipping_address) { - message.setProperty('traits.shippingAddress', event.shipping_address); - } - if (event.billing_address) { - message.setProperty('traits.billingAddress', event.billing_address); - } - if (!message.userId && event.user_id) { - message.setProperty('userId', event.user_id); - } -}; - -module.exports = { - getShopifyTopic, - getProductsListFromLineItems, - createPropertiesForEcomEvent, - extractEmailFromPayload, - getAnonymousIdAndSessionId, - checkAndUpdateCartItems, - getHashLineItems, - getDataFromRedis, - mapCustomerDetails, -}; From 155024de61f77f5954746b316f56d6bad01d1383 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:46:47 +0530 Subject: [PATCH 17/22] chore: sonarcloud reliability check fix --- src/v1/sources/shopify/pixelTransform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/pixelTransform.js index 5cabbde1eb..ba64bc4810 100644 --- a/src/v1/sources/shopify/pixelTransform.js +++ b/src/v1/sources/shopify/pixelTransform.js @@ -27,7 +27,7 @@ function processPixelEvent(inputEvent) { const { checkout } = data ?? {}; const { order } = checkout ?? {}; const { customer } = order ?? {}; - let message; + let message = {}; switch (name) { case PIXEL_EVENT_TOPICS.PAGE_VIEWED: message = pageViewedEventBuilder(inputEvent); From c8c77f289fed006fd2e49f9708825d65b7a65b83 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Fri, 20 Sep 2024 10:03:56 +0530 Subject: [PATCH 18/22] chore: update util file names --- src/v1/sources/shopify/pixelTransform.js | 2 +- src/v1/sources/shopify/{utilV2.js => pixelUtils.js} | 0 .../shopify/{shopify.util.test.js => pixelUtils.test.js} | 2 +- src/v1/sources/shopify/transform.js | 1 + 4 files changed, 3 insertions(+), 2 deletions(-) rename src/v1/sources/shopify/{utilV2.js => pixelUtils.js} (100%) rename src/v1/sources/shopify/{shopify.util.test.js => pixelUtils.test.js} (99%) diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/pixelTransform.js index ba64bc4810..dc9f00b23f 100644 --- a/src/v1/sources/shopify/pixelTransform.js +++ b/src/v1/sources/shopify/pixelTransform.js @@ -10,7 +10,7 @@ const { checkoutEventBuilder, checkoutStepEventBuilder, searchEventBuilder, -} = require('./utilV2'); +} = require('./pixelUtils'); const { INTEGERATION, PIXEL_EVENT_TOPICS } = require('./config'); const NO_OPERATION_SUCCESS = { diff --git a/src/v1/sources/shopify/utilV2.js b/src/v1/sources/shopify/pixelUtils.js similarity index 100% rename from src/v1/sources/shopify/utilV2.js rename to src/v1/sources/shopify/pixelUtils.js diff --git a/src/v1/sources/shopify/shopify.util.test.js b/src/v1/sources/shopify/pixelUtils.test.js similarity index 99% rename from src/v1/sources/shopify/shopify.util.test.js rename to src/v1/sources/shopify/pixelUtils.test.js index 6202d4ec88..cd544568cd 100644 --- a/src/v1/sources/shopify/shopify.util.test.js +++ b/src/v1/sources/shopify/pixelUtils.test.js @@ -7,7 +7,7 @@ const { checkoutEventBuilder, checkoutStepEventBuilder, searchEventBuilder, -} = require('./utilV2'); +} = require('./pixelUtils'); const { EventType } = require('../../../constants'); const Message = require('../../../v0/sources/message'); jest.mock('ioredis', () => require('../../../../test/__mocks__/redis')); diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index e0cf4dbb32..2b86e1de0f 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -35,6 +35,7 @@ const process = async (inputEvent) => { if (isIdentifierEvent(event)) { return processIdentifierEvent(event, metricMetadata); } + // this is for default legacy tracker based server-side events processing const response = await processEvent(event, metricMetadata, source); return response; }; From 28859689554ed10fc393ba65543de3ec551d3322 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:44:02 +0530 Subject: [PATCH 19/22] chore: move webhook specific logic for v2 pixel, address comments --- src/v0/sources/shopify/transform.js | 3 + src/v1/sources/shopify/pixelTransform.js | 5 +- .../shopify/pixelWebhookEventTransform.js | 86 +++++++++++++++++++ src/v1/sources/shopify/transform.js | 11 +-- test/integrations/sources/shopify/data.ts | 14 ++- 5 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 src/v1/sources/shopify/pixelWebhookEventTransform.js diff --git a/src/v0/sources/shopify/transform.js b/src/v0/sources/shopify/transform.js index 584d8810af..a207e70850 100644 --- a/src/v0/sources/shopify/transform.js +++ b/src/v0/sources/shopify/transform.js @@ -292,4 +292,7 @@ module.exports = { processEvent, isIdentifierEvent, processIdentifierEvent, + identifyPayloadBuilder, + ecomPayloadBuilder, + trackPayloadBuilder, }; diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/pixelTransform.js index dc9f00b23f..8f2b4223a0 100644 --- a/src/v1/sources/shopify/pixelTransform.js +++ b/src/v1/sources/shopify/pixelTransform.js @@ -80,12 +80,11 @@ function processPixelEvent(inputEvent) { return message; } -const processEventV2 = async (event) => { +const processEventFromPixel = async (event) => { const pixelEvent = processPixelEvent(event); return removeUndefinedAndNullValues(pixelEvent); }; module.exports = { - processEventV2, - processPixelEvent, + processEventFromPixel, }; diff --git a/src/v1/sources/shopify/pixelWebhookEventTransform.js b/src/v1/sources/shopify/pixelWebhookEventTransform.js new file mode 100644 index 0000000000..6dc4b362e9 --- /dev/null +++ b/src/v1/sources/shopify/pixelWebhookEventTransform.js @@ -0,0 +1,86 @@ +const lodash = require('lodash'); +const get = require('get-value'); +const stats = require('../../../util/stats'); +const { getShopifyTopic, extractEmailFromPayload } = require('../../../v0/sources/shopify/util'); +const { + identifyPayloadBuilder, + trackPayloadBuilder, + ecomPayloadBuilder, +} = require('../../../v0/sources/shopify/transform'); +const { removeUndefinedAndNullValues, generateUUID } = require('../../../v0/util'); +const Message = require('../../../v0/sources/message'); +const { + INTEGERATION, + IDENTIFY_TOPICS, + ECOM_TOPICS, + SUPPORTED_TRACK_EVENTS, +} = require('../../../v0/sources/shopify/config'); + +const NO_OPERATION_SUCCESS = { + outputToSource: { + body: Buffer.from('OK').toString('base64'), + contentType: 'text/plain', + }, + statusCode: 200, +}; + +const processPixelWebhookEvent = async (inputEvent, metricMetadata) => { + let message = new Message(INTEGERATION); + const event = lodash.cloneDeep(inputEvent); + const shopifyTopic = getShopifyTopic(event); + delete event.query_parameters; + switch (shopifyTopic) { + case IDENTIFY_TOPICS.CUSTOMERS_CREATE: + case IDENTIFY_TOPICS.CUSTOMERS_UPDATE: + message = identifyPayloadBuilder(event); + break; + case ECOM_TOPICS.ORDERS_CREATE: + case ECOM_TOPICS.ORDERS_UPDATE: + case ECOM_TOPICS.CHECKOUTS_CREATE: + case ECOM_TOPICS.CHECKOUTS_UPDATE: + message = ecomPayloadBuilder(event, shopifyTopic); + break; + case 'carts_update': + message = trackPayloadBuilder(event, shopifyTopic); + break; + default: + if (!SUPPORTED_TRACK_EVENTS.includes(shopifyTopic)) { + stats.increment('invalid_shopify_event', { + writeKey: metricMetadata.writeKey, + source: metricMetadata.source, + shopifyTopic: metricMetadata.shopifyTopic, + }); + return NO_OPERATION_SUCCESS; + } + message = trackPayloadBuilder(event, shopifyTopic); + break; + } + + if (message.userId) { + message.userId = String(message.userId); + } + message.anonymousId = generateUUID(); + + if (!get(message, 'traits.email')) { + const email = extractEmailFromPayload(event); + if (email) { + message.setProperty('traits.email', email); + } + } + message.setProperty(`integrations.${INTEGERATION}`, true); + message.setProperty('context.library', { + name: 'RudderStack Shopify Cloud', + version: '2.0.0', + }); + message.setProperty('context.topic', shopifyTopic); + // attaching cart, checkout and order tokens in context object + message.setProperty(`context.cart_token`, event.cart_token); + message.setProperty(`context.checkout_token`, event.checkout_token); + if (shopifyTopic === 'orders_updated') { + message.setProperty(`context.order_token`, event.token); + } + message = removeUndefinedAndNullValues(message); + return message; +}; + +module.exports = { processPixelWebhookEvent }; diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index 2b86e1de0f..2b87d58c6e 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ const { isDefinedAndNotNull } = require('../../../v0/util'); -const { processEventV2 } = require('./pixelTransform'); +const { processEventFromPixel } = require('./pixelTransform'); +const { processPixelWebhookEvent } = require('./pixelWebhookEventTransform'); const { processEvent, isIdentifierEvent, @@ -22,14 +23,10 @@ const process = async (inputEvent) => { if (pixelEventLabel) { // this is a event fired from the web pixel loaded on the browser // by the user interactions with the store. - const responseV2 = await processEventV2(event); + const responseV2 = await processEventFromPixel(event); return responseV2; } - const webhookEventResponse = await processEvent(event, metricMetadata, source); - webhookEventResponse.context.library = { - name: 'RudderStack Shopify Cloud', - version: '2.0.0', - }; + const webhookEventResponse = await processPixelWebhookEvent(event, metricMetadata, source); return webhookEventResponse; } if (isIdentifierEvent(event)) { diff --git a/test/integrations/sources/shopify/data.ts b/test/integrations/sources/shopify/data.ts index 2c30fd0aa0..c00f1a4997 100644 --- a/test/integrations/sources/shopify/data.ts +++ b/test/integrations/sources/shopify/data.ts @@ -1,4 +1,8 @@ import { skip } from 'node:test'; +import utils from '../../../../src/v0/util'; +const defaultMockFns = () => { + jest.spyOn(utils, 'generateUUID').mockReturnValue('97fcd7b2-cc24-47d7-b776-057b7b199513'); +}; const dummySourceConfig = { ID: 'dummy-source-id', @@ -5546,7 +5550,7 @@ const v1ServerSideEventsScenarios = [ }, }, timestamp: '2024-09-17T07:29:02.000Z', - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '97fcd7b2-cc24-47d7-b776-057b7b199513', }, ], }, @@ -5554,6 +5558,9 @@ const v1ServerSideEventsScenarios = [ ], }, }, + mockFns: () => { + defaultMockFns(); + }, }, { name: 'shopify', @@ -5758,7 +5765,7 @@ const v1ServerSideEventsScenarios = [ }, ], }, - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '97fcd7b2-cc24-47d7-b776-057b7b199513', }, ], }, @@ -5766,6 +5773,9 @@ const v1ServerSideEventsScenarios = [ ], }, }, + mockFns: () => { + defaultMockFns(); + }, }, ]; From f65379d20ab0c77fc9e151b809b86350272e2a53 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Fri, 20 Sep 2024 16:04:23 +0530 Subject: [PATCH 20/22] chore: more refactoring, update userId and anonymousid from customer object --- src/v0/sources/shopify/transform.js | 2 -- src/v1/sources/shopify/pixelWebhookEventTransform.js | 5 +++-- src/v1/sources/shopify/transform.js | 11 ++--------- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/v0/sources/shopify/transform.js b/src/v0/sources/shopify/transform.js index a207e70850..8cf39dfa5c 100644 --- a/src/v0/sources/shopify/transform.js +++ b/src/v0/sources/shopify/transform.js @@ -290,8 +290,6 @@ const process = async (event) => { module.exports = { process, processEvent, - isIdentifierEvent, - processIdentifierEvent, identifyPayloadBuilder, ecomPayloadBuilder, trackPayloadBuilder, diff --git a/src/v1/sources/shopify/pixelWebhookEventTransform.js b/src/v1/sources/shopify/pixelWebhookEventTransform.js index 6dc4b362e9..0ac469e98a 100644 --- a/src/v1/sources/shopify/pixelWebhookEventTransform.js +++ b/src/v1/sources/shopify/pixelWebhookEventTransform.js @@ -1,5 +1,6 @@ const lodash = require('lodash'); const get = require('get-value'); +const { isDefinedNotNullNotEmpty } = require('@rudderstack/integrations-lib'); const stats = require('../../../util/stats'); const { getShopifyTopic, extractEmailFromPayload } = require('../../../v0/sources/shopify/util'); const { @@ -56,8 +57,8 @@ const processPixelWebhookEvent = async (inputEvent, metricMetadata) => { break; } - if (message.userId) { - message.userId = String(message.userId); + if (event.customer && isDefinedNotNullNotEmpty(event?.customer?.id)) { + message.userId = String(event.customer.id); } message.anonymousId = generateUUID(); diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index 2b87d58c6e..586b6f0220 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -2,11 +2,7 @@ const { isDefinedAndNotNull } = require('../../../v0/util'); const { processEventFromPixel } = require('./pixelTransform'); const { processPixelWebhookEvent } = require('./pixelWebhookEventTransform'); -const { - processEvent, - isIdentifierEvent, - processIdentifierEvent, -} = require('../../../v0/sources/shopify/transform'); +const { process: processLegacyEvents } = require('../../../v0/sources/shopify/transform'); const process = async (inputEvent) => { const { event, source } = inputEvent; @@ -29,11 +25,8 @@ const process = async (inputEvent) => { const webhookEventResponse = await processPixelWebhookEvent(event, metricMetadata, source); return webhookEventResponse; } - if (isIdentifierEvent(event)) { - return processIdentifierEvent(event, metricMetadata); - } // this is for default legacy tracker based server-side events processing - const response = await processEvent(event, metricMetadata, source); + const response = await processLegacyEvents(event); return response; }; From ef7e429d12dc6420041bd684255d5b86ca159c3b Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Fri, 20 Sep 2024 17:55:17 +0530 Subject: [PATCH 21/22] chore: update library name for pixel and webhook events in pixel app flow --- src/v1/sources/shopify/pixelTransform.js | 1 + .../sources/shopify/pixelWebhookEventTransform.js | 1 + test/integrations/sources/shopify/data.ts | 15 +++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/pixelTransform.js index 8f2b4223a0..0ca64b4123 100644 --- a/src/v1/sources/shopify/pixelTransform.js +++ b/src/v1/sources/shopify/pixelTransform.js @@ -73,6 +73,7 @@ function processPixelEvent(inputEvent) { message.setProperty(`integrations.${INTEGERATION}`, true); message.setProperty('context.library', { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }); message.setProperty('context.topic', name); diff --git a/src/v1/sources/shopify/pixelWebhookEventTransform.js b/src/v1/sources/shopify/pixelWebhookEventTransform.js index 0ac469e98a..43b741f837 100644 --- a/src/v1/sources/shopify/pixelWebhookEventTransform.js +++ b/src/v1/sources/shopify/pixelWebhookEventTransform.js @@ -71,6 +71,7 @@ const processPixelWebhookEvent = async (inputEvent, metricMetadata) => { message.setProperty(`integrations.${INTEGERATION}`, true); message.setProperty('context.library', { name: 'RudderStack Shopify Cloud', + eventOrigin: 'server', version: '2.0.0', }); message.setProperty('context.topic', shopifyTopic); diff --git a/test/integrations/sources/shopify/data.ts b/test/integrations/sources/shopify/data.ts index c00f1a4997..0a9911e96c 100644 --- a/test/integrations/sources/shopify/data.ts +++ b/test/integrations/sources/shopify/data.ts @@ -178,6 +178,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'page_viewed', @@ -376,6 +377,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'product_viewed', @@ -626,6 +628,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'cart_viewed', @@ -917,6 +920,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'collection_viewed', @@ -1207,6 +1211,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'product_added_to_cart', @@ -1456,6 +1461,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'product_removed_from_cart', @@ -1827,6 +1833,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'checkout_started', @@ -2227,6 +2234,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'checkout_address_info_submitted', @@ -2721,6 +2729,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'checkout_contact_info_submitted', @@ -3214,6 +3223,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'checkout_shipping_info_submitted', @@ -3725,6 +3735,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'payment_info_submitted', @@ -4219,6 +4230,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'checkout_completed', @@ -4456,6 +4468,7 @@ const pixelEventsTestScenarios = [ }, library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', version: '2.0.0', }, topic: 'search_submitted', @@ -5391,6 +5404,7 @@ const v1ServerSideEventsScenarios = [ context: { library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'server', version: '2.0.0', }, integration: { @@ -5674,6 +5688,7 @@ const v1ServerSideEventsScenarios = [ context: { library: { name: 'RudderStack Shopify Cloud', + eventOrigin: 'server', version: '2.0.0', }, integration: { From 56b1c6fda562d2a687a14eca5839a6132edfe174 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:22:23 +0530 Subject: [PATCH 22/22] chore: refactor pixel tests to seperate directory, remove reduntant test data --- src/v1/sources/shopify/transform.js | 4 +- .../integrations/sources/shopify/constants.ts | 155 + test/integrations/sources/shopify/data.ts | 5192 +---------------- .../pixelTestScenarios/CheckoutEventsTests.ts | 570 ++ .../pixelTestScenarios/CheckoutStepsTests.ts | 1517 +++++ .../pixelTestScenarios/ProductEventsTests.ts | 888 +++ .../shopify/v1ServerSideEventsTests.ts | 598 ++ 7 files changed, 3736 insertions(+), 5188 deletions(-) create mode 100644 test/integrations/sources/shopify/constants.ts create mode 100644 test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts create mode 100644 test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts create mode 100644 test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts create mode 100644 test/integrations/sources/shopify/v1ServerSideEventsTests.ts diff --git a/src/v1/sources/shopify/transform.js b/src/v1/sources/shopify/transform.js index 586b6f0220..ff9aadbca4 100644 --- a/src/v1/sources/shopify/transform.js +++ b/src/v1/sources/shopify/transform.js @@ -15,8 +15,8 @@ const process = async (inputEvent) => { // check on the source Config to identify the event is from the tracker-based (legacy) // or the pixel-based (latest) implementation. if (source && isDefinedAndNotNull(source.Config) && source?.Config?.version === 'pixel') { - const { pixelEventLabel } = event; - if (pixelEventLabel) { + const { pixelEventLabel: pixelClientEventLabel } = event; + if (pixelClientEventLabel) { // this is a event fired from the web pixel loaded on the browser // by the user interactions with the store. const responseV2 = await processEventFromPixel(event); diff --git a/test/integrations/sources/shopify/constants.ts b/test/integrations/sources/shopify/constants.ts new file mode 100644 index 0000000000..f9df305841 --- /dev/null +++ b/test/integrations/sources/shopify/constants.ts @@ -0,0 +1,155 @@ +export const dummySourceConfig = { + ID: 'dummy-source-id', + OriginalID: '', + Name: 'Shopify v2', + Config: { + disableClientSideIdentifier: false, + eventUpload: false, + version: 'pixel', + }, + Enabled: true, + WorkspaceID: 'dummy-workspace-id', + Destinations: null, + WriteKey: 'dummy-write-key', +}; + +export const dummyBillingAddresses = [ + { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, +]; + +export const dummyContext = { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, +}; + +export const responseDummyContext = { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', + version: '2.0.0', + }, +}; diff --git a/test/integrations/sources/shopify/data.ts b/test/integrations/sources/shopify/data.ts index 0a9911e96c..7a74bc4d06 100644 --- a/test/integrations/sources/shopify/data.ts +++ b/test/integrations/sources/shopify/data.ts @@ -1,4599 +1,8 @@ import { skip } from 'node:test'; -import utils from '../../../../src/v0/util'; -const defaultMockFns = () => { - jest.spyOn(utils, 'generateUUID').mockReturnValue('97fcd7b2-cc24-47d7-b776-057b7b199513'); -}; - -const dummySourceConfig = { - ID: 'dummy-source-id', - OriginalID: '', - Name: 'Shopify v2', - Config: { - disableClientSideIdentifier: false, - eventUpload: false, - version: 'pixel', - }, - Enabled: true, - WorkspaceID: 'dummy-workspace-id', - Destinations: null, - WriteKey: 'dummy-write-key', -}; - -const pixelEventsTestScenarios = [ - { - name: 'shopify', - description: 'Page Call -> page_view event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f6b6f548-5FEF-4DAE-9CAB-39EE6F94E09B', - name: 'page_viewed', - data: {}, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T17:24:30.373Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - characterSet: 'UTF-8', - title: 'pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['page_viewed'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/', - port: '', - protocol: 'https:', - search: '', - }, - referrer: - 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - characterSet: 'UTF-8', - title: 'pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'pixel-testing-rs', - url: 'https://store.myshopify.com/', - path: '/', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'page_viewed', - }, - integrations: { - SHOPIFY: true, - }, - name: 'Page View', - type: 'page', - properties: {}, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> product_viewed event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f6c07b5a-D20A-4E5F-812E-337299B56C34', - name: 'product_viewed', - data: { - productVariant: { - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - id: '7234590834801', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - type: 'snowboard', - }, - id: '41327143321713', - image: { - src: '//store.myshopify.com/cdn/shop/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', - }, - sku: '', - title: 'Default Title', - untranslatedTitle: 'Default Title', - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T17:34:54.889Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/products/the-collection-snowboard-liquid', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/', - characterSet: 'UTF-8', - title: 'The Collection Snowboard: Liquid – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/products/the-collection-snowboard-liquid', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['product_viewed'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/products/the-collection-snowboard-liquid', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/', - characterSet: 'UTF-8', - title: 'The Collection Snowboard: Liquid – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/products/the-collection-snowboard-liquid', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'The Collection Snowboard: Liquid – pixel-testing-rs', - url: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - path: '/products/the-collection-snowboard-liquid', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'product_viewed', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Product Viewed', - properties: { - productVariant: { - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - id: '7234590834801', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - type: 'snowboard', - }, - id: '41327143321713', - image: { - src: '//store.myshopify.com/cdn/shop/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', - }, - sku: '', - title: 'Default Title', - untranslatedTitle: 'Default Title', - }, - product_id: '7234590834801', - variant: 'The Collection Snowboard: Liquid', - brand: 'Hydrogen Vendor', - category: 'snowboard', - price: 749.95, - currency: 'USD', - url: '/products/the-collection-snowboard-liquid', - name: 'The Collection Snowboard: Liquid', - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> cart_viewed event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'shu-f6eecef1-4132-459F-CDB5-681DA3DD61CD', - name: 'cart_viewed', - data: { - cart: { - cost: { - totalAmount: { - amount: 1259.9, - currencyCode: 'USD', - }, - }, - lines: [ - { - cost: { - totalAmount: { - amount: 1259.9, - currencyCode: 'USD', - }, - }, - merchandise: { - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - id: '7234590736497', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - type: 'snowboard', - }, - id: '41327143157873', - image: { - src: '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', - }, - sku: 'sku-managed-1', - title: 'Default Title', - untranslatedTitle: 'Default Title', - }, - quantity: 2, - }, - ], - totalQuantity: 2, - attributes: [], - id: 'Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T18:25:30.125Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/cart', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/cart', - port: '', - protocol: 'https:', - search: '', - }, - referrer: '', - characterSet: 'UTF-8', - title: 'Your Shopping Cart – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/cart', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/cart', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['cart_viewed'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/cart', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/cart', - port: '', - protocol: 'https:', - search: '', - }, - referrer: '', - characterSet: 'UTF-8', - title: 'Your Shopping Cart – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/cart', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/cart', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'Your Shopping Cart – pixel-testing-rs', - url: 'https://store.myshopify.com/cart', - path: '/cart', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'cart_viewed', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Cart Viewed', - properties: { - products: [ - { - cost: { - totalAmount: { - amount: 1259.9, - currencyCode: 'USD', - }, - }, - merchandise: { - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - id: '7234590736497', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - type: 'snowboard', - }, - id: '41327143157873', - image: { - src: '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', - }, - sku: 'sku-managed-1', - title: 'Default Title', - untranslatedTitle: 'Default Title', - }, - quantity: 2, - product_id: '7234590736497', - variant: 'The Multi-managed Snowboard', - image_url: - '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', - price: 629.95, - category: 'snowboard', - url: '/products/the-multi-managed-snowboard', - brand: 'Multi-managed Vendor', - sku: 'sku-managed-1', - name: 'Default Title', - }, - ], - cart_id: 'Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - total: 1259.9, - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> collection_viewed event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f6f0c6be-43F8-47D2-5F94-C22AD5ED3E79', - name: 'collection_viewed', - data: { - collection: { - id: '', - title: 'Products', - productVariants: [ - { - price: { - amount: 10, - currencyCode: 'USD', - }, - product: { - title: 'Gift Card', - vendor: 'Snowboard Vendor', - id: '7234590605425', - untranslatedTitle: 'Gift Card', - url: '/products/gift-card', - type: 'giftcard', - }, - id: '41327142895729', - image: { - src: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', - }, - sku: '', - title: '$10', - untranslatedTitle: '$10', - }, - { - price: { - amount: 24.95, - currencyCode: 'USD', - }, - product: { - title: 'Selling Plans Ski Wax', - vendor: 'pixel-testing-rs', - id: '7234590802033', - untranslatedTitle: 'Selling Plans Ski Wax', - url: '/products/selling-plans-ski-wax', - type: 'accessories', - }, - id: '41327143223409', - image: { - src: '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', - }, - sku: '', - title: 'Selling Plans Ski Wax', - untranslatedTitle: 'Selling Plans Ski Wax', - }, - { - price: { - amount: 2629.95, - currencyCode: 'USD', - }, - product: { - title: 'The 3p Fulfilled Snowboard', - vendor: 'pixel-testing-rs', - id: '7234590703729', - untranslatedTitle: 'The 3p Fulfilled Snowboard', - url: '/products/the-3p-fulfilled-snowboard', - type: 'snowboard', - }, - id: '41327143125105', - image: { - src: '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', - }, - sku: 'sku-hosted-1', - title: 'Default Title', - untranslatedTitle: 'Default Title', - }, - ], - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T18:27:39.197Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/collections/all', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/collections/all', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Products – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/collections/all', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/collections/all', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['collection_viewed'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/collections/all', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/collections/all', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Products – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/collections/all', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/collections/all', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'Products – pixel-testing-rs', - url: 'https://store.myshopify.com/collections/all', - path: '/collections/all', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'collection_viewed', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Product List Viewed', - properties: { - cart_id: 'c7b3f99b-4d34-463b-835f-c879482a7750', - list_id: 'sh-f6f0c6be-43F8-47D2-5F94-C22AD5ED3E79', - products: [ - { - price: 10, - product: { - title: 'Gift Card', - vendor: 'Snowboard Vendor', - id: '7234590605425', - untranslatedTitle: 'Gift Card', - url: '/products/gift-card', - type: 'giftcard', - }, - id: '41327142895729', - image: { - src: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', - }, - sku: '', - title: '$10', - untranslatedTitle: '$10', - image_url: - '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', - product_id: '7234590605425', - variant: 'Gift Card', - category: 'giftcard', - url: '/products/gift-card', - brand: 'Snowboard Vendor', - name: '$10', - }, - { - price: 24.95, - product: { - title: 'Selling Plans Ski Wax', - vendor: 'pixel-testing-rs', - id: '7234590802033', - untranslatedTitle: 'Selling Plans Ski Wax', - url: '/products/selling-plans-ski-wax', - type: 'accessories', - }, - id: '41327143223409', - image: { - src: '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', - }, - sku: '', - title: 'Selling Plans Ski Wax', - untranslatedTitle: 'Selling Plans Ski Wax', - image_url: - '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', - product_id: '7234590802033', - variant: 'Selling Plans Ski Wax', - category: 'accessories', - url: '/products/selling-plans-ski-wax', - brand: 'pixel-testing-rs', - name: 'Selling Plans Ski Wax', - }, - { - price: 2629.95, - product: { - title: 'The 3p Fulfilled Snowboard', - vendor: 'pixel-testing-rs', - id: '7234590703729', - untranslatedTitle: 'The 3p Fulfilled Snowboard', - url: '/products/the-3p-fulfilled-snowboard', - type: 'snowboard', - }, - id: '41327143125105', - image: { - src: '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', - }, - sku: 'sku-hosted-1', - title: 'Default Title', - untranslatedTitle: 'Default Title', - image_url: - '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', - product_id: '7234590703729', - variant: 'The 3p Fulfilled Snowboard', - category: 'snowboard', - url: '/products/the-3p-fulfilled-snowboard', - brand: 'pixel-testing-rs', - name: 'Default Title', - }, - ], - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> product_added_to_cart event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f6f828db-F77B-43E8-96C4-1D51DACD52A3', - name: 'product_added_to_cart', - data: { - cartLine: { - cost: { - totalAmount: { - amount: 749.95, - currencyCode: 'USD', - }, - }, - merchandise: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid?variant=41327143321713', - }, - sku: '', - title: null, - untranslatedTitle: null, - }, - quantity: 1, - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T18:34:42.625Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/products/the-collection-snowboard-liquid', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/collections/all', - characterSet: 'UTF-8', - title: 'The Collection Snowboard: Liquid – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/products/the-collection-snowboard-liquid', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['carts_update'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/products/the-collection-snowboard-liquid', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/collections/all', - characterSet: 'UTF-8', - title: 'The Collection Snowboard: Liquid – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/products/the-collection-snowboard-liquid', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'The Collection Snowboard: Liquid – pixel-testing-rs', - url: 'https://store.myshopify.com/products/the-collection-snowboard-liquid', - path: '/products/the-collection-snowboard-liquid', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'product_added_to_cart', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Product Added', - properties: { - cartLine: { - cost: { - totalAmount: { - amount: 749.95, - currencyCode: 'USD', - }, - }, - merchandise: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid?variant=41327143321713', - }, - sku: '', - title: null, - untranslatedTitle: null, - }, - quantity: 1, - }, - image_url: - 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', - price: 749.95, - product_id: '7234590834801', - variant: 'The Collection Snowboard: Liquid', - category: 'snowboard', - brand: 'Hydrogen Vendor', - url: '/products/the-collection-snowboard-liquid?variant=41327143321713', - sku: '', - name: null, - quantity: 1, - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> product_removed_from_cart event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'shu-f778d1eb-9B83-4832-9DC0-5C3B33A809F0', - name: 'product_removed_from_cart', - data: { - cartLine: { - cost: { - totalAmount: { - amount: 749.95, - currencyCode: 'USD', - }, - }, - merchandise: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid?variant=41327143321713', - }, - sku: '', - title: null, - untranslatedTitle: null, - }, - quantity: 1, - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T20:56:00.125Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/cart', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/cart', - port: '', - protocol: 'https:', - search: '', - }, - referrer: '', - characterSet: 'UTF-8', - title: 'Your Shopping Cart – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/cart', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/cart', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['carts_update'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/cart', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/cart', - port: '', - protocol: 'https:', - search: '', - }, - referrer: '', - characterSet: 'UTF-8', - title: 'Your Shopping Cart – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/cart', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/cart', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'Your Shopping Cart – pixel-testing-rs', - url: 'https://store.myshopify.com/cart', - path: '/cart', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'product_removed_from_cart', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Product Removed', - properties: { - cartLine: { - cost: { - totalAmount: { - amount: 749.95, - currencyCode: 'USD', - }, - }, - merchandise: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid?variant=41327143321713', - }, - sku: '', - title: null, - untranslatedTitle: null, - }, - quantity: 1, - }, - image_url: - 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', - price: 749.95, - product_id: '7234590834801', - variant: 'The Collection Snowboard: Liquid', - category: 'snowboard', - brand: 'Hydrogen Vendor', - url: '/products/the-collection-snowboard-liquid?variant=41327143321713', - sku: '', - name: null, - quantity: 1, - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> checkout_started event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', - name: 'checkout_started', - data: { - checkout: { - buyerAcceptsEmailMarketing: false, - buyerAcceptsSmsMarketing: false, - attributes: [], - billingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - token: '5f7028e0bd5225c17b24bdaa0c09f914', - currencyCode: 'USD', - discountApplications: [], - discountsAmount: { - amount: 0, - currencyCode: 'USD', - }, - email: '', - phone: '', - lineItems: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - }, - sku: null, - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: { - id: '41327143157873', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - }, - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - id: '7234590736497', - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - type: 'snowboard', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - }, - sku: 'sku-managed-1', - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - ], - localization: { - country: { - isoCode: 'US', - }, - language: { - isoCode: 'en-US', - }, - market: { - id: 'gid://shopify/Market/23505895537', - handle: 'us', - }, - }, - order: { - id: null, - customer: { - id: null, - isFirstOrder: null, - }, - }, - delivery: { - selectedDeliveryOptions: [], - }, - shippingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - subtotalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - shippingLine: { - price: { - amount: 0, - currencyCode: 'USD', - }, - }, - smsMarketingPhone: null, - totalTax: { - amount: 0, - currencyCode: 'USD', - }, - totalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - transactions: [], - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T20:57:59.674Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['checkouts_update'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'Checkout - pixel-testing-rs', - url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'checkout_started', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Checkout Started', - properties: { - products: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: 'The Collection Snowboard: Liquid', - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - name: 'The Collection Snowboard: Liquid', - image_url: - 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - price: 749.95, - sku: null, - product_id: '7234590834801', - category: 'snowboard', - url: '/products/the-collection-snowboard-liquid', - brand: 'Hydrogen Vendor', - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: 'The Multi-managed Snowboard', - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - name: 'The Multi-managed Snowboard', - image_url: - 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - price: 629.95, - sku: 'sku-managed-1', - product_id: '7234590736497', - category: 'snowboard', - url: '/products/the-multi-managed-snowboard', - brand: 'Multi-managed Vendor', - }, - ], - order_id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', - checkout_id: '5f7028e0bd5225c17b24bdaa0c09f914', - total: 2759.8, - currency: 'USD', - discount: 0, - shipping: 0, - revenue: 2759.8, - value: 2759.8, - tax: 0, - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> address_info_submitted event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f7d2154d-7525-47A4-87FA-E54D2322E129', - name: 'checkout_address_info_submitted', - data: { - checkout: { - buyerAcceptsEmailMarketing: false, - buyerAcceptsSmsMarketing: false, - attributes: [], - billingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - token: '5f7028e0bd5225c17b24bdaa0c09f914', - currencyCode: 'USD', - discountApplications: [], - discountsAmount: { - amount: 0, - currencyCode: 'USD', - }, - email: 'test-user@sampleemail.com', - phone: '', - lineItems: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - }, - sku: null, - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: { - id: '41327143157873', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - }, - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - id: '7234590736497', - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - type: 'snowboard', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - }, - sku: 'sku-managed-1', - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - ], - localization: { - country: { - isoCode: 'US', - }, - language: { - isoCode: 'en-US', - }, - market: { - id: 'gid://shopify/Market/23505895537', - handle: 'us', - }, - }, - order: { - id: null, - customer: { - id: null, - isFirstOrder: null, - }, - }, - delivery: { - selectedDeliveryOptions: [ - { - cost: { - amount: 0, - currencyCode: 'USD', - }, - costAfterDiscounts: { - amount: 0, - currencyCode: 'USD', - }, - description: null, - handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', - title: 'Economy', - type: 'shipping', - }, - ], - }, - shippingAddress: { - address1: 'Queens Center', - address2: null, - city: 'Elmhurst', - country: 'US', - countryCode: 'US', - firstName: 'test', - lastName: 'user', - phone: null, - province: 'NY', - provinceCode: 'NY', - zip: '11373', - }, - subtotalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - shippingLine: { - price: { - amount: 0, - currencyCode: 'USD', - }, - }, - smsMarketingPhone: null, - totalTax: { - amount: 0, - currencyCode: 'USD', - }, - totalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - transactions: [], - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T21:45:50.523Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['checkouts_update'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'Checkout - pixel-testing-rs', - url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'checkout_address_info_submitted', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Checkout Address Info Submitted', - properties: { - buyerAcceptsEmailMarketing: false, - buyerAcceptsSmsMarketing: false, - attributes: [], - billingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - token: '5f7028e0bd5225c17b24bdaa0c09f914', - currencyCode: 'USD', - discountApplications: [], - discountsAmount: { - amount: 0, - currencyCode: 'USD', - }, - email: 'test-user@sampleemail.com', - phone: '', - lineItems: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - }, - sku: null, - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: { - id: '41327143157873', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - }, - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - id: '7234590736497', - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - type: 'snowboard', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - }, - sku: 'sku-managed-1', - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - ], - localization: { - country: { - isoCode: 'US', - }, - language: { - isoCode: 'en-US', - }, - market: { - id: 'gid://shopify/Market/23505895537', - handle: 'us', - }, - }, - order: { - id: null, - customer: { - id: null, - isFirstOrder: null, - }, - }, - delivery: { - selectedDeliveryOptions: [ - { - cost: { - amount: 0, - currencyCode: 'USD', - }, - costAfterDiscounts: { - amount: 0, - currencyCode: 'USD', - }, - description: null, - handle: - '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', - title: 'Economy', - type: 'shipping', - }, - ], - }, - shippingAddress: { - address1: 'Queens Center', - address2: null, - city: 'Elmhurst', - country: 'US', - countryCode: 'US', - firstName: 'test', - lastName: 'user', - phone: null, - province: 'NY', - provinceCode: 'NY', - zip: '11373', - }, - subtotalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - shippingLine: { - price: { - amount: 0, - currencyCode: 'USD', - }, - }, - smsMarketingPhone: null, - totalTax: { - amount: 0, - currencyCode: 'USD', - }, - totalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - transactions: [], - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> contact_info_submitted event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f7c8416f-1D35-4304-EF29-78666678C4E9', - name: 'checkout_contact_info_submitted', - data: { - checkout: { - buyerAcceptsEmailMarketing: false, - buyerAcceptsSmsMarketing: false, - attributes: [], - billingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - token: '5f7028e0bd5225c17b24bdaa0c09f914', - currencyCode: 'USD', - discountApplications: [], - discountsAmount: { - amount: 0, - currencyCode: 'USD', - }, - email: 'test-user@sampleemail.com', - phone: '', - lineItems: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - }, - sku: null, - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: { - id: '41327143157873', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - }, - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - id: '7234590736497', - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - type: 'snowboard', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - }, - sku: 'sku-managed-1', - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - ], - localization: { - country: { - isoCode: 'US', - }, - language: { - isoCode: 'en-US', - }, - market: { - id: 'gid://shopify/Market/23505895537', - handle: 'us', - }, - }, - order: { - id: null, - customer: { - id: null, - isFirstOrder: null, - }, - }, - delivery: { - selectedDeliveryOptions: [], - }, - shippingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - subtotalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - shippingLine: { - price: { - amount: 0, - currencyCode: 'USD', - }, - }, - smsMarketingPhone: null, - totalTax: { - amount: 0, - currencyCode: 'USD', - }, - totalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - transactions: [], - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T21:40:28.498Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['checkouts_update'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'Checkout - pixel-testing-rs', - url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'checkout_contact_info_submitted', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Checkout Contact Info Submitted', - properties: { - buyerAcceptsEmailMarketing: false, - buyerAcceptsSmsMarketing: false, - attributes: [], - billingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - token: '5f7028e0bd5225c17b24bdaa0c09f914', - currencyCode: 'USD', - discountApplications: [], - discountsAmount: { - amount: 0, - currencyCode: 'USD', - }, - email: 'test-user@sampleemail.com', - phone: '', - lineItems: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - }, - sku: null, - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: { - id: '41327143157873', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - }, - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - id: '7234590736497', - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - type: 'snowboard', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - }, - sku: 'sku-managed-1', - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - ], - localization: { - country: { - isoCode: 'US', - }, - language: { - isoCode: 'en-US', - }, - market: { - id: 'gid://shopify/Market/23505895537', - handle: 'us', - }, - }, - order: { - id: null, - customer: { - id: null, - isFirstOrder: null, - }, - }, - delivery: { - selectedDeliveryOptions: [], - }, - shippingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - subtotalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - shippingLine: { - price: { - amount: 0, - currencyCode: 'USD', - }, - }, - smsMarketingPhone: null, - totalTax: { - amount: 0, - currencyCode: 'USD', - }, - totalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - transactions: [], - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> shipping_info_submitted event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f7d5618e-404A-4E6D-4662-599A4BCC9E7C', - name: 'checkout_shipping_info_submitted', - data: { - checkout: { - buyerAcceptsEmailMarketing: false, - buyerAcceptsSmsMarketing: false, - attributes: [], - billingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - token: '5f7028e0bd5225c17b24bdaa0c09f914', - currencyCode: 'USD', - discountApplications: [], - discountsAmount: { - amount: 0, - currencyCode: 'USD', - }, - email: 'test-user@sampleemail.com', - phone: '', - lineItems: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - }, - sku: null, - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: { - id: '41327143157873', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - }, - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - id: '7234590736497', - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - type: 'snowboard', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - }, - sku: 'sku-managed-1', - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - ], - localization: { - country: { - isoCode: 'US', - }, - language: { - isoCode: 'en-US', - }, - market: { - id: 'gid://shopify/Market/23505895537', - handle: 'us', - }, - }, - order: { - id: null, - customer: { - id: null, - isFirstOrder: null, - }, - }, - delivery: { - selectedDeliveryOptions: [ - { - cost: { - amount: 0, - currencyCode: 'USD', - }, - costAfterDiscounts: { - amount: 0, - currencyCode: 'USD', - }, - description: null, - handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', - title: 'Economy', - type: 'shipping', - }, - ], - }, - shippingAddress: { - address1: 'Queens Center', - address2: null, - city: 'Elmhurst', - country: 'US', - countryCode: 'US', - firstName: 'test', - lastName: 'user', - phone: null, - province: 'NY', - provinceCode: 'NY', - zip: '11373', - }, - subtotalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - shippingLine: { - price: { - amount: 0, - currencyCode: 'USD', - }, - }, - smsMarketingPhone: null, - totalTax: { - amount: 0, - currencyCode: 'USD', - }, - totalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - transactions: [], - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T21:47:38.576Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 433, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 433, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['checkouts_update'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 433, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 433, - }, - page: { - title: 'Checkout - pixel-testing-rs', - url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'checkout_shipping_info_submitted', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Checkout Shipping Info Submitted', - properties: { - buyerAcceptsEmailMarketing: false, - buyerAcceptsSmsMarketing: false, - attributes: [], - billingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - token: '5f7028e0bd5225c17b24bdaa0c09f914', - currencyCode: 'USD', - discountApplications: [], - discountsAmount: { - amount: 0, - currencyCode: 'USD', - }, - email: 'test-user@sampleemail.com', - phone: '', - lineItems: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - }, - sku: null, - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: { - id: '41327143157873', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - }, - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - id: '7234590736497', - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - type: 'snowboard', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - }, - sku: 'sku-managed-1', - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - ], - localization: { - country: { - isoCode: 'US', - }, - language: { - isoCode: 'en-US', - }, - market: { - id: 'gid://shopify/Market/23505895537', - handle: 'us', - }, - }, - order: { - id: null, - customer: { - id: null, - isFirstOrder: null, - }, - }, - delivery: { - selectedDeliveryOptions: [ - { - cost: { - amount: 0, - currencyCode: 'USD', - }, - costAfterDiscounts: { - amount: 0, - currencyCode: 'USD', - }, - description: null, - handle: - '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', - title: 'Economy', - type: 'shipping', - }, - ], - }, - shippingAddress: { - address1: 'Queens Center', - address2: null, - city: 'Elmhurst', - country: 'US', - countryCode: 'US', - firstName: 'test', - lastName: 'user', - phone: null, - province: 'NY', - provinceCode: 'NY', - zip: '11373', - }, - subtotalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - shippingLine: { - price: { - amount: 0, - currencyCode: 'USD', - }, - }, - smsMarketingPhone: null, - totalTax: { - amount: 0, - currencyCode: 'USD', - }, - totalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - transactions: [], - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> payment_info_submitted event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f7d843ea-ED11-4A12-F32F-C5A45BED0413', - name: 'payment_info_submitted', - data: { - checkout: { - buyerAcceptsEmailMarketing: false, - buyerAcceptsSmsMarketing: false, - attributes: [], - billingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - token: '5f7028e0bd5225c17b24bdaa0c09f914', - currencyCode: 'USD', - discountApplications: [], - discountsAmount: { - amount: 0, - currencyCode: 'USD', - }, - email: 'test-user@sampleemail.com', - phone: '', - lineItems: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - }, - sku: null, - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: { - id: '41327143157873', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - }, - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - id: '7234590736497', - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - type: 'snowboard', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - }, - sku: 'sku-managed-1', - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - ], - localization: { - country: { - isoCode: 'US', - }, - language: { - isoCode: 'en-US', - }, - market: { - id: 'gid://shopify/Market/23505895537', - handle: 'us', - }, - }, - order: { - id: null, - customer: { - id: null, - isFirstOrder: null, - }, - }, - delivery: { - selectedDeliveryOptions: [ - { - cost: { - amount: 0, - currencyCode: 'USD', - }, - costAfterDiscounts: { - amount: 0, - currencyCode: 'USD', - }, - description: null, - handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', - title: 'Economy', - type: 'shipping', - }, - ], - }, - shippingAddress: { - address1: 'Queens Center', - address2: null, - city: 'Elmhurst', - country: 'US', - countryCode: 'US', - firstName: 'test', - lastName: 'user', - phone: null, - province: 'NY', - provinceCode: 'NY', - zip: '11373', - }, - subtotalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - shippingLine: { - price: { - amount: 0, - currencyCode: 'USD', - }, - }, - smsMarketingPhone: null, - totalTax: { - amount: 0, - currencyCode: 'USD', - }, - totalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - transactions: [], - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T21:49:13.092Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['checkouts_update'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'Checkout - pixel-testing-rs', - url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', - path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU/processing', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'payment_info_submitted', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Payment Info Submitted', - properties: { - buyerAcceptsEmailMarketing: false, - buyerAcceptsSmsMarketing: false, - attributes: [], - billingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - token: '5f7028e0bd5225c17b24bdaa0c09f914', - currencyCode: 'USD', - discountApplications: [], - discountsAmount: { - amount: 0, - currencyCode: 'USD', - }, - email: 'test-user@sampleemail.com', - phone: '', - lineItems: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - }, - sku: null, - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: { - id: '41327143157873', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - }, - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - id: '7234590736497', - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - type: 'snowboard', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - }, - sku: 'sku-managed-1', - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - ], - localization: { - country: { - isoCode: 'US', - }, - language: { - isoCode: 'en-US', - }, - market: { - id: 'gid://shopify/Market/23505895537', - handle: 'us', - }, - }, - order: { - id: null, - customer: { - id: null, - isFirstOrder: null, - }, - }, - delivery: { - selectedDeliveryOptions: [ - { - cost: { - amount: 0, - currencyCode: 'USD', - }, - costAfterDiscounts: { - amount: 0, - currencyCode: 'USD', - }, - description: null, - handle: - '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', - title: 'Economy', - type: 'shipping', - }, - ], - }, - shippingAddress: { - address1: 'Queens Center', - address2: null, - city: 'Elmhurst', - country: 'US', - countryCode: 'US', - firstName: 'test', - lastName: 'user', - phone: null, - province: 'NY', - provinceCode: 'NY', - zip: '11373', - }, - subtotalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - shippingLine: { - price: { - amount: 0, - currencyCode: 'USD', - }, - }, - smsMarketingPhone: null, - totalTax: { - amount: 0, - currencyCode: 'USD', - }, - totalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - transactions: [], - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> checkout_completed event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', - name: 'checkout_completed', - data: { - checkout: { - buyerAcceptsEmailMarketing: false, - buyerAcceptsSmsMarketing: false, - attributes: [], - billingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - token: '5f7028e0bd5225c17b24bdaa0c09f914', - currencyCode: 'USD', - discountApplications: [], - discountsAmount: { - amount: 0, - currencyCode: 'USD', - }, - email: '', - phone: '', - lineItems: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: { - id: '41327143321713', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - }, - price: { - amount: 749.95, - currencyCode: 'USD', - }, - product: { - id: '7234590834801', - title: 'The Collection Snowboard: Liquid', - vendor: 'Hydrogen Vendor', - type: 'snowboard', - untranslatedTitle: 'The Collection Snowboard: Liquid', - url: '/products/the-collection-snowboard-liquid', - }, - sku: null, - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: { - id: '41327143157873', - image: { - src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - }, - price: { - amount: 629.95, - currencyCode: 'USD', - }, - product: { - id: '7234590736497', - title: 'The Multi-managed Snowboard', - vendor: 'Multi-managed Vendor', - type: 'snowboard', - untranslatedTitle: 'The Multi-managed Snowboard', - url: '/products/the-multi-managed-snowboard', - }, - sku: 'sku-managed-1', - title: null, - untranslatedTitle: null, - }, - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - }, - ], - localization: { - country: { - isoCode: 'US', - }, - language: { - isoCode: 'en-US', - }, - market: { - id: 'gid://shopify/Market/23505895537', - handle: 'us', - }, - }, - order: { - id: null, - customer: { - id: null, - isFirstOrder: null, - }, - }, - delivery: { - selectedDeliveryOptions: [], - }, - shippingAddress: { - address1: null, - address2: null, - city: null, - country: 'US', - countryCode: 'US', - firstName: null, - lastName: null, - phone: null, - province: null, - provinceCode: null, - zip: null, - }, - subtotalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - shippingLine: { - price: { - amount: 0, - currencyCode: 'USD', - }, - }, - smsMarketingPhone: null, - totalTax: { - amount: 0, - currencyCode: 'USD', - }, - totalPrice: { - amount: 2759.8, - currencyCode: 'USD', - }, - transactions: [], - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T20:57:59.674Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['checkouts_update'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - referrer: 'https://store.myshopify.com/cart', - characterSet: 'UTF-8', - title: 'Checkout - pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: - '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - port: '', - protocol: 'https:', - search: '', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'Checkout - pixel-testing-rs', - url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', - search: '', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'checkout_completed', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Checkout Completed', - properties: { - products: [ - { - discountAllocations: [], - id: '41327143321713', - quantity: 2, - title: 'The Collection Snowboard: Liquid', - variant: 'The Collection Snowboard: Liquid', - finalLinePrice: { - amount: 1499.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - name: 'The Collection Snowboard: Liquid', - image_url: - 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', - price: 749.95, - sku: null, - product_id: '7234590834801', - category: 'snowboard', - url: '/products/the-collection-snowboard-liquid', - brand: 'Hydrogen Vendor', - }, - { - discountAllocations: [], - id: '41327143157873', - quantity: 2, - title: 'The Multi-managed Snowboard', - variant: 'The Multi-managed Snowboard', - finalLinePrice: { - amount: 1259.9, - currencyCode: 'USD', - }, - sellingPlanAllocation: null, - properties: [], - name: 'The Multi-managed Snowboard', - image_url: - 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', - price: 629.95, - sku: 'sku-managed-1', - product_id: '7234590736497', - category: 'snowboard', - url: '/products/the-multi-managed-snowboard', - brand: 'Multi-managed Vendor', - }, - ], - order_id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', - checkout_id: '5f7028e0bd5225c17b24bdaa0c09f914', - total: 2759.8, - currency: 'USD', - discount: 0, - shipping: 0, - revenue: 2759.8, - value: 2759.8, - tax: 0, - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> search_submitted event from web pixel', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f7d599b4-D80F-4D05-C4CE-B980D5444596', - name: 'search_submitted', - data: { - searchResult: { - query: 'skate', - productVariants: [], - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T22:37:35.869Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/search', - port: '', - protocol: 'https:', - search: '?q=skate&options%5Bprefix%5D=last', - }, - referrer: 'https://store.myshopify.com/', - characterSet: 'UTF-8', - title: 'Search: 0 results found for "skate" – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/search', - port: '', - protocol: 'https:', - search: '?q=skate&options%5Bprefix%5D=last', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['search_submitted'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - document: { - location: { - href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/search', - port: '', - protocol: 'https:', - search: '?q=skate&options%5Bprefix%5D=last', - }, - referrer: 'https://store.myshopify.com/', - characterSet: 'UTF-8', - title: 'Search: 0 results found for "skate" – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/search', - port: '', - protocol: 'https:', - search: '?q=skate&options%5Bprefix%5D=last', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - page: { - title: 'Search: 0 results found for "skate" – pixel-testing-rs', - url: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', - path: '/search', - search: '?q=skate&options%5Bprefix%5D=last', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - screen: { - height: 1117, - width: 1728, - }, - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'client', - version: '2.0.0', - }, - topic: 'search_submitted', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Search Submitted', - properties: { - query: 'skate', - }, - anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - }, - ], - }, - }, - ], - }, - }, - }, - { - name: 'shopify', - description: 'Track Call -> unknown event from web pixel, should not be sent to Shopify', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'sh-f7d599b4-D80F-4D05-C4CE-B980D5444596', - name: 'unknown_event', - data: { - searchResult: { - query: 'skate', - productVariants: [], - }, - }, - type: 'standard', - clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', - timestamp: '2024-09-15T22:37:35.869Z', - context: { - document: { - location: { - href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/search', - port: '', - protocol: 'https:', - search: '?q=skate&options%5Bprefix%5D=last', - }, - referrer: 'https://store.myshopify.com/', - characterSet: 'UTF-8', - title: 'Search: 0 results found for "skate" – pixel-testing-rs', - }, - navigator: { - language: 'en-US', - cookieEnabled: true, - languages: ['en-US', 'en'], - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', - }, - window: { - innerHeight: 1028, - innerWidth: 1362, - outerHeight: 1080, - outerWidth: 1728, - pageXOffset: 0, - pageYOffset: 0, - location: { - href: 'https://store.myshopify.com/search?q=skate&options%5Bprefix%5D=last', - hash: '', - host: 'store.myshopify.com', - hostname: 'store.myshopify.com', - origin: 'https://store.myshopify.com', - pathname: '/search', - port: '', - protocol: 'https:', - search: '?q=skate&options%5Bprefix%5D=last', - }, - origin: 'https://store.myshopify.com', - screen: { - height: 1117, - width: 1728, - }, - screenX: 0, - screenY: 37, - scrollX: 0, - scrollY: 0, - }, - }, - pixelEventLabel: true, - query_parameters: { - topic: ['search_submitted'], - writeKey: ['dummy-write-key'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - outputToSource: { - body: 'T0s=', - contentType: 'text/plain', - }, - statusCode: 200, - }, - ], - }, - }, - }, -]; +import { pixelCheckoutEventsTestScenarios } from './pixelTestScenarios/CheckoutEventsTests'; +import { pixelCheckoutStepsScenarios } from './pixelTestScenarios/CheckoutStepsTests'; +import { pixelEventsTestScenarios } from './pixelTestScenarios/ProductEventsTests'; +import { v1ServerSideEventsScenarios } from './v1ServerSideEventsTests'; const serverSideEventsScenarios = [ { @@ -5203,598 +612,9 @@ const serverSideEventsScenarios = [ }, ]; -const v1ServerSideEventsScenarios = [ - { - name: 'shopify', - description: 'Track Call -> Checkout Updated event', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 35374569160817, - token: 'e89d4437003b6b8480f8bc7f8036a659', - cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - email: 'AJAIKUMARBAJPAI1962@GMAIL.COM', - gateway: null, - buyer_accepts_marketing: false, - buyer_accepts_sms_marketing: false, - sms_marketing_phone: null, - created_at: '2024-09-16T03:50:15+00:00', - updated_at: '2024-09-17T03:29:02-04:00', - landing_site: '/', - note: '', - note_attributes: [], - referring_site: '', - shipping_lines: [ - { - code: 'Standard', - price: '6.90', - original_shop_price: '6.90', - original_shop_markup: '0.00', - source: 'shopify', - title: 'Standard', - presentment_title: 'Standard', - phone: null, - tax_lines: [], - custom_tax_lines: null, - markup: '0.00', - carrier_identifier: null, - carrier_service_id: null, - api_client_id: '580111', - delivery_option_group: { - token: '26492692a443ee35c30eb82073bacaa8', - type: 'one_time_purchase', - }, - delivery_expectation_range: null, - delivery_expectation_type: null, - id: null, - requested_fulfillment_service_id: null, - delivery_category: null, - validation_context: null, - applied_discounts: [], - }, - ], - shipping_address: { - first_name: 'Yashasvi', - address1: '103 Block B', - phone: null, - city: 'Kanpur', - zip: '85003', - province: 'Arizona', - country: 'United States', - last_name: 'Bajpai', - address2: 'Shyam Nagar', - company: null, - latitude: null, - longitude: null, - name: 'Yashasvi Bajpai', - country_code: 'US', - province_code: 'AZ', - }, - taxes_included: false, - total_weight: 0, - currency: 'USD', - completed_at: null, - phone: null, - customer_locale: 'en-US', - line_items: [ - { - key: '41327143059569', - fulfillment_service: 'manual', - gift_card: false, - grams: 0, - presentment_title: 'The Multi-location Snowboard', - presentment_variant_title: '', - product_id: 7234590638193, - quantity: 1, - requires_shipping: true, - sku: '', - tax_lines: [], - taxable: true, - title: 'The Multi-location Snowboard', - variant_id: 41327143059569, - variant_title: '', - variant_price: '729.95', - vendor: 'pixel-testing-rs', - unit_price_measurement: { - measured_type: null, - quantity_value: null, - quantity_unit: null, - reference_value: null, - reference_unit: null, - }, - compare_at_price: null, - line_price: '729.95', - price: '729.95', - applied_discounts: [], - destination_location_id: null, - user_id: null, - rank: null, - origin_location_id: null, - properties: {}, - }, - ], - name: '#35374569160817', - abandoned_checkout_url: - 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', - discount_codes: [], - tax_lines: [], - presentment_currency: 'USD', - source_name: 'web', - total_line_items_price: '729.95', - total_tax: '0.00', - total_discounts: '0.00', - subtotal_price: '729.95', - total_price: '736.85', - total_duties: '0.00', - device_id: null, - user_id: null, - location_id: null, - source_identifier: null, - source_url: null, - source: null, - closed_at: null, - customer: { - id: 7188389789809, - email: 'ajaikumarbajpai1962@gmail.com', - accepts_marketing: false, - created_at: null, - updated_at: null, - first_name: 'Yashasvi', - last_name: 'Bajpai', - orders_count: 0, - state: 'disabled', - total_spent: '0.00', - last_order_id: null, - note: null, - verified_email: true, - multipass_identifier: null, - tax_exempt: false, - phone: null, - tags: '', - currency: 'USD', - accepts_marketing_updated_at: null, - admin_graphql_api_id: 'gid://shopify/Customer/7188389789809', - default_address: { - id: null, - customer_id: 7188389789809, - first_name: 'Yashasvi', - last_name: 'Bajpai', - company: null, - address1: '103 Block B', - address2: 'Shyam Nagar', - city: 'Kanpur', - province: 'Arizona', - country: 'United States', - zip: '85003', - phone: null, - name: 'Yashasvi Bajpai', - province_code: 'AZ', - country_code: 'US', - country_name: 'United States', - default: true, - }, - last_order_name: null, - marketing_opt_in_level: null, - }, - query_parameters: { - topic: ['checkouts_update'], - writeKey: ['2l9QoM7KRMJLMcYhXNUVDT0Mqbd'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'server', - version: '2.0.0', - }, - integration: { - name: 'SHOPIFY', - }, - topic: 'checkouts_update', - cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Checkout Updated', - properties: { - order_id: 35374569160817, - value: '736.85', - tax: '0.00', - currency: 'USD', - token: 'e89d4437003b6b8480f8bc7f8036a659', - cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - email: 'AJAIKUMARBAJPAI1962@GMAIL.COM', - buyer_accepts_marketing: false, - buyer_accepts_sms_marketing: false, - created_at: '2024-09-16T03:50:15+00:00', - updated_at: '2024-09-17T03:29:02-04:00', - landing_site: '/', - note: '', - note_attributes: [], - referring_site: '', - shipping_lines: [ - { - code: 'Standard', - price: '6.90', - original_shop_price: '6.90', - original_shop_markup: '0.00', - source: 'shopify', - title: 'Standard', - presentment_title: 'Standard', - phone: null, - tax_lines: [], - custom_tax_lines: null, - markup: '0.00', - carrier_identifier: null, - carrier_service_id: null, - api_client_id: '580111', - delivery_option_group: { - token: '26492692a443ee35c30eb82073bacaa8', - type: 'one_time_purchase', - }, - delivery_expectation_range: null, - delivery_expectation_type: null, - id: null, - requested_fulfillment_service_id: null, - delivery_category: null, - validation_context: null, - applied_discounts: [], - }, - ], - taxes_included: false, - total_weight: 0, - customer_locale: 'en-US', - name: '#35374569160817', - abandoned_checkout_url: - 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', - discount_codes: [], - tax_lines: [], - presentment_currency: 'USD', - source_name: 'web', - total_line_items_price: '729.95', - total_discounts: '0.00', - subtotal_price: '729.95', - total_duties: '0.00', - products: [ - { - product_id: 7234590638193, - price: '729.95', - brand: 'pixel-testing-rs', - quantity: 1, - key: '41327143059569', - fulfillment_service: 'manual', - gift_card: false, - grams: 0, - presentment_title: 'The Multi-location Snowboard', - presentment_variant_title: '', - requires_shipping: true, - tax_lines: [], - taxable: true, - title: 'The Multi-location Snowboard', - unit_price_measurement: { - measured_type: null, - quantity_value: null, - quantity_unit: null, - reference_value: null, - reference_unit: null, - }, - compare_at_price: null, - line_price: '729.95', - applied_discounts: [], - destination_location_id: null, - user_id: null, - rank: null, - origin_location_id: null, - properties: {}, - variant: '41327143059569 729.95 ', - }, - ], - }, - userId: '7188389789809', - traits: { - email: 'ajaikumarbajpai1962@gmail.com', - firstName: 'Yashasvi', - lastName: 'Bajpai', - address: { - id: null, - customer_id: 7188389789809, - first_name: 'Yashasvi', - last_name: 'Bajpai', - company: null, - address1: '103 Block B', - address2: 'Shyam Nagar', - city: 'Kanpur', - province: 'Arizona', - country: 'United States', - zip: '85003', - phone: null, - name: 'Yashasvi Bajpai', - province_code: 'AZ', - country_code: 'US', - country_name: 'United States', - default: true, - }, - acceptsMarketing: false, - orderCount: 0, - state: 'disabled', - totalSpent: '0.00', - verifiedEmail: true, - taxExempt: false, - tags: '', - currency: 'USD', - adminGraphqlApiId: 'gid://shopify/Customer/7188389789809', - shippingAddress: { - first_name: 'Yashasvi', - address1: '103 Block B', - phone: null, - city: 'Kanpur', - zip: '85003', - province: 'Arizona', - country: 'United States', - last_name: 'Bajpai', - address2: 'Shyam Nagar', - company: null, - latitude: null, - longitude: null, - name: 'Yashasvi Bajpai', - country_code: 'US', - province_code: 'AZ', - }, - }, - timestamp: '2024-09-17T07:29:02.000Z', - anonymousId: '97fcd7b2-cc24-47d7-b776-057b7b199513', - }, - ], - }, - }, - ], - }, - }, - mockFns: () => { - defaultMockFns(); - }, - }, - { - name: 'shopify', - description: 'Track Call -> Cart Update event', - module: 'source', - version: 'v1', - input: { - request: { - body: [ - { - event: { - id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - line_items: [ - { - id: 41327143059569, - properties: null, - quantity: 3, - variant_id: 41327143059569, - key: '41327143059569:90562f18109e0e6484b0c297e7981b30', - discounted_price: '729.95', - discounts: [], - gift_card: false, - grams: 0, - line_price: '2189.85', - original_line_price: '2189.85', - original_price: '729.95', - price: '729.95', - product_id: 7234590638193, - sku: '', - taxable: true, - title: 'The Multi-location Snowboard', - total_discount: '0.00', - vendor: 'pixel-testing-rs', - discounted_price_set: { - shop_money: { - amount: '729.95', - currency_code: 'USD', - }, - presentment_money: { - amount: '729.95', - currency_code: 'USD', - }, - }, - line_price_set: { - shop_money: { - amount: '2189.85', - currency_code: 'USD', - }, - presentment_money: { - amount: '2189.85', - currency_code: 'USD', - }, - }, - original_line_price_set: { - shop_money: { - amount: '2189.85', - currency_code: 'USD', - }, - presentment_money: { - amount: '2189.85', - currency_code: 'USD', - }, - }, - price_set: { - shop_money: { - amount: '729.95', - currency_code: 'USD', - }, - presentment_money: { - amount: '729.95', - currency_code: 'USD', - }, - }, - total_discount_set: { - shop_money: { - amount: '0.0', - currency_code: 'USD', - }, - presentment_money: { - amount: '0.0', - currency_code: 'USD', - }, - }, - }, - ], - note: '', - updated_at: '2024-09-17T08:15:13.280Z', - created_at: '2024-09-16T03:50:15.478Z', - query_parameters: { - topic: ['carts_update'], - writeKey: ['2l9QoM7KRMJLMcYhXNUVDT0Mqbd'], - }, - }, - source: dummySourceConfig, - }, - ], - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }, - pathSuffix: '', - }, - output: { - response: { - status: 200, - body: [ - { - output: { - batch: [ - { - context: { - library: { - name: 'RudderStack Shopify Cloud', - eventOrigin: 'server', - version: '2.0.0', - }, - integration: { - name: 'SHOPIFY', - }, - topic: 'carts_update', - }, - integrations: { - SHOPIFY: true, - }, - type: 'track', - event: 'Cart Update', - properties: { - id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', - note: '', - updated_at: '2024-09-17T08:15:13.280Z', - created_at: '2024-09-16T03:50:15.478Z', - products: [ - { - product_id: 7234590638193, - price: '729.95', - brand: 'pixel-testing-rs', - quantity: 3, - id: 41327143059569, - properties: null, - key: '41327143059569:90562f18109e0e6484b0c297e7981b30', - discounted_price: '729.95', - discounts: [], - gift_card: false, - grams: 0, - line_price: '2189.85', - original_line_price: '2189.85', - original_price: '729.95', - taxable: true, - title: 'The Multi-location Snowboard', - total_discount: '0.00', - discounted_price_set: { - shop_money: { - amount: '729.95', - currency_code: 'USD', - }, - presentment_money: { - amount: '729.95', - currency_code: 'USD', - }, - }, - line_price_set: { - shop_money: { - amount: '2189.85', - currency_code: 'USD', - }, - presentment_money: { - amount: '2189.85', - currency_code: 'USD', - }, - }, - original_line_price_set: { - shop_money: { - amount: '2189.85', - currency_code: 'USD', - }, - presentment_money: { - amount: '2189.85', - currency_code: 'USD', - }, - }, - price_set: { - shop_money: { - amount: '729.95', - currency_code: 'USD', - }, - presentment_money: { - amount: '729.95', - currency_code: 'USD', - }, - }, - total_discount_set: { - shop_money: { - amount: '0.0', - currency_code: 'USD', - }, - presentment_money: { - amount: '0.0', - currency_code: 'USD', - }, - }, - variant: '41327143059569 ', - }, - ], - }, - anonymousId: '97fcd7b2-cc24-47d7-b776-057b7b199513', - }, - ], - }, - }, - ], - }, - }, - mockFns: () => { - defaultMockFns(); - }, - }, -]; - export const data = [ + ...pixelCheckoutEventsTestScenarios, + ...pixelCheckoutStepsScenarios, ...pixelEventsTestScenarios, ...serverSideEventsScenarios, ...v1ServerSideEventsScenarios, diff --git a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts new file mode 100644 index 0000000000..1009fa2d04 --- /dev/null +++ b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutEventsTests.ts @@ -0,0 +1,570 @@ +// This file contains the test scenarios for the pixel checkout events +import { dummySourceConfig, dummyBillingAddresses, dummyContext } from '../constants'; + +export const pixelCheckoutEventsTestScenarios = [ + { + name: 'shopify', + description: 'Track Call -> checkout_started event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + name: 'checkout_started', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: dummyBillingAddresses[0], + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: '', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: dummyBillingAddresses[0], + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T20:57:59.674Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', + version: '2.0.0', + }, + topic: 'checkout_started', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Started', + properties: { + products: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: 'The Collection Snowboard: Liquid', + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + name: 'The Collection Snowboard: Liquid', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + price: 749.95, + sku: null, + product_id: '7234590834801', + category: 'snowboard', + url: '/products/the-collection-snowboard-liquid', + brand: 'Hydrogen Vendor', + }, + ], + order_id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + checkout_id: '5f7028e0bd5225c17b24bdaa0c09f914', + total: 2759.8, + currency: 'USD', + discount: 0, + shipping: 0, + revenue: 2759.8, + value: 2759.8, + tax: 0, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> checkout_completed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + name: 'checkout_completed', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: dummyBillingAddresses[0], + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: '', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: dummyBillingAddresses[0], + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T20:57:59.674Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + document: { + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + referrer: 'https://store.myshopify.com/cart', + characterSet: 'UTF-8', + title: 'Checkout - pixel-testing-rs', + }, + navigator: { + language: 'en-US', + cookieEnabled: true, + languages: ['en-US', 'en'], + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + }, + window: { + innerHeight: 1028, + innerWidth: 1362, + outerHeight: 1080, + outerWidth: 1728, + pageXOffset: 0, + pageYOffset: 0, + location: { + href: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + hash: '', + host: 'store.myshopify.com', + hostname: 'store.myshopify.com', + origin: 'https://store.myshopify.com', + pathname: + '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + port: '', + protocol: 'https:', + search: '', + }, + origin: 'https://store.myshopify.com', + screen: { + height: 1117, + width: 1728, + }, + screenX: 0, + screenY: 37, + scrollX: 0, + scrollY: 0, + }, + page: { + title: 'Checkout - pixel-testing-rs', + url: 'https://store.myshopify.com/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + path: '/checkouts/cn/Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + search: '', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + screen: { + height: 1117, + width: 1728, + }, + library: { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'client', + version: '2.0.0', + }, + topic: 'checkout_completed', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Completed', + properties: { + products: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: 'The Collection Snowboard: Liquid', + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + name: 'The Collection Snowboard: Liquid', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + price: 749.95, + sku: null, + product_id: '7234590834801', + category: 'snowboard', + url: '/products/the-collection-snowboard-liquid', + brand: 'Hydrogen Vendor', + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: 'The Multi-managed Snowboard', + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + name: 'The Multi-managed Snowboard', + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + price: 629.95, + sku: 'sku-managed-1', + product_id: '7234590736497', + category: 'snowboard', + url: '/products/the-multi-managed-snowboard', + brand: 'Multi-managed Vendor', + }, + ], + order_id: 'sh-f77a78f1-C1D8-4ED4-9C9B-0D352CF6F3BF', + checkout_id: '5f7028e0bd5225c17b24bdaa0c09f914', + total: 2759.8, + currency: 'USD', + discount: 0, + shipping: 0, + revenue: 2759.8, + value: 2759.8, + tax: 0, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts new file mode 100644 index 0000000000..9d845c1dde --- /dev/null +++ b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts @@ -0,0 +1,1517 @@ +import { dummySourceConfig, dummyContext, responseDummyContext } from '../constants'; + +export const pixelCheckoutStepsScenarios = [ + { + name: 'shopify', + description: 'Track Call -> address_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d2154d-7525-47A4-87FA-E54D2322E129', + name: 'checkout_address_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:45:50.523Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'checkout_address_info_submitted' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Address Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> contact_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7c8416f-1D35-4304-EF29-78666678C4E9', + name: 'checkout_contact_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:40:28.498Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'checkout_contact_info_submitted' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Contact Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [], + }, + shippingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> shipping_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d5618e-404A-4E6D-4662-599A4BCC9E7C', + name: 'checkout_shipping_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:47:38.576Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'checkout_shipping_info_submitted' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Shipping Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> payment_info_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d843ea-ED11-4A12-F32F-C5A45BED0413', + name: 'payment_info_submitted', + data: { + checkout: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T21:49:13.092Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'payment_info_submitted' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Payment Info Submitted', + properties: { + buyerAcceptsEmailMarketing: false, + buyerAcceptsSmsMarketing: false, + attributes: [], + billingAddress: { + address1: null, + address2: null, + city: null, + country: 'US', + countryCode: 'US', + firstName: null, + lastName: null, + phone: null, + province: null, + provinceCode: null, + zip: null, + }, + token: '5f7028e0bd5225c17b24bdaa0c09f914', + currencyCode: 'USD', + discountApplications: [], + discountsAmount: { + amount: 0, + currencyCode: 'USD', + }, + email: 'test-user@sampleemail.com', + phone: '', + lineItems: [ + { + discountAllocations: [], + id: '41327143321713', + quantity: 2, + title: 'The Collection Snowboard: Liquid', + variant: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6_64x64.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + }, + sku: null, + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1499.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + { + discountAllocations: [], + id: '41327143157873', + quantity: 2, + title: 'The Multi-managed Snowboard', + variant: { + id: '41327143157873', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a_64x64.jpg?v=1724736597', + }, + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + id: '7234590736497', + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + type: 'snowboard', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + }, + sku: 'sku-managed-1', + title: null, + untranslatedTitle: null, + }, + finalLinePrice: { + amount: 1259.9, + currencyCode: 'USD', + }, + sellingPlanAllocation: null, + properties: [], + }, + ], + localization: { + country: { + isoCode: 'US', + }, + language: { + isoCode: 'en-US', + }, + market: { + id: 'gid://shopify/Market/23505895537', + handle: 'us', + }, + }, + order: { + id: null, + customer: { + id: null, + isFirstOrder: null, + }, + }, + delivery: { + selectedDeliveryOptions: [ + { + cost: { + amount: 0, + currencyCode: 'USD', + }, + costAfterDiscounts: { + amount: 0, + currencyCode: 'USD', + }, + description: null, + handle: + '5f7028e0bd5225c17b24bdaa0c09f914-8388085074acab7e91de633521be86f0', + title: 'Economy', + type: 'shipping', + }, + ], + }, + shippingAddress: { + address1: 'Queens Center', + address2: null, + city: 'Elmhurst', + country: 'US', + countryCode: 'US', + firstName: 'test', + lastName: 'user', + phone: null, + province: 'NY', + provinceCode: 'NY', + zip: '11373', + }, + subtotalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + shippingLine: { + price: { + amount: 0, + currencyCode: 'USD', + }, + }, + smsMarketingPhone: null, + totalTax: { + amount: 0, + currencyCode: 'USD', + }, + totalPrice: { + amount: 2759.8, + currencyCode: 'USD', + }, + transactions: [], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts new file mode 100644 index 0000000000..0b8f8c3c1a --- /dev/null +++ b/test/integrations/sources/shopify/pixelTestScenarios/ProductEventsTests.ts @@ -0,0 +1,888 @@ +// This file contains the test scenarios related to Shopify pixel events, emitted from web pixel on the browser. +import { dummyContext, dummySourceConfig, responseDummyContext } from '../constants'; + +export const pixelEventsTestScenarios = [ + { + name: 'shopify', + description: 'Page Call -> page_view event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6b6f548-5FEF-4DAE-9CAB-39EE6F94E09B', + name: 'page_viewed', + data: {}, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T17:24:30.373Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['page_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'page_viewed' }, + integrations: { + SHOPIFY: true, + }, + name: 'Page View', + type: 'page', + properties: {}, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> product_viewed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6c07b5a-D20A-4E5F-812E-337299B56C34', + name: 'product_viewed', + data: { + productVariant: { + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + id: '7234590834801', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + type: 'snowboard', + }, + id: '41327143321713', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + sku: '', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T17:34:54.889Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['product_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'product_viewed' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product Viewed', + properties: { + productVariant: { + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + id: '7234590834801', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid', + type: 'snowboard', + }, + id: '41327143321713', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + sku: '', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + product_id: '7234590834801', + variant: 'The Collection Snowboard: Liquid', + brand: 'Hydrogen Vendor', + category: 'snowboard', + price: 749.95, + currency: 'USD', + url: '/products/the-collection-snowboard-liquid', + name: 'The Collection Snowboard: Liquid', + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> cart_viewed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'shu-f6eecef1-4132-459F-CDB5-681DA3DD61CD', + name: 'cart_viewed', + data: { + cart: { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + lines: [ + { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + merchandise: { + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + id: '7234590736497', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + type: 'snowboard', + }, + id: '41327143157873', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', + }, + sku: 'sku-managed-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + quantity: 2, + }, + ], + totalQuantity: 2, + attributes: [], + id: 'Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T18:25:30.125Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['cart_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'cart_viewed' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Cart Viewed', + properties: { + products: [ + { + cost: { + totalAmount: { + amount: 1259.9, + currencyCode: 'USD', + }, + }, + merchandise: { + price: { + amount: 629.95, + currencyCode: 'USD', + }, + product: { + title: 'The Multi-managed Snowboard', + vendor: 'Multi-managed Vendor', + id: '7234590736497', + untranslatedTitle: 'The Multi-managed Snowboard', + url: '/products/the-multi-managed-snowboard', + type: 'snowboard', + }, + id: '41327143157873', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', + }, + sku: 'sku-managed-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + quantity: 2, + product_id: '7234590736497', + variant: 'The Multi-managed Snowboard', + image_url: + '//store.myshopify.com/cdn/shop/files/Main_9129b69a-0c7b-4f66-b6cf-c4222f18028a.jpg?v=1724736597', + price: 629.95, + category: 'snowboard', + url: '/products/the-multi-managed-snowboard', + brand: 'Multi-managed Vendor', + sku: 'sku-managed-1', + name: 'Default Title', + }, + ], + cart_id: 'Z2NwLXVzLWVhc3QxOjAxSjY5OVpIRURQNERFMDBKUTVaRkI4UzdU', + total: 1259.9, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> collection_viewed event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6f0c6be-43F8-47D2-5F94-C22AD5ED3E79', + name: 'collection_viewed', + data: { + collection: { + id: '', + title: 'Products', + productVariants: [ + { + price: { + amount: 10, + currencyCode: 'USD', + }, + product: { + title: 'Gift Card', + vendor: 'Snowboard Vendor', + id: '7234590605425', + untranslatedTitle: 'Gift Card', + url: '/products/gift-card', + type: 'giftcard', + }, + id: '41327142895729', + image: { + src: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + }, + sku: '', + title: '$10', + untranslatedTitle: '$10', + }, + { + price: { + amount: 24.95, + currencyCode: 'USD', + }, + product: { + title: 'Selling Plans Ski Wax', + vendor: 'pixel-testing-rs', + id: '7234590802033', + untranslatedTitle: 'Selling Plans Ski Wax', + url: '/products/selling-plans-ski-wax', + type: 'accessories', + }, + id: '41327143223409', + image: { + src: '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', + }, + sku: '', + title: 'Selling Plans Ski Wax', + untranslatedTitle: 'Selling Plans Ski Wax', + }, + { + price: { + amount: 2629.95, + currencyCode: 'USD', + }, + product: { + title: 'The 3p Fulfilled Snowboard', + vendor: 'pixel-testing-rs', + id: '7234590703729', + untranslatedTitle: 'The 3p Fulfilled Snowboard', + url: '/products/the-3p-fulfilled-snowboard', + type: 'snowboard', + }, + id: '41327143125105', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', + }, + sku: 'sku-hosted-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + }, + ], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T18:27:39.197Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['collection_viewed'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'collection_viewed' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product List Viewed', + properties: { + cart_id: 'c7b3f99b-4d34-463b-835f-c879482a7750', + list_id: 'sh-f6f0c6be-43F8-47D2-5F94-C22AD5ED3E79', + products: [ + { + price: 10, + product: { + title: 'Gift Card', + vendor: 'Snowboard Vendor', + id: '7234590605425', + untranslatedTitle: 'Gift Card', + url: '/products/gift-card', + type: 'giftcard', + }, + id: '41327142895729', + image: { + src: '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + }, + sku: '', + title: '$10', + untranslatedTitle: '$10', + image_url: + '//store.myshopify.com/cdn/shop/files/gift_card.png?v=1724736596', + product_id: '7234590605425', + variant: 'Gift Card', + category: 'giftcard', + url: '/products/gift-card', + brand: 'Snowboard Vendor', + name: '$10', + }, + { + price: 24.95, + product: { + title: 'Selling Plans Ski Wax', + vendor: 'pixel-testing-rs', + id: '7234590802033', + untranslatedTitle: 'Selling Plans Ski Wax', + url: '/products/selling-plans-ski-wax', + type: 'accessories', + }, + id: '41327143223409', + image: { + src: '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', + }, + sku: '', + title: 'Selling Plans Ski Wax', + untranslatedTitle: 'Selling Plans Ski Wax', + image_url: + '//store.myshopify.com/cdn/shop/files/snowboard_wax.png?v=1724736599', + product_id: '7234590802033', + variant: 'Selling Plans Ski Wax', + category: 'accessories', + url: '/products/selling-plans-ski-wax', + brand: 'pixel-testing-rs', + name: 'Selling Plans Ski Wax', + }, + { + price: 2629.95, + product: { + title: 'The 3p Fulfilled Snowboard', + vendor: 'pixel-testing-rs', + id: '7234590703729', + untranslatedTitle: 'The 3p Fulfilled Snowboard', + url: '/products/the-3p-fulfilled-snowboard', + type: 'snowboard', + }, + id: '41327143125105', + image: { + src: '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', + }, + sku: 'sku-hosted-1', + title: 'Default Title', + untranslatedTitle: 'Default Title', + image_url: + '//store.myshopify.com/cdn/shop/files/Main_b9e0da7f-db89-4d41-83f0-7f417b02831d.jpg?v=1724736597', + product_id: '7234590703729', + variant: 'The 3p Fulfilled Snowboard', + category: 'snowboard', + url: '/products/the-3p-fulfilled-snowboard', + brand: 'pixel-testing-rs', + name: 'Default Title', + }, + ], + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> product_added_to_cart event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f6f828db-F77B-43E8-96C4-1D51DACD52A3', + name: 'product_added_to_cart', + data: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T18:34:42.625Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['carts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'product_added_to_cart' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product Added', + properties: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + price: 749.95, + product_id: '7234590834801', + variant: 'The Collection Snowboard: Liquid', + category: 'snowboard', + brand: 'Hydrogen Vendor', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + sku: '', + name: null, + quantity: 1, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> product_removed_from_cart event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'shu-f778d1eb-9B83-4832-9DC0-5C3B33A809F0', + name: 'product_removed_from_cart', + data: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T20:56:00.125Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['carts_update'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'product_removed_from_cart' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Product Removed', + properties: { + cartLine: { + cost: { + totalAmount: { + amount: 749.95, + currencyCode: 'USD', + }, + }, + merchandise: { + id: '41327143321713', + image: { + src: 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + }, + price: { + amount: 749.95, + currencyCode: 'USD', + }, + product: { + id: '7234590834801', + title: 'The Collection Snowboard: Liquid', + vendor: 'Hydrogen Vendor', + type: 'snowboard', + untranslatedTitle: 'The Collection Snowboard: Liquid', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + }, + sku: '', + title: null, + untranslatedTitle: null, + }, + quantity: 1, + }, + image_url: + 'https://cdn.shopify.com/s/files/1/0590/2696/4593/files/Main_b13ad453-477c-4ed1-9b43-81f3345adfd6.jpg?v=1724736600', + price: 749.95, + product_id: '7234590834801', + variant: 'The Collection Snowboard: Liquid', + category: 'snowboard', + brand: 'Hydrogen Vendor', + url: '/products/the-collection-snowboard-liquid?variant=41327143321713', + sku: '', + name: null, + quantity: 1, + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> search_submitted event from web pixel', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d599b4-D80F-4D05-C4CE-B980D5444596', + name: 'search_submitted', + data: { + searchResult: { + query: 'skate', + productVariants: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T22:37:35.869Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['search_submitted'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { ...responseDummyContext, topic: 'search_submitted' }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Search Submitted', + properties: { + query: 'skate', + }, + anonymousId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + }, + ], + }, + }, + ], + }, + }, + }, + { + name: 'shopify', + description: 'Track Call -> unknown event from web pixel, should not be sent to Shopify', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'sh-f7d599b4-D80F-4D05-C4CE-B980D5444596', + name: 'unknown_event', + data: { + searchResult: { + query: 'skate', + productVariants: [], + }, + }, + type: 'standard', + clientId: 'c7b3f99b-4d34-463b-835f-c879482a7750', + timestamp: '2024-09-15T22:37:35.869Z', + context: dummyContext, + pixelEventLabel: true, + query_parameters: { + topic: ['search_submitted'], + writeKey: ['dummy-write-key'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + outputToSource: { + body: 'T0s=', + contentType: 'text/plain', + }, + statusCode: 200, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/sources/shopify/v1ServerSideEventsTests.ts b/test/integrations/sources/shopify/v1ServerSideEventsTests.ts new file mode 100644 index 0000000000..a91a213873 --- /dev/null +++ b/test/integrations/sources/shopify/v1ServerSideEventsTests.ts @@ -0,0 +1,598 @@ +// This file contains the test scenarios for the server-side events from the Shopify GraphQL API for +// the v1 transformation flow +import utils from '../../../../src/v0/util'; +const defaultMockFns = () => { + jest.spyOn(utils, 'generateUUID').mockReturnValue('97fcd7b2-cc24-47d7-b776-057b7b199513'); +}; +import { dummySourceConfig } from './constants'; + +export const v1ServerSideEventsScenarios = [ + { + name: 'shopify', + description: 'Track Call -> Checkout Updated event', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 35374569160817, + token: 'e89d4437003b6b8480f8bc7f8036a659', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + email: 'testuser101@gmail.com', + gateway: null, + buyer_accepts_marketing: false, + buyer_accepts_sms_marketing: false, + sms_marketing_phone: null, + created_at: '2024-09-16T03:50:15+00:00', + updated_at: '2024-09-17T03:29:02-04:00', + landing_site: '/', + note: '', + note_attributes: [], + referring_site: '', + shipping_lines: [ + { + code: 'Standard', + price: '6.90', + original_shop_price: '6.90', + original_shop_markup: '0.00', + source: 'shopify', + title: 'Standard', + presentment_title: 'Standard', + phone: null, + tax_lines: [], + custom_tax_lines: null, + markup: '0.00', + carrier_identifier: null, + carrier_service_id: null, + api_client_id: '580111', + delivery_option_group: { + token: '26492692a443ee35c30eb82073bacaa8', + type: 'one_time_purchase', + }, + delivery_expectation_range: null, + delivery_expectation_type: null, + id: null, + requested_fulfillment_service_id: null, + delivery_category: null, + validation_context: null, + applied_discounts: [], + }, + ], + shipping_address: { + first_name: 'testuser', + address1: 'oakwood bridge', + phone: null, + city: 'KLF', + zip: '85003', + province: 'Arizona', + country: 'United States', + last_name: 'dummy', + address2: 'Hedgetown', + company: null, + latitude: null, + longitude: null, + name: 'testuser dummy', + country_code: 'US', + province_code: 'AZ', + }, + taxes_included: false, + total_weight: 0, + currency: 'USD', + completed_at: null, + phone: null, + customer_locale: 'en-US', + line_items: [ + { + key: '41327143059569', + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + presentment_title: 'The Multi-location Snowboard', + presentment_variant_title: '', + product_id: 7234590638193, + quantity: 1, + requires_shipping: true, + sku: '', + tax_lines: [], + taxable: true, + title: 'The Multi-location Snowboard', + variant_id: 41327143059569, + variant_title: '', + variant_price: '729.95', + vendor: 'pixel-testing-rs', + unit_price_measurement: { + measured_type: null, + quantity_value: null, + quantity_unit: null, + reference_value: null, + reference_unit: null, + }, + compare_at_price: null, + line_price: '729.95', + price: '729.95', + applied_discounts: [], + destination_location_id: null, + user_id: null, + rank: null, + origin_location_id: null, + properties: {}, + }, + ], + name: '#35374569160817', + abandoned_checkout_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', + discount_codes: [], + tax_lines: [], + presentment_currency: 'USD', + source_name: 'web', + total_line_items_price: '729.95', + total_tax: '0.00', + total_discounts: '0.00', + subtotal_price: '729.95', + total_price: '736.85', + total_duties: '0.00', + device_id: null, + user_id: null, + location_id: null, + source_identifier: null, + source_url: null, + source: null, + closed_at: null, + customer: { + id: 7188389789809, + email: 'testuser101@gmail.com', + accepts_marketing: false, + created_at: null, + updated_at: null, + first_name: 'testuser', + last_name: 'dummy', + orders_count: 0, + state: 'disabled', + total_spent: '0.00', + last_order_id: null, + note: null, + verified_email: true, + multipass_identifier: null, + tax_exempt: false, + phone: null, + tags: '', + currency: 'USD', + accepts_marketing_updated_at: null, + admin_graphql_api_id: 'gid://shopify/Customer/7188389789809', + default_address: { + id: null, + customer_id: 7188389789809, + first_name: 'testuser', + last_name: 'dummy', + company: null, + address1: 'oakwood bridge', + address2: 'Hedgetown', + city: 'KLF', + province: 'Arizona', + country: 'United States', + zip: '85003', + phone: null, + name: 'testuser dummy', + province_code: 'AZ', + country_code: 'US', + country_name: 'United States', + default: true, + }, + last_order_name: null, + marketing_opt_in_level: null, + }, + query_parameters: { + topic: ['checkouts_update'], + writeKey: ['2l9QoM7KRMJLMcYhXNUVDT0Mqbd'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'server', + version: '2.0.0', + }, + integration: { + name: 'SHOPIFY', + }, + topic: 'checkouts_update', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Checkout Updated', + properties: { + order_id: 35374569160817, + value: '736.85', + tax: '0.00', + currency: 'USD', + token: 'e89d4437003b6b8480f8bc7f8036a659', + cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + email: 'testuser101@gmail.com', + buyer_accepts_marketing: false, + buyer_accepts_sms_marketing: false, + created_at: '2024-09-16T03:50:15+00:00', + updated_at: '2024-09-17T03:29:02-04:00', + landing_site: '/', + note: '', + note_attributes: [], + referring_site: '', + shipping_lines: [ + { + code: 'Standard', + price: '6.90', + original_shop_price: '6.90', + original_shop_markup: '0.00', + source: 'shopify', + title: 'Standard', + presentment_title: 'Standard', + phone: null, + tax_lines: [], + custom_tax_lines: null, + markup: '0.00', + carrier_identifier: null, + carrier_service_id: null, + api_client_id: '580111', + delivery_option_group: { + token: '26492692a443ee35c30eb82073bacaa8', + type: 'one_time_purchase', + }, + delivery_expectation_range: null, + delivery_expectation_type: null, + id: null, + requested_fulfillment_service_id: null, + delivery_category: null, + validation_context: null, + applied_discounts: [], + }, + ], + taxes_included: false, + total_weight: 0, + customer_locale: 'en-US', + name: '#35374569160817', + abandoned_checkout_url: + 'https://pixel-testing-rs.myshopify.com/59026964593/checkouts/ac/Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2/recover?key=8195f56ee0de230b3a0469cc692f3436', + discount_codes: [], + tax_lines: [], + presentment_currency: 'USD', + source_name: 'web', + total_line_items_price: '729.95', + total_discounts: '0.00', + subtotal_price: '729.95', + total_duties: '0.00', + products: [ + { + product_id: 7234590638193, + price: '729.95', + brand: 'pixel-testing-rs', + quantity: 1, + key: '41327143059569', + fulfillment_service: 'manual', + gift_card: false, + grams: 0, + presentment_title: 'The Multi-location Snowboard', + presentment_variant_title: '', + requires_shipping: true, + tax_lines: [], + taxable: true, + title: 'The Multi-location Snowboard', + unit_price_measurement: { + measured_type: null, + quantity_value: null, + quantity_unit: null, + reference_value: null, + reference_unit: null, + }, + compare_at_price: null, + line_price: '729.95', + applied_discounts: [], + destination_location_id: null, + user_id: null, + rank: null, + origin_location_id: null, + properties: {}, + variant: '41327143059569 729.95 ', + }, + ], + }, + userId: '7188389789809', + traits: { + email: 'testuser101@gmail.com', + firstName: 'testuser', + lastName: 'dummy', + address: { + id: null, + customer_id: 7188389789809, + first_name: 'testuser', + last_name: 'dummy', + company: null, + address1: 'oakwood bridge', + address2: 'Hedgetown', + city: 'KLF', + province: 'Arizona', + country: 'United States', + zip: '85003', + phone: null, + name: 'testuser dummy', + province_code: 'AZ', + country_code: 'US', + country_name: 'United States', + default: true, + }, + acceptsMarketing: false, + orderCount: 0, + state: 'disabled', + totalSpent: '0.00', + verifiedEmail: true, + taxExempt: false, + tags: '', + currency: 'USD', + adminGraphqlApiId: 'gid://shopify/Customer/7188389789809', + shippingAddress: { + first_name: 'testuser', + address1: 'oakwood bridge', + phone: null, + city: 'KLF', + zip: '85003', + province: 'Arizona', + country: 'United States', + last_name: 'dummy', + address2: 'Hedgetown', + company: null, + latitude: null, + longitude: null, + name: 'testuser dummy', + country_code: 'US', + province_code: 'AZ', + }, + }, + timestamp: '2024-09-17T07:29:02.000Z', + anonymousId: '97fcd7b2-cc24-47d7-b776-057b7b199513', + }, + ], + }, + }, + ], + }, + }, + mockFns: () => { + defaultMockFns(); + }, + }, + { + name: 'shopify', + description: 'Track Call -> Cart Update event', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + line_items: [ + { + id: 41327143059569, + properties: null, + quantity: 3, + variant_id: 41327143059569, + key: '41327143059569:90562f18109e0e6484b0c297e7981b30', + discounted_price: '729.95', + discounts: [], + gift_card: false, + grams: 0, + line_price: '2189.85', + original_line_price: '2189.85', + original_price: '729.95', + price: '729.95', + product_id: 7234590638193, + sku: '', + taxable: true, + title: 'The Multi-location Snowboard', + total_discount: '0.00', + vendor: 'pixel-testing-rs', + discounted_price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + original_line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + total_discount_set: { + shop_money: { + amount: '0.0', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.0', + currency_code: 'USD', + }, + }, + }, + ], + note: '', + updated_at: '2024-09-17T08:15:13.280Z', + created_at: '2024-09-16T03:50:15.478Z', + query_parameters: { + topic: ['carts_update'], + writeKey: ['2l9QoM7KRMJLMcYhXNUVDT0Mqbd'], + }, + }, + source: dummySourceConfig, + }, + ], + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + name: 'RudderStack Shopify Cloud', + eventOrigin: 'server', + version: '2.0.0', + }, + integration: { + name: 'SHOPIFY', + }, + topic: 'carts_update', + }, + integrations: { + SHOPIFY: true, + }, + type: 'track', + event: 'Cart Update', + properties: { + id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', + note: '', + updated_at: '2024-09-17T08:15:13.280Z', + created_at: '2024-09-16T03:50:15.478Z', + products: [ + { + product_id: 7234590638193, + price: '729.95', + brand: 'pixel-testing-rs', + quantity: 3, + id: 41327143059569, + properties: null, + key: '41327143059569:90562f18109e0e6484b0c297e7981b30', + discounted_price: '729.95', + discounts: [], + gift_card: false, + grams: 0, + line_price: '2189.85', + original_line_price: '2189.85', + original_price: '729.95', + taxable: true, + title: 'The Multi-location Snowboard', + total_discount: '0.00', + discounted_price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + original_line_price_set: { + shop_money: { + amount: '2189.85', + currency_code: 'USD', + }, + presentment_money: { + amount: '2189.85', + currency_code: 'USD', + }, + }, + price_set: { + shop_money: { + amount: '729.95', + currency_code: 'USD', + }, + presentment_money: { + amount: '729.95', + currency_code: 'USD', + }, + }, + total_discount_set: { + shop_money: { + amount: '0.0', + currency_code: 'USD', + }, + presentment_money: { + amount: '0.0', + currency_code: 'USD', + }, + }, + variant: '41327143059569 ', + }, + ], + }, + anonymousId: '97fcd7b2-cc24-47d7-b776-057b7b199513', + }, + ], + }, + }, + ], + }, + }, + mockFns: () => { + defaultMockFns(); + }, + }, +];