From 8753a421b1f9c46400a0b202fcbbb89c34d2106e Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Tue, 7 Apr 2026 14:36:54 +0100 Subject: [PATCH 1/6] exclude values when null --- src/libs/prepareRequestPayload/index.native.ts | 2 +- src/libs/prepareRequestPayload/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/prepareRequestPayload/index.native.ts b/src/libs/prepareRequestPayload/index.native.ts index d84c505f0618..bfb6a5e0b1d7 100644 --- a/src/libs/prepareRequestPayload/index.native.ts +++ b/src/libs/prepareRequestPayload/index.native.ts @@ -16,7 +16,7 @@ const prepareRequestPayload: PrepareRequestPayload = (command, data, initiatedOf promiseChain = promiseChain.then(() => { const value = data[key]; - if (value === undefined) { + if (value === undefined || value === null) { return Promise.resolve(); } diff --git a/src/libs/prepareRequestPayload/index.ts b/src/libs/prepareRequestPayload/index.ts index 1dda836375d6..2963f5310cd3 100644 --- a/src/libs/prepareRequestPayload/index.ts +++ b/src/libs/prepareRequestPayload/index.ts @@ -10,7 +10,7 @@ const prepareRequestPayload: PrepareRequestPayload = (command, data) => { for (const key of Object.keys(data)) { const value = data[key]; - if (value === undefined) { + if (value === undefined || value === null) { continue; } From b845b821fd6ba4476f04f019de1a11e492536892 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Tue, 7 Apr 2026 14:38:20 +0100 Subject: [PATCH 2/6] add test file for prepareRequestPayload --- tests/unit/prepareRequestPayloadTest.ts | 75 +++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 tests/unit/prepareRequestPayloadTest.ts diff --git a/tests/unit/prepareRequestPayloadTest.ts b/tests/unit/prepareRequestPayloadTest.ts new file mode 100644 index 000000000000..e66d759844ba --- /dev/null +++ b/tests/unit/prepareRequestPayloadTest.ts @@ -0,0 +1,75 @@ +import prepareRequestPayload from '@libs/prepareRequestPayload'; + +describe('prepareRequestPayload', () => { + it('should append string values to FormData', async () => { + const formData = await prepareRequestPayload('TestCommand', {authToken: 'abc123', email: 'test@example.com'}, false); + + expect(formData.get('authToken')).toBe('abc123'); + expect(formData.get('email')).toBe('test@example.com'); + }); + + it('should omit null values from FormData instead of coercing them to the string "null"', async () => { + const formData = await prepareRequestPayload('TestCommand', {authToken: null, email: null, referer: 'ecash'}, false); + + expect(formData.has('authToken')).toBe(false); + expect(formData.has('email')).toBe(false); + expect(formData.get('referer')).toBe('ecash'); + }); + + it('should omit undefined values from FormData', async () => { + const formData = await prepareRequestPayload('TestCommand', {authToken: undefined, platform: 'web'}, false); + + expect(formData.has('authToken')).toBe(false); + expect(formData.get('platform')).toBe('web'); + }); + + it('should include falsy non-null/undefined values (0, false, empty string)', async () => { + const formData = await prepareRequestPayload('TestCommand', {count: 0, flag: false, label: ''}, false); + + expect(formData.get('count')).toBe('0'); + expect(formData.get('flag')).toBe('false'); + expect(formData.get('label')).toBe(''); + }); + + it('should warn when an unsupported object value is passed', async () => { + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); + + await prepareRequestPayload('TestCommand', {badParam: {nested: 'object'}}, false); + + expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("An unsupported value was passed to command 'TestCommand' (parameter: 'badParam')")); + warnSpy.mockRestore(); + }); + + it('should not warn for valid primitive values', async () => { + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); + + await prepareRequestPayload('TestCommand', {str: 'hello', num: 42, bool: true}, false); + + expect(warnSpy).not.toHaveBeenCalled(); + warnSpy.mockRestore(); + }); + + it('should return an empty FormData when all values are null or undefined', async () => { + const formData = await prepareRequestPayload('TestCommand', {a: null, b: undefined}, false); + const entries = Array.from(formData.entries()); + + expect(entries).toHaveLength(0); + }); + + it('should return an empty FormData for an empty data object', async () => { + const formData = await prepareRequestPayload('TestCommand', {}, false); + const entries = Array.from(formData.entries()); + + expect(entries).toHaveLength(0); + }); + + it('should append Blob values without warning', async () => { + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); + const blob = new Blob(['file content'], {type: 'text/plain'}); + + await prepareRequestPayload('TestCommand', {file: blob}, false); + + expect(warnSpy).not.toHaveBeenCalled(); + warnSpy.mockRestore(); + }); +}); From aec962e9c03ed23660740e914039135fd924d5c7 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Tue, 7 Apr 2026 15:46:24 +0100 Subject: [PATCH 3/6] clean up tests --- tests/unit/prepareRequestPayloadTest.ts | 35 ------------------------- 1 file changed, 35 deletions(-) diff --git a/tests/unit/prepareRequestPayloadTest.ts b/tests/unit/prepareRequestPayloadTest.ts index e66d759844ba..45a05a481731 100644 --- a/tests/unit/prepareRequestPayloadTest.ts +++ b/tests/unit/prepareRequestPayloadTest.ts @@ -31,45 +31,10 @@ describe('prepareRequestPayload', () => { expect(formData.get('label')).toBe(''); }); - it('should warn when an unsupported object value is passed', async () => { - const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); - - await prepareRequestPayload('TestCommand', {badParam: {nested: 'object'}}, false); - - expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("An unsupported value was passed to command 'TestCommand' (parameter: 'badParam')")); - warnSpy.mockRestore(); - }); - - it('should not warn for valid primitive values', async () => { - const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); - - await prepareRequestPayload('TestCommand', {str: 'hello', num: 42, bool: true}, false); - - expect(warnSpy).not.toHaveBeenCalled(); - warnSpy.mockRestore(); - }); - - it('should return an empty FormData when all values are null or undefined', async () => { - const formData = await prepareRequestPayload('TestCommand', {a: null, b: undefined}, false); - const entries = Array.from(formData.entries()); - - expect(entries).toHaveLength(0); - }); - it('should return an empty FormData for an empty data object', async () => { const formData = await prepareRequestPayload('TestCommand', {}, false); const entries = Array.from(formData.entries()); expect(entries).toHaveLength(0); }); - - it('should append Blob values without warning', async () => { - const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); - const blob = new Blob(['file content'], {type: 'text/plain'}); - - await prepareRequestPayload('TestCommand', {file: blob}, false); - - expect(warnSpy).not.toHaveBeenCalled(); - warnSpy.mockRestore(); - }); }); From cc00f8abe534b3d77300884db0d59085d6e906dd Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Tue, 7 Apr 2026 17:15:59 +0100 Subject: [PATCH 4/6] use waitForBatchedUpdates --- tests/unit/prepareRequestPayloadTest.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/unit/prepareRequestPayloadTest.ts b/tests/unit/prepareRequestPayloadTest.ts index 45a05a481731..c46926e8bbe8 100644 --- a/tests/unit/prepareRequestPayloadTest.ts +++ b/tests/unit/prepareRequestPayloadTest.ts @@ -1,15 +1,18 @@ import prepareRequestPayload from '@libs/prepareRequestPayload'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; describe('prepareRequestPayload', () => { it('should append string values to FormData', async () => { - const formData = await prepareRequestPayload('TestCommand', {authToken: 'abc123', email: 'test@example.com'}, false); + const promise = prepareRequestPayload('TestCommand', {authToken: 'abc123', email: 'test@example.com'}, false); + const formData = await waitForBatchedUpdates().then(() => promise); expect(formData.get('authToken')).toBe('abc123'); expect(formData.get('email')).toBe('test@example.com'); }); it('should omit null values from FormData instead of coercing them to the string "null"', async () => { - const formData = await prepareRequestPayload('TestCommand', {authToken: null, email: null, referer: 'ecash'}, false); + const promise = prepareRequestPayload('TestCommand', {authToken: null, email: null, referer: 'ecash'}, false); + const formData = await waitForBatchedUpdates().then(() => promise); expect(formData.has('authToken')).toBe(false); expect(formData.has('email')).toBe(false); @@ -17,14 +20,16 @@ describe('prepareRequestPayload', () => { }); it('should omit undefined values from FormData', async () => { - const formData = await prepareRequestPayload('TestCommand', {authToken: undefined, platform: 'web'}, false); + const promise = prepareRequestPayload('TestCommand', {authToken: undefined, platform: 'web'}, false); + const formData = await waitForBatchedUpdates().then(() => promise); expect(formData.has('authToken')).toBe(false); expect(formData.get('platform')).toBe('web'); }); it('should include falsy non-null/undefined values (0, false, empty string)', async () => { - const formData = await prepareRequestPayload('TestCommand', {count: 0, flag: false, label: ''}, false); + const promise = prepareRequestPayload('TestCommand', {count: 0, flag: false, label: ''}, false); + const formData = await waitForBatchedUpdates().then(() => promise); expect(formData.get('count')).toBe('0'); expect(formData.get('flag')).toBe('false'); @@ -32,7 +37,8 @@ describe('prepareRequestPayload', () => { }); it('should return an empty FormData for an empty data object', async () => { - const formData = await prepareRequestPayload('TestCommand', {}, false); + const promise = prepareRequestPayload('TestCommand', {}, false); + const formData = await waitForBatchedUpdates().then(() => promise); const entries = Array.from(formData.entries()); expect(entries).toHaveLength(0); From 6c61b4268327e51fa4e6aadd4083148da6453a24 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Tue, 7 Apr 2026 17:45:57 +0100 Subject: [PATCH 5/6] try useRealTimers --- tests/unit/prepareRequestPayloadTest.ts | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/unit/prepareRequestPayloadTest.ts b/tests/unit/prepareRequestPayloadTest.ts index c46926e8bbe8..6ff77452dde2 100644 --- a/tests/unit/prepareRequestPayloadTest.ts +++ b/tests/unit/prepareRequestPayloadTest.ts @@ -1,18 +1,23 @@ import prepareRequestPayload from '@libs/prepareRequestPayload'; -import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; + +beforeAll(() => { + jest.useRealTimers(); +}); + +afterAll(() => { + jest.useFakeTimers(); +}); describe('prepareRequestPayload', () => { it('should append string values to FormData', async () => { - const promise = prepareRequestPayload('TestCommand', {authToken: 'abc123', email: 'test@example.com'}, false); - const formData = await waitForBatchedUpdates().then(() => promise); + const formData = await prepareRequestPayload('TestCommand', {authToken: 'abc123', email: 'test@example.com'}, false); expect(formData.get('authToken')).toBe('abc123'); expect(formData.get('email')).toBe('test@example.com'); }); it('should omit null values from FormData instead of coercing them to the string "null"', async () => { - const promise = prepareRequestPayload('TestCommand', {authToken: null, email: null, referer: 'ecash'}, false); - const formData = await waitForBatchedUpdates().then(() => promise); + const formData = await prepareRequestPayload('TestCommand', {authToken: null, email: null, referer: 'ecash'}, false); expect(formData.has('authToken')).toBe(false); expect(formData.has('email')).toBe(false); @@ -20,16 +25,14 @@ describe('prepareRequestPayload', () => { }); it('should omit undefined values from FormData', async () => { - const promise = prepareRequestPayload('TestCommand', {authToken: undefined, platform: 'web'}, false); - const formData = await waitForBatchedUpdates().then(() => promise); + const formData = await prepareRequestPayload('TestCommand', {authToken: undefined, platform: 'web'}, false); expect(formData.has('authToken')).toBe(false); expect(formData.get('platform')).toBe('web'); }); it('should include falsy non-null/undefined values (0, false, empty string)', async () => { - const promise = prepareRequestPayload('TestCommand', {count: 0, flag: false, label: ''}, false); - const formData = await waitForBatchedUpdates().then(() => promise); + const formData = await prepareRequestPayload('TestCommand', {count: 0, flag: false, label: ''}, false); expect(formData.get('count')).toBe('0'); expect(formData.get('flag')).toBe('false'); @@ -37,8 +40,7 @@ describe('prepareRequestPayload', () => { }); it('should return an empty FormData for an empty data object', async () => { - const promise = prepareRequestPayload('TestCommand', {}, false); - const formData = await waitForBatchedUpdates().then(() => promise); + const formData = await prepareRequestPayload('TestCommand', {}, false); const entries = Array.from(formData.entries()); expect(entries).toHaveLength(0); From b59748d34138bce9b823add646600ef27fe8d672 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Wed, 8 Apr 2026 21:28:13 +0100 Subject: [PATCH 6/6] fix test --- jest/setup.ts | 2 +- tests/unit/prepareRequestPayloadTest.ts | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/jest/setup.ts b/jest/setup.ts index f9a2fd198927..4528f7a4232b 100644 --- a/jest/setup.ts +++ b/jest/setup.ts @@ -292,7 +292,7 @@ jest.mock('@libs/prepareRequestPayload/index.native.ts', () => ({ for (const key of Object.keys(data)) { const value = data[key]; - if (value === undefined) { + if (value === undefined || value === null) { continue; } diff --git a/tests/unit/prepareRequestPayloadTest.ts b/tests/unit/prepareRequestPayloadTest.ts index 6ff77452dde2..45a05a481731 100644 --- a/tests/unit/prepareRequestPayloadTest.ts +++ b/tests/unit/prepareRequestPayloadTest.ts @@ -1,13 +1,5 @@ import prepareRequestPayload from '@libs/prepareRequestPayload'; -beforeAll(() => { - jest.useRealTimers(); -}); - -afterAll(() => { - jest.useFakeTimers(); -}); - describe('prepareRequestPayload', () => { it('should append string values to FormData', async () => { const formData = await prepareRequestPayload('TestCommand', {authToken: 'abc123', email: 'test@example.com'}, false);