From 55a85ba52cb214c9d05a05fcafa41ca884e2b732 Mon Sep 17 00:00:00 2001 From: M-OC Date: Thu, 29 Aug 2019 12:26:58 -0700 Subject: [PATCH] setUser tests pass --- src/lib/constants.js | 7 ++ src/lib/get-property-id.js | 33 ++++++ src/lib/track.js | 6 ++ src/tracker-component.js | 54 +++------- test/tracker-component.test.js | 6 +- test/tracker/set-user.test.js | 190 +++++++++++++++++++++++++++++---- 6 files changed, 235 insertions(+), 61 deletions(-) create mode 100644 src/lib/get-property-id.js diff --git a/src/lib/constants.js b/src/lib/constants.js index 862454d6..6af09fe7 100644 --- a/src/lib/constants.js +++ b/src/lib/constants.js @@ -5,5 +5,12 @@ export default { 'storage': { 'paypalCrCart': 'paypal-cr-cart', 'paypalCrCartExpiry': 'paypal-cr-cart-expiry' + }, + 'defaultTrackerConfig': { + 'user': { + 'id': null, + 'email': null, + 'name': null + } } }; diff --git a/src/lib/get-property-id.js b/src/lib/get-property-id.js new file mode 100644 index 00000000..00d2d887 --- /dev/null +++ b/src/lib/get-property-id.js @@ -0,0 +1,33 @@ +import { getClientID, getMerchantID } from '@paypal/sdk-client/src'; + +export const getPropertyId = ({ paramsToPropertyIdUrl }) => { + return new Promise(resolve => { + const clientId = getClientID(); + const merchantId = getMerchantID()[0]; + const propertyIdKey = `property-id-${ clientId }-${ merchantId }`; + const savedPropertyId = window.localStorage.getItem(propertyIdKey); + const currentUrl = `${ window.location.protocol }//${ window.location.host }`; + if (savedPropertyId) { + return resolve(savedPropertyId); + } + let url; + if (paramsToPropertyIdUrl) { + url = paramsToPropertyIdUrl(); + } else { + url = 'https://paypal.com/tagmanager/containers/xo'; + } + return window.fetch(`${ url }?mrid=${ merchantId }&url=${ encodeURIComponent(currentUrl) }`) + .then(res => { + if (res.status === 200) { + return res; + } + }) + .then(r => r.json()).then(container => { + window.localStorage.setItem(propertyIdKey, container.id); + resolve(container.id); + }) + .catch(() => { + // doing nothing for now since there's no logging + }); + }); +}; \ No newline at end of file diff --git a/src/lib/track.js b/src/lib/track.js index 59d779d1..9508348f 100644 --- a/src/lib/track.js +++ b/src/lib/track.js @@ -20,6 +20,12 @@ export const track = (config : Config, trackingType : TrackingType, trackingD ...config.user, id: getUserIdCookie() }; + + // remove null, undefined values + user.id || delete user.id + user.email || delete user.email + user.name || delete user.name + const deviceInfo = getDeviceInfo(); const data = { ...trackingData, diff --git a/src/tracker-component.js b/src/tracker-component.js index 012ae60d..89c01abb 100644 --- a/src/tracker-component.js +++ b/src/tracker-component.js @@ -5,6 +5,7 @@ import { getClientID, getMerchantID } from '@paypal/sdk-client/src'; // $FlowFixMe import { getUserIdCookie } from './lib/cookie-utils'; +import { getPropertyId } from './lib/get-property-id'; import getJetlore from './lib/jetlore'; import { composeCart } from './lib/compose-cart'; import { track } from './lib/track'; @@ -25,7 +26,8 @@ import type { const { accessTokenUrl, - storage + storage, + defaultTrackerConfig } = constants; const getAccessToken = (url : string, mrid : string) : Promise => { @@ -93,8 +95,6 @@ const getJetlorePayload = (type : string, options : Object) : Object => { let trackEventQueue = []; -const defaultTrackerConfig = { user: { email: undefined, name: undefined } }; - export const clearTrackQueue = (config : Config) => { // $FlowFixMe return trackEventQueue.filter(([ trackingType, trackingData ]) => { // eslint-disable-line array-callback-return @@ -129,38 +129,6 @@ const clearExpiredCart = () => { } }; -const getPropertyId = ({ paramsToPropertyIdUrl }) => { - return new Promise(resolve => { - const clientId = getClientID(); - const merchantId = getMerchantID()[0]; - const propertyIdKey = `property-id-${ clientId }-${ merchantId }`; - const savedPropertyId = window.localStorage.getItem(propertyIdKey); - const currentUrl = `${ window.location.protocol }//${ window.location.host }`; - if (savedPropertyId) { - return resolve(savedPropertyId); - } - let url; - if (paramsToPropertyIdUrl) { - url = paramsToPropertyIdUrl(); - } else { - url = 'https://paypal.com/tagmanager/containers/xo'; - } - return window.fetch(`${ url }?mrid=${ merchantId }&url=${ encodeURIComponent(currentUrl) }`) - .then(res => { - if (res.status === 200) { - return res; - } - }) - .then(r => r.json()).then(container => { - window.localStorage.setItem(propertyIdKey, container.id); - resolve(container.id); - }) - .catch(() => { - // doing nothing for now since there's no logging - }); - }); -}; - export const setImplicitPropertyId = (config : Config) => { /* ** this is used for backwards compatibility @@ -182,7 +150,8 @@ const clearCancelledCart = () => { window.localStorage.removeItem(storage.paypalCrCart); }; -export const Tracker = (config? : Config = defaultTrackerConfig) => { +export const Tracker = (config? : Config = {}) => { + config = { ...defaultTrackerConfig, ...config } /* * Use the get param ?ppDebug=true to see logs * @@ -252,12 +221,19 @@ export const Tracker = (config? : Config = defaultTrackerConfig) => { }, purchase: (data : PurchaseData) => track(config, 'purchase', data), setUser: (data : UserData) => { + const user = data.user || data + const configUser = config.user || {} + + const userId = user.id !== undefined ? user.id : config.user.id + const userEmail = user.email !== undefined ? user.email : config.user.email + const userName = user.name !== undefined ? user.name : config.user.name + config = { ...config, user: { - ...config.user, - email: data.user.email || ((config && config.user) || {}).email, - name: data.user.name || ((config && config.user) || {}).name + id: userId, + email: userEmail, + name: userName } }; trackEvent(config, 'setUser', { oldUserId: getUserIdCookie() }); diff --git a/test/tracker-component.test.js b/test/tracker-component.test.js index 7199b83c..c0cbf31e 100644 --- a/test/tracker-component.test.js +++ b/test/tracker-component.test.js @@ -462,9 +462,9 @@ describe('paypal.Tracker', () => { JSON.stringify({ oldUserId: 'abc123', user: { + id: 'abc123', email: '__test__email9', name: '__test__userName9', - id: 'abc123' }, propertyId, trackingType: 'setUser', @@ -496,9 +496,9 @@ describe('paypal.Tracker', () => { JSON.stringify({ oldUserId: 'abc123', user: { + id: 'abc123', email: '__test__email@gmail.com', name: '__test__name', - id: 'abc123' }, propertyId, trackingType: 'setUser', @@ -544,9 +544,9 @@ describe('paypal.Tracker', () => { currencyCode: 'USD', cartEventType: 'addToCart', user: { + id: 'abc123', email: '__test__email2', name: '__test__name1', - id: 'abc123' }, propertyId, trackingType: 'cartEvent', diff --git a/test/tracker/set-user.test.js b/test/tracker/set-user.test.js index 2345587c..5bca585d 100644 --- a/test/tracker/set-user.test.js +++ b/test/tracker/set-user.test.js @@ -1,44 +1,196 @@ -/* global it describe beforeEach expect */ +/* global it describe beforeEach expect jest */ /* @flow */ import { Tracker } from '../../src/tracker-component'; +import { getPropertyId } from '../../src/lib/get-property-id'; +import { track } from '../../src/lib/track'; + +import constants from '../../src/lib/constants'; + +jest.mock('../../src/lib/track') +jest.mock('../../src/lib/get-property-id', () => { + return { + getPropertyId: async () => 'mockpropertyidofsomekind' + } +}) describe('setUser', () => { + const { defaultTrackerConfig } = constants + let config; + let mockItem; beforeEach(() => { config = { + propertyId: 'foobar', user: { - // id: 'arglebargle123', + id: 'arglebargle123', name: 'Bob Ross', email: 'bossrob21@pbs.org' } }; + + mockItem = { + id: 'XL novelty hat', + imgUrl: 'https://www.paypalobjects.com/digitalassets/c/gifts/media/catalog/product/b/e/bestbuy.jpg', + price: '100.00', + title: 'Best Buy', + url: 'http://localhost.paypal.com:8080/us/gifts/brands/best-buy', + quantity: 1, + }; }); + afterEach(() => { + track.mockReset(); + window.localStorage.removeItem('paypal-cr-cart'); + window.localStorage.removeItem('paypal-cr-cart-expirty'); + }) + + afterAll(() => { + track.mockRestore(); + getPropertyId.mockRestore(); + }) + it('user should be set when the tracker is initialized', () => { - Tracker(config); + const tracker = Tracker(config); + let args + + tracker.addToCart({items: [mockItem]}) + tracker.removeFromCart({items: [mockItem]}) + + args = track.mock.calls - expect(true).toEqual(true); + expect(args[0][0].user).toEqual(config.user); + expect(args[1][0].user).toEqual(config.user); }); - // it('no user should be set if no user is passed to initialization', () => { - // expect(true).toEqual(false); - // }); + it('no user should be set if no configuration is passed to initialization', (done) => { + const tracker = Tracker(); + let args - // it('user should be set when set user is called', () => { - // expect(true).toEqual(false); - // }); + // wait for mock propertyId to resolve + setTimeout(() => { + tracker.addToCart({items: [mockItem]}) + tracker.removeFromCart({items: [mockItem]}) - // it('already-existing user should be updated when set user is called', () => { - // expect(true).toEqual(false); - // }); + args = track.mock.calls + expect(args[0][0].user).toEqual(defaultTrackerConfig.user); + expect(args[1][0].user).toEqual(defaultTrackerConfig.user); + done() + }, 100) + }); + + it('no user should be set if no user is passed to initialization', () => { + const tracker = Tracker({propertyId: 'somevalue'}); + let args + + tracker.addToCart({items: [mockItem]}) + tracker.removeFromCart({items: [mockItem]}) + + args = track.mock.calls + expect(args[0][0].user).toEqual(defaultTrackerConfig.user); + expect(args[1][0].user).toEqual(defaultTrackerConfig.user); + }); + + it('user should be set when set user is called', () => { + const tracker = Tracker({propertyId: 'somevalue'}); + let args + tracker.addToCart({items: [mockItem]}) + tracker.removeFromCart({items: [mockItem]}) - // it('setUser accepts different types of input', () => { - // expect(true).toEqual(false); - // }); + tracker.setUser(config.user) + tracker.addToCart({items: [mockItem]}) + tracker.removeFromCart({items: [mockItem]}) + + args = track.mock.calls + expect(args[0][0].user).toEqual(defaultTrackerConfig.user); + expect(args[1][0].user).toEqual(defaultTrackerConfig.user); + expect(args[2][0].user).toEqual(config.user); + expect(args[3][0].user).toEqual(config.user); + expect(args[4][0].user).toEqual(config.user); + }); - // it('user can be unset by passing null', () => { - // expect(true).toEqual(false); - // }); + it('already-existing user should be updated when set user is called', () => { + const alternateUser = { + id: 'wut', + name: 'Steve Jobs', + email: 'steve@apple.com' + } + + const tracker = Tracker(config); + let args + + tracker.addToCart({items: [mockItem]}) + tracker.removeFromCart({items: [mockItem]}) + + tracker.setUser(alternateUser) + tracker.addToCart({items: [mockItem]}) + tracker.removeFromCart({items: [mockItem]}) + + args = track.mock.calls + expect(args[0][0].user).toEqual(config.user); + expect(args[1][0].user).toEqual(config.user); + expect(args[2][0].user).toEqual(alternateUser); + expect(args[3][0].user).toEqual(alternateUser); + expect(args[4][0].user).toEqual(alternateUser); + }); + + + it('setUser accepts different types of input', () => { + const alternateUser = { + id: 'wut', + name: 'Steve Jobs', + email: 'steve@apple.com' + } + + const tracker = Tracker({propertyId: 'somevalue'}); + let args + + tracker.setUser(alternateUser) + tracker.addToCart({items: [mockItem]}) + tracker.removeFromCart({items: [mockItem]}) + + tracker.setUser({user: config.user}) + tracker.addToCart({items: [mockItem]}) + tracker.removeFromCart({items: [mockItem]}) + args = track.mock.calls + + expect(args[0][0].user).toEqual(alternateUser); + expect(args[1][0].user).toEqual(alternateUser); + expect(args[2][0].user).toEqual(alternateUser); + expect(args[3][0].user).toEqual(config.user); + expect(args[4][0].user).toEqual(config.user); + expect(args[5][0].user).toEqual(config.user); + }); + + it('user can be unset by passing null', () => { + const alternateUser = { + id: 'wut', + name: 'Steve Jobs', + email: 'steve@apple.com' + } + const tracker = Tracker(config); + let args + + tracker.setUser({ + id: null, + email: null, + name: null + }) + tracker.addToCart({items: [mockItem]}) + tracker.removeFromCart({items: [mockItem]}) + + tracker.setUser(alternateUser) + tracker.addToCart({items: [mockItem]}) + tracker.removeFromCart({items: [mockItem]}) + args = track.mock.calls + + expect(args[0][0].user).toEqual(defaultTrackerConfig.user); + expect(args[1][0].user).toEqual(defaultTrackerConfig.user); + expect(args[2][0].user).toEqual(defaultTrackerConfig.user); + + expect(args[3][0].user).toEqual(alternateUser); + expect(args[4][0].user).toEqual(alternateUser); + expect(args[5][0].user).toEqual(alternateUser); + }); });