From d40e772f1a3741c1c4e9ab2365ed464b3988812e Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:41:54 +0530 Subject: [PATCH] feat: onboard shopify to v1 (#3665) * feat: onboard shopify to v1, initial commit * chore: refactor, add pixel transformation definitions * feat: add support for all pixel events in v1 shopify source * fix: add customer id check * chore: fix checks * fix: add configs for new webhook topics and events from pixel app * chore: update webhook event topic in mapping * chore: refactor * chore: update cart viewed logic * chore: refactor pixel code logic and tests * fix: library version for old and new serverside events * chore: address comments, refactorx1 * chore: add test * chore: add testsx2 * chore: update version naming from config * chore: keep old v0 logic intact, refactor * chore: sonarcloud reliability check fix * chore: update util file names * chore: move webhook specific logic for v2 pixel, address comments * chore: more refactoring, update userId and anonymousid from customer object * chore: update library name for pixel and webhook events in pixel app flow * chore: refactor pixel tests to seperate directory, remove reduntant test data --------- Co-authored-by: Krishna Chaitanya --- src/v0/sources/shopify/config.js | 52 + src/v0/sources/shopify/transform.js | 8 +- src/v1/sources/shopify/config.js | 76 + .../cartViewedEventMapping.json | 42 + .../checkoutStartedCompletedEventMapping.json | 42 + .../contextualFieldMapping.json | 34 + .../productListViewedEventMapping.json | 38 + .../productToCartEventMapping.json | 42 + .../productViewedEventMapping.json | 46 + src/v1/sources/shopify/pixelTransform.js | 91 + src/v1/sources/shopify/pixelUtils.js | 195 +++ src/v1/sources/shopify/pixelUtils.test.js | 244 +++ .../shopify/pixelWebhookEventTransform.js | 88 + src/v1/sources/shopify/transform.js | 33 + .../integrations/sources/shopify/constants.ts | 155 ++ test/integrations/sources/shopify/data.ts | 14 +- .../pixelTestScenarios/CheckoutEventsTests.ts | 570 +++++++ .../pixelTestScenarios/CheckoutStepsTests.ts | 1517 +++++++++++++++++ .../pixelTestScenarios/ProductEventsTests.ts | 888 ++++++++++ .../shopify/v1ServerSideEventsTests.ts | 598 +++++++ 20 files changed, 4771 insertions(+), 2 deletions(-) create mode 100644 src/v1/sources/shopify/config.js create mode 100644 src/v1/sources/shopify/pixelEventsMappings/cartViewedEventMapping.json create mode 100644 src/v1/sources/shopify/pixelEventsMappings/checkoutStartedCompletedEventMapping.json create mode 100644 src/v1/sources/shopify/pixelEventsMappings/contextualFieldMapping.json create mode 100644 src/v1/sources/shopify/pixelEventsMappings/productListViewedEventMapping.json create mode 100644 src/v1/sources/shopify/pixelEventsMappings/productToCartEventMapping.json create mode 100644 src/v1/sources/shopify/pixelEventsMappings/productViewedEventMapping.json create mode 100644 src/v1/sources/shopify/pixelTransform.js create mode 100644 src/v1/sources/shopify/pixelUtils.js create mode 100644 src/v1/sources/shopify/pixelUtils.test.js create mode 100644 src/v1/sources/shopify/pixelWebhookEventTransform.js create mode 100644 src/v1/sources/shopify/transform.js 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/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..8cf39dfa5c 100644 --- a/src/v0/sources/shopify/transform.js +++ b/src/v0/sources/shopify/transform.js @@ -287,4 +287,10 @@ const process = async (event) => { return response; }; -exports.process = process; +module.exports = { + process, + processEvent, + identifyPayloadBuilder, + ecomPayloadBuilder, + trackPayloadBuilder, +}; diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js new file mode 100644 index 0000000000..5a3ce99b40 --- /dev/null +++ b/src/v1/sources/shopify/config.js @@ -0,0 +1,76 @@ +const path = require('path'); +const fs = require('fs'); + +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 contextualFieldMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'contextualFieldMapping.json')), +); + +const cartViewedEventMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'cartViewedEventMapping.json')), +); + +const productListViewedEventMappingJSON = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, 'pixelEventsMappings', 'productListViewedEventMapping.json'), + ), +); + +const productViewedEventMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'productViewedEventMapping.json')), +); + +const productToCartEventMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'productToCartEventMapping.json')), +); + +const checkoutStartedCompletedEventMappingJSON = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, 'pixelEventsMappings', 'checkoutStartedCompletedEventMapping.json'), + ), +); + +const INTEGERATION = 'SHOPIFY'; + +module.exports = { + INTEGERATION, + PIXEL_EVENT_TOPICS, + PIXEL_EVENT_MAPPING, + contextualFieldMappingJSON, + cartViewedEventMappingJSON, + productListViewedEventMappingJSON, + productViewedEventMappingJSON, + productToCartEventMappingJSON, + checkoutStartedCompletedEventMappingJSON, +}; diff --git a/src/v1/sources/shopify/pixelEventsMappings/cartViewedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/cartViewedEventMapping.json new file mode 100644 index 0000000000..b74320c758 --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/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/pixelEventsMappings/checkoutStartedCompletedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/checkoutStartedCompletedEventMapping.json new file mode 100644 index 0000000000..478bcfc270 --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/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/pixelEventsMappings/contextualFieldMapping.json b/src/v1/sources/shopify/pixelEventsMappings/contextualFieldMapping.json new file mode 100644 index 0000000000..f314684948 --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/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/pixelEventsMappings/productListViewedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/productListViewedEventMapping.json new file mode 100644 index 0000000000..fb8e8a4567 --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/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/pixelEventsMappings/productToCartEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/productToCartEventMapping.json new file mode 100644 index 0000000000..2f9d71bc03 --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/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/pixelEventsMappings/productViewedEventMapping.json b/src/v1/sources/shopify/pixelEventsMappings/productViewedEventMapping.json new file mode 100644 index 0000000000..becb15acfc --- /dev/null +++ b/src/v1/sources/shopify/pixelEventsMappings/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..0ca64b4123 --- /dev/null +++ b/src/v1/sources/shopify/pixelTransform.js @@ -0,0 +1,91 @@ +const stats = require('../../../util/stats'); +const logger = require('../../../logger'); +const { removeUndefinedAndNullValues } = require('../../../v0/util'); +const { + pageViewedEventBuilder, + cartViewedEventBuilder, + productListViewedEventBuilder, + productViewedEventBuilder, + productToCartEventBuilder, + checkoutEventBuilder, + checkoutStepEventBuilder, + searchEventBuilder, +} = require('./pixelUtils'); +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', + eventOrigin: 'client', + version: '2.0.0', + }); + message.setProperty('context.topic', name); + message = removeUndefinedAndNullValues(message); + return message; +} + +const processEventFromPixel = async (event) => { + const pixelEvent = processPixelEvent(event); + return removeUndefinedAndNullValues(pixelEvent); +}; + +module.exports = { + processEventFromPixel, +}; diff --git a/src/v1/sources/shopify/pixelUtils.js b/src/v1/sources/shopify/pixelUtils.js new file mode 100644 index 0000000000..92197a558b --- /dev/null +++ b/src/v1/sources/shopify/pixelUtils.js @@ -0,0 +1,195 @@ +/* eslint-disable no-param-reassign */ +const Message = require('../../../v0/sources/message'); +const { EventType } = require('../../../constants'); +const { + INTEGERATION, + PIXEL_EVENT_MAPPING, + 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, contextualFieldMappingJSON); + 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 = []; + let total; + if (lines) { + lines.forEach((line) => { + const product = mapObjectKeys(line, cartViewedEventMappingJSON); + products.push(product); + total = line.cost.totalAmount.amount; + }); + } + + const properties = { + products, + cart_id: inputEvent.data.cart.id, + total, + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage(EventType.TRACK, 'Cart Viewed', properties, contextualPayload); +}; + +const productListViewedEventBuilder = (inputEvent) => { + const productVariants = inputEvent?.data?.collection?.productVariants; + const products = []; + + productVariants.forEach((productVariant) => { + const mappedProduct = mapObjectKeys(productVariant, productListViewedEventMappingJSON); + products.push(mappedProduct); + }); + + const properties = { + cart_id: inputEvent.clientId, + list_id: inputEvent.id, + products, + }; + + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage(EventType.TRACK, 'Product List Viewed', properties, contextualPayload); +}; + +const productViewedEventBuilder = (inputEvent) => { + const properties = { + ...mapObjectKeys(inputEvent.data, productViewedEventMappingJSON), + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage(EventType.TRACK, 'Product Viewed', properties, contextualPayload); +}; + +const productToCartEventBuilder = (inputEvent) => { + const properties = { + ...mapObjectKeys(inputEvent.data, productToCartEventMappingJSON), + }; + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + return createMessage( + EventType.TRACK, + PIXEL_EVENT_MAPPING[inputEvent.name], + properties, + contextualPayload, + ); +}; + +const checkoutEventBuilder = (inputEvent) => { + const lineItems = inputEvent?.data?.checkout?.lineItems; + const products = []; + + lineItems.forEach((lineItem) => { + const mappedProduct = mapObjectKeys(lineItem, checkoutStartedCompletedEventMappingJSON); + 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, contextualFieldMappingJSON); + return createMessage( + EventType.TRACK, + PIXEL_EVENT_MAPPING[inputEvent.name], + properties, + contextualPayload, + ); +}; + +const checkoutStepEventBuilder = (inputEvent) => { + const contextualPayload = mapObjectKeys(inputEvent.context, contextualFieldMappingJSON); + const properties = { + ...inputEvent.data.checkout, + }; + 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, contextualFieldMappingJSON); + return createMessage( + EventType.TRACK, + PIXEL_EVENT_MAPPING[inputEvent.name], + properties, + contextualPayload, + ); +}; + +module.exports = { + pageViewedEventBuilder, + cartViewedEventBuilder, + productListViewedEventBuilder, + productViewedEventBuilder, + productToCartEventBuilder, + checkoutEventBuilder, + checkoutStepEventBuilder, + searchEventBuilder, +}; diff --git a/src/v1/sources/shopify/pixelUtils.test.js b/src/v1/sources/shopify/pixelUtils.test.js new file mode 100644 index 0000000000..cd544568cd --- /dev/null +++ b/src/v1/sources/shopify/pixelUtils.test.js @@ -0,0 +1,244 @@ +const { + pageViewedEventBuilder, + cartViewedEventBuilder, + productListViewedEventBuilder, + productViewedEventBuilder, + productToCartEventBuilder, + checkoutEventBuilder, + checkoutStepEventBuilder, + searchEventBuilder, +} = require('./pixelUtils'); +const { EventType } = require('../../../constants'); +const Message = require('../../../v0/sources/message'); +jest.mock('ioredis', () => require('../../../../test/__mocks__/redis')); +jest.mock('../../../v0/sources/message'); + +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/pixelWebhookEventTransform.js b/src/v1/sources/shopify/pixelWebhookEventTransform.js new file mode 100644 index 0000000000..43b741f837 --- /dev/null +++ b/src/v1/sources/shopify/pixelWebhookEventTransform.js @@ -0,0 +1,88 @@ +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 { + 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 (event.customer && isDefinedNotNullNotEmpty(event?.customer?.id)) { + message.userId = String(event.customer.id); + } + 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', + eventOrigin: 'server', + 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 new file mode 100644 index 0000000000..ff9aadbca4 --- /dev/null +++ b/src/v1/sources/shopify/transform.js @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +const { isDefinedAndNotNull } = require('../../../v0/util'); +const { processEventFromPixel } = require('./pixelTransform'); +const { processPixelWebhookEvent } = require('./pixelWebhookEventTransform'); +const { process: processLegacyEvents } = require('../../../v0/sources/shopify/transform'); + +const process = async (inputEvent) => { + const { event, source } = inputEvent; + const metricMetadata = { + // eslint-disable-next-line unicorn/consistent-destructuring + 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) + // or the pixel-based (latest) implementation. + if (source && isDefinedAndNotNull(source.Config) && source?.Config?.version === 'pixel') { + 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); + return responseV2; + } + const webhookEventResponse = await processPixelWebhookEvent(event, metricMetadata, source); + return webhookEventResponse; + } + // this is for default legacy tracker based server-side events processing + const response = await processLegacyEvents(event); + return response; +}; + +module.exports = { process }; 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 f5eb3c148b..7a74bc4d06 100644 --- a/test/integrations/sources/shopify/data.ts +++ b/test/integrations/sources/shopify/data.ts @@ -1,6 +1,10 @@ import { skip } from 'node:test'; +import { pixelCheckoutEventsTestScenarios } from './pixelTestScenarios/CheckoutEventsTests'; +import { pixelCheckoutStepsScenarios } from './pixelTestScenarios/CheckoutStepsTests'; +import { pixelEventsTestScenarios } from './pixelTestScenarios/ProductEventsTests'; +import { v1ServerSideEventsScenarios } from './v1ServerSideEventsTests'; -export const data = [ +const serverSideEventsScenarios = [ { name: 'shopify', description: 'Track Call -> carts_create ', @@ -607,3 +611,11 @@ export const data = [ }, }, ]; + +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(); + }, + }, +];