diff --git a/src/v1/sources/shopify/pixelTransform.js b/src/v1/sources/shopify/pixelTransform.js index 17de96f6e0..03dbdae008 100644 --- a/src/v1/sources/shopify/pixelTransform.js +++ b/src/v1/sources/shopify/pixelTransform.js @@ -29,16 +29,7 @@ const NO_OPERATION_SUCCESS = { }, statusCode: 200, }; -const extractCartToken = (cartToken) => { - if (typeof cartToken !== 'string') { - logger.error(`Cart token is not a string`); - return undefined; - } - const cartTokenParts = cartToken.split('/'); - return cartTokenParts[3]; -}; - -const handleCartTokenRedisOperations = async (inputEvent, clientId) => { +const extractCartTokenAndConfigureAnonymousId = async (inputEvent, clientId) => { try { const cartTokenLocation = pixelEventToCartTokenLocationMapping[inputEvent.name]; if (!cartTokenLocation) { @@ -49,8 +40,17 @@ const handleCartTokenRedisOperations = async (inputEvent, clientId) => { return; } const unparsedCartToken = _.get(inputEvent, cartTokenLocation); - const cartToken = extractCartToken(unparsedCartToken); - inputEvent.anonymousId = clientId; + if (typeof unparsedCartToken !== 'string') { + logger.error(`Cart token is not a string`); + stats.increment('shopify_pixel_cart_token_not_found', { + event: inputEvent.name, + writeKey: inputEvent.query_parameters.writeKey, + }); + return; + } + const cartTokenParts = unparsedCartToken.split('/'); + const cartToken = cartTokenParts[3]; + if (isDefinedNotNullNotEmpty(clientId)) { await RedisDB.setVal(cartToken, ['anonymousId', clientId]); stats.increment('shopify_pixel_cart_token_set', { @@ -58,6 +58,7 @@ const handleCartTokenRedisOperations = async (inputEvent, clientId) => { writeKey: inputEvent.query_parameters.writeKey, }); } + inputEvent.anonymousId = clientId; } catch (error) { logger.error(`Error handling Redis operations for event: ${inputEvent.name}`, error); stats.increment('shopify_pixel_cart_token_redis_error', { @@ -79,6 +80,7 @@ function processPixelEvent(inputEvent) { message = pageViewedEventBuilder(inputEvent); break; case PIXEL_EVENT_TOPICS.CART_VIEWED: + extractCartTokenAndConfigureAnonymousId(inputEvent, clientId); message = cartViewedEventBuilder(inputEvent); break; case PIXEL_EVENT_TOPICS.COLLECTION_VIEWED: @@ -94,7 +96,7 @@ function processPixelEvent(inputEvent) { case PIXEL_EVENT_TOPICS.CHECKOUT_STARTED: case PIXEL_EVENT_TOPICS.CHECKOUT_COMPLETED: if (customer.id) message.userId = customer.id || ''; - handleCartTokenRedisOperations(inputEvent, clientId); + extractCartTokenAndConfigureAnonymousId(inputEvent, clientId); message = checkoutEventBuilder(inputEvent); break; case PIXEL_EVENT_TOPICS.CHECKOUT_ADDRESS_INFO_SUBMITTED: @@ -102,7 +104,7 @@ function processPixelEvent(inputEvent) { case PIXEL_EVENT_TOPICS.CHECKOUT_SHIPPING_INFO_SUBMITTED: case PIXEL_EVENT_TOPICS.PAYMENT_INFO_SUBMITTED: if (customer.id) message.userId = customer.id || ''; - handleCartTokenRedisOperations(inputEvent, clientId); + extractCartTokenAndConfigureAnonymousId(inputEvent, clientId); message = checkoutStepEventBuilder(inputEvent); break; case PIXEL_EVENT_TOPICS.SEARCH_SUBMITTED: @@ -136,5 +138,5 @@ const processEventFromPixel = async (event) => { module.exports = { processEventFromPixel, - handleCartTokenRedisOperations, + extractCartTokenAndConfigureAnonymousId, }; diff --git a/src/v1/sources/shopify/pixelTransform.redisCartToken.test.js b/src/v1/sources/shopify/pixelTransform.redisCartToken.test.js index 2424077670..f3d104b066 100644 --- a/src/v1/sources/shopify/pixelTransform.redisCartToken.test.js +++ b/src/v1/sources/shopify/pixelTransform.redisCartToken.test.js @@ -1,20 +1,15 @@ -const { handleCartTokenRedisOperations } = require('./pixelTransform'); +const { extractCartTokenAndConfigureAnonymousId } = require('./pixelTransform'); const { RedisDB } = require('../../../util/redis/redisConnector'); -const { eventToCartTokenLocationMapping } = require('./config'); const stats = require('../../../util/stats'); const logger = require('../../../logger'); +const { pixelEventToCartTokenLocationMapping } = require('./config'); jest.mock('../../../util/redis/redisConnector', () => ({ RedisDB: { - getVal: jest.fn(), setVal: jest.fn(), }, })); -jest.mock('./config', () => ({ - eventToCartTokenLocationMapping: { eventName: 'cartToken' }, -})); - jest.mock('../../../util/stats', () => ({ increment: jest.fn(), })); @@ -24,57 +19,93 @@ jest.mock('../../../logger', () => ({ error: jest.fn(), })); -describe('handleCartTokenRedisOperations', () => { +jest.mock('./config', () => ({ + pixelEventToCartTokenLocationMapping: { cart_viewed: 'properties.cart_id' }, +})); + +describe('extractCartTokenAndConfigureAnonymousId', () => { beforeEach(() => { jest.clearAllMocks(); }); - it('should increment stats and return when cart token location is not found', async () => { - const inputEvent = { name: 'unknownEvent', query_parameters: { writeKey: 'testKey' } }; + it('should map inputEvent name to correct cart token location', async () => { + const inputEvent = { + name: 'cart_viewed', + properties: { + cart_id: '/checkout/cn/1234', + }, + query_parameters: { + writeKey: 'testWriteKey', + }, + }; + const clientId = 'testClientId'; - await handleCartTokenRedisOperations(inputEvent, 'clientId'); + await extractCartTokenAndConfigureAnonymousId(inputEvent, clientId); - expect(stats.increment).toHaveBeenCalledWith('shopify_pixel_cart_token_not_found', { - event: 'unknownEvent', - writeKey: 'testKey', + expect(RedisDB.setVal).toHaveBeenCalledWith('1234', ['anonymousId', clientId]); + expect(stats.increment).toHaveBeenCalledWith('shopify_pixel_cart_token_set', { + event: 'cart_viewed', + writeKey: 'testWriteKey', }); }); - it('should set new anonymousId in Redis and increment stats', async () => { + it('should handle inputEvent with undefined or null name gracefully', async () => { const inputEvent = { - name: 'eventName', - query_parameters: { writeKey: 'testKey' }, - cartToken: 'shopify/cart/12345', + name: null, + query_parameters: { + writeKey: 'testWriteKey', + }, }; - RedisDB.setVal.mockResolvedValue(); + const clientId = 'testClientId'; - await handleCartTokenRedisOperations(inputEvent, 'clientId'); + await extractCartTokenAndConfigureAnonymousId(inputEvent, clientId); - expect(RedisDB.setVal).toHaveBeenCalledWith('12345', 'clientId'); - expect(stats.increment).toHaveBeenCalledWith('shopify_pixel_cart_token_set', { - event: 'eventName', - writeKey: 'testKey', + expect(stats.increment).toHaveBeenCalledWith('shopify_pixel_cart_token_not_found', { + event: null, + writeKey: 'testWriteKey', }); }); + it('should log error when cart token is not a string', async () => { + const inputEvent = { + name: 'cart_viewed', + properties: { + cart_id: 12345, + }, + query_parameters: { + writeKey: 'testWriteKey', + }, + }; + const clientId = 'testClientId'; + + await extractCartTokenAndConfigureAnonymousId(inputEvent, clientId); + + expect(logger.error).toHaveBeenCalledWith('Cart token is not a string'); + }); + it('should log error and increment stats when exception occurs', async () => { const inputEvent = { - name: 'eventName', - query_parameters: { writeKey: 'testKey' }, - cartToken: 'shopify/cart/12345', + name: 'cart_viewed', + properties: { + cart_id: 'shopify/cart/1234', + }, + query_parameters: { + writeKey: 'testWriteKey', + }, }; + const clientId = 'testClientId'; const error = new Error('Redis error'); RedisDB.setVal.mockRejectedValue(error); - await handleCartTokenRedisOperations(inputEvent, 'clientId'); + await extractCartTokenAndConfigureAnonymousId(inputEvent, clientId); expect(logger.error).toHaveBeenCalledWith( - 'Error handling Redis operations for event: eventName', + 'Error handling Redis operations for event: cart_viewed', error, ); expect(stats.increment).toHaveBeenCalledWith('shopify_pixel_cart_token_redis_error', { - event: 'eventName', - writeKey: 'testKey', + event: 'cart_viewed', + writeKey: 'testWriteKey', }); }); });