From b81f337e1654fc0d254c5485e5d342271498cadb Mon Sep 17 00:00:00 2001 From: opercy Date: Thu, 22 Jan 2026 17:23:02 -0600 Subject: [PATCH 1/3] remove usage of stale treatment if expired & remove adding deviceID from localstorage to merchant storage --- src/library/zoid/treatments/component.js | 8 +-- src/utils/experiments.js | 1 + tests/unit/spec/src/utils/experiments.test.js | 50 +++++++++++++++++-- .../src/zoid/treatments/component.test.js | 3 +- 4 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/library/zoid/treatments/component.js b/src/library/zoid/treatments/component.js index 987f6fd47a..de7d53bfa8 100644 --- a/src/library/zoid/treatments/component.js +++ b/src/library/zoid/treatments/component.js @@ -71,17 +71,13 @@ export default createGlobalVariableGetter('__paypal_credit_treatments__', () => // 15 minutes in milliseconds const TREATMENTS_MAX_AGE = 1000 * 60 * 15; - return ({ treatmentsHash, deviceID }) => { + return ({ treatmentsHash }) => { updateStorage({ experiments: { treatmentsHash, // Experiments can only be maintained for 15 minutes expiration: Date.now() + TREATMENTS_MAX_AGE - }, - // Write deviceID from paypal.com localStorage to merchant domain localStorage - // This should be the only place that we write to the storage.id - // to prevent it getting out of sync with treatmentsHash - id: deviceID + } }); globalEvent.trigger('treatments'); diff --git a/src/utils/experiments.js b/src/utils/experiments.js index ef90d5d49e..44e615f778 100644 --- a/src/utils/experiments.js +++ b/src/utils/experiments.js @@ -31,6 +31,7 @@ export function getLocalTreatments() { } else { fetchTreatments(); } + return null; } return experiments.treatmentsHash; diff --git a/tests/unit/spec/src/utils/experiments.test.js b/tests/unit/spec/src/utils/experiments.test.js index a6a84f16a5..24c3ca6bc4 100644 --- a/tests/unit/spec/src/utils/experiments.test.js +++ b/tests/unit/spec/src/utils/experiments.test.js @@ -1,4 +1,4 @@ -import { ensureTreatments, getNamespace, globalEvent } from '../../../../../src/utils'; +import { ensureTreatments, getLocalTreatments, getNamespace, globalEvent } from '../../../../../src/utils'; jest.mock('../../../../../src/utils/global', () => { const global = jest.requireActual('../../../../../src/utils/global'); @@ -93,9 +93,9 @@ describe('experiments utils', () => { ensureTreatments(); - expect(globalEvent.trigger).toHaveBeenCalledWith('treatments'); + expect(globalEvent.trigger).not.toHaveBeenCalledWith('treatments'); - // treatment refresh should be triggered in the background + // treatment refresh should be triggered to get fresh data expect(document.querySelector('iframe')).not.toBeNull(); }); @@ -107,4 +107,48 @@ describe('experiments utils', () => { // treatments should not be marked ready expect(globalEvent.trigger).not.toHaveBeenCalled(); }); + + test('Returns null for stale treatments instead of stale value', () => { + // Set up expired treatments in localStorage + window.localStorage.setItem( + localStorageKey, + JSON.stringify({ + experiments: { + treatmentsHash, + expiration: new Date(1999, 0, 1).getTime() // Expired date + } + }) + ); + + // Call getLocalTreatments and verify it returns null for stale data + const result = getLocalTreatments(); + + // Should return null instead of the stale treatmentsHash + expect(result).toBeNull(); + + // Should trigger background fetch of new treatments + expect(document.querySelector('iframe')).not.toBeNull(); + }); + + test('Returns treatmentsHash for fresh treatments', () => { + // Set up fresh treatments in localStorage + window.localStorage.setItem( + localStorageKey, + JSON.stringify({ + experiments: { + treatmentsHash, + expiration: new Date(9999, 0, 1).getTime() // Future date + } + }) + ); + + // Call getLocalTreatments and verify it returns the hash + const result = getLocalTreatments(); + + // Should return the treatmentsHash for fresh data + expect(result).toBe(treatmentsHash); + + // Should NOT trigger a fetch since data is fresh + expect(document.querySelector('iframe')).toBeNull(); + }); }); diff --git a/tests/unit/spec/src/zoid/treatments/component.test.js b/tests/unit/spec/src/zoid/treatments/component.test.js index fd4746c306..619b1811f9 100644 --- a/tests/unit/spec/src/zoid/treatments/component.test.js +++ b/tests/unit/spec/src/zoid/treatments/component.test.js @@ -33,8 +33,7 @@ describe('treatments component', () => { experiments: { treatmentsHash, expiration: expect.any(Number) - }, - id: deviceID + } }); expect(globalEvent.trigger).toHaveBeenCalledWith('treatments'); From 1e685d2c0df24f8b3daa6ed21ec7a136ab4e2a5e Mon Sep 17 00:00:00 2001 From: opercy Date: Thu, 22 Jan 2026 17:29:06 -0600 Subject: [PATCH 2/3] remove duplicate test --- tests/unit/spec/src/utils/experiments.test.js | 46 +------------------ 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/tests/unit/spec/src/utils/experiments.test.js b/tests/unit/spec/src/utils/experiments.test.js index 24c3ca6bc4..78259d0683 100644 --- a/tests/unit/spec/src/utils/experiments.test.js +++ b/tests/unit/spec/src/utils/experiments.test.js @@ -1,4 +1,4 @@ -import { ensureTreatments, getLocalTreatments, getNamespace, globalEvent } from '../../../../../src/utils'; +import { ensureTreatments, getNamespace, globalEvent } from '../../../../../src/utils'; jest.mock('../../../../../src/utils/global', () => { const global = jest.requireActual('../../../../../src/utils/global'); @@ -107,48 +107,4 @@ describe('experiments utils', () => { // treatments should not be marked ready expect(globalEvent.trigger).not.toHaveBeenCalled(); }); - - test('Returns null for stale treatments instead of stale value', () => { - // Set up expired treatments in localStorage - window.localStorage.setItem( - localStorageKey, - JSON.stringify({ - experiments: { - treatmentsHash, - expiration: new Date(1999, 0, 1).getTime() // Expired date - } - }) - ); - - // Call getLocalTreatments and verify it returns null for stale data - const result = getLocalTreatments(); - - // Should return null instead of the stale treatmentsHash - expect(result).toBeNull(); - - // Should trigger background fetch of new treatments - expect(document.querySelector('iframe')).not.toBeNull(); - }); - - test('Returns treatmentsHash for fresh treatments', () => { - // Set up fresh treatments in localStorage - window.localStorage.setItem( - localStorageKey, - JSON.stringify({ - experiments: { - treatmentsHash, - expiration: new Date(9999, 0, 1).getTime() // Future date - } - }) - ); - - // Call getLocalTreatments and verify it returns the hash - const result = getLocalTreatments(); - - // Should return the treatmentsHash for fresh data - expect(result).toBe(treatmentsHash); - - // Should NOT trigger a fetch since data is fresh - expect(document.querySelector('iframe')).toBeNull(); - }); }); From 359e01f25bccbc6e290cfeeb405ba34d083cd89b Mon Sep 17 00:00:00 2001 From: opercy Date: Fri, 23 Jan 2026 10:06:14 -0600 Subject: [PATCH 3/3] revert commenting out deviceID from treatments/components --- src/library/zoid/treatments/component.js | 8 ++++++-- tests/unit/spec/src/zoid/treatments/component.test.js | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/library/zoid/treatments/component.js b/src/library/zoid/treatments/component.js index de7d53bfa8..987f6fd47a 100644 --- a/src/library/zoid/treatments/component.js +++ b/src/library/zoid/treatments/component.js @@ -71,13 +71,17 @@ export default createGlobalVariableGetter('__paypal_credit_treatments__', () => // 15 minutes in milliseconds const TREATMENTS_MAX_AGE = 1000 * 60 * 15; - return ({ treatmentsHash }) => { + return ({ treatmentsHash, deviceID }) => { updateStorage({ experiments: { treatmentsHash, // Experiments can only be maintained for 15 minutes expiration: Date.now() + TREATMENTS_MAX_AGE - } + }, + // Write deviceID from paypal.com localStorage to merchant domain localStorage + // This should be the only place that we write to the storage.id + // to prevent it getting out of sync with treatmentsHash + id: deviceID }); globalEvent.trigger('treatments'); diff --git a/tests/unit/spec/src/zoid/treatments/component.test.js b/tests/unit/spec/src/zoid/treatments/component.test.js index 619b1811f9..fd4746c306 100644 --- a/tests/unit/spec/src/zoid/treatments/component.test.js +++ b/tests/unit/spec/src/zoid/treatments/component.test.js @@ -33,7 +33,8 @@ describe('treatments component', () => { experiments: { treatmentsHash, expiration: expect.any(Number) - } + }, + id: deviceID }); expect(globalEvent.trigger).toHaveBeenCalledWith('treatments');