From c7d83ccca72b6abd5ccc0fff1fbe4ddf33eb0c4a Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Wed, 11 Oct 2023 11:08:18 -0700 Subject: [PATCH] test: more client level tests --- .../test/browser-client.test.ts | 207 +++++++++++++----- .../analytics-core/src/plugins/destination.ts | 10 +- 2 files changed, 157 insertions(+), 60 deletions(-) diff --git a/packages/analytics-browser/test/browser-client.test.ts b/packages/analytics-browser/test/browser-client.test.ts index 12f9e3711..1f9b8c16e 100644 --- a/packages/analytics-browser/test/browser-client.test.ts +++ b/packages/analytics-browser/test/browser-client.test.ts @@ -262,64 +262,161 @@ describe('browser-client', () => { expect(webAttributionPluginPlugin).toHaveBeenCalledTimes(1); }); - test.each([ - ['api_key', undefined, core.INVALID_OR_MISSING_FIELDS_DIAGNOSTIC_MESSAGE], - [undefined, { time: [0] }, core.EVENT_ERROR_DIAGNOSTIC_MESSAGE], - ])('should diagnostic track when 400 invalid response', async (missingField, eventsWithInvalidFields, message) => { - const transportProvider = { - send: jest.fn().mockImplementationOnce(() => { - return Promise.resolve({ - status: Status.Invalid, - statusCode: 400, - body: { - error: 'error', - missingField: missingField, - eventsWithInvalidFields: eventsWithInvalidFields, - eventsWithMissingFields: {}, - eventsWithInvalidIdLengths: {}, - silencedEvents: [], - }, - }); - }), - }; + describe('diagnostic', () => { + test('should not diagnostic track when 200', async () => { + const transportProvider = { + send: jest.fn().mockImplementationOnce(() => { + return Promise.resolve({ + status: Status.Success, + statusCode: 200, + }); + }), + }; + + await client.init(apiKey, { + defaultTracking: false, + }).promise; + const diagnosticTrack = jest.spyOn(client.config.diagnosticProvider as Diagnostic, 'track'); + client.config.transportProvider = transportProvider; + await client.track('event_type', { userId: 'user_0' }).promise; + + expect(diagnosticTrack).toHaveBeenCalledTimes(0); + }); - await client.init(apiKey, { - defaultTracking: false, - }).promise; - const diagnosticTrack = jest.spyOn(client.config.diagnosticProvider as Diagnostic, 'track'); - client.config.transportProvider = transportProvider; - await client.track('event_type', { userId: 'user_0' }).promise; - - expect(diagnosticTrack).toHaveBeenCalledTimes(1); - expect(diagnosticTrack).toHaveBeenCalledWith(1, 400, message); - }); - - test('should diagnostic track when 429 rate limit when flush', async () => { - const transportProvider = { - send: jest.fn().mockImplementationOnce(() => { - return Promise.resolve({ - status: Status.RateLimit, - statusCode: 429, - body: { - exceededDailyQuotaUsers: { user_0: 1 }, - exceededDailyQuotaDevices: {}, - throttledEvents: [], - }, - }); - }), - }; + test.each([null, new Error()])('should diagnostic track when 0 unexpected error', async (res) => { + const transportProvider = { + send: jest.fn().mockImplementationOnce(() => { + return Promise.resolve(res); + }), + }; + + await client.init(apiKey, { + defaultTracking: false, + }).promise; + const diagnosticTrack = jest.spyOn(client.config.diagnosticProvider as Diagnostic, 'track'); + client.config.transportProvider = transportProvider; + await client.track('event_type', { userId: 'user_0' }).promise; + + expect(diagnosticTrack).toHaveBeenCalledTimes(1); + expect(diagnosticTrack).toHaveBeenCalledWith(1, 0, core.UNEXPECTED_DIAGNOSTIC_MESSAGE); + }); - await client.init(apiKey, { - defaultTracking: false, - }).promise; - const diagnosticTrack = jest.spyOn(client.config.diagnosticProvider as Diagnostic, 'track'); - client.config.transportProvider = transportProvider; - client.track('event_type', { userId: 'user_0' }); - // flush() calls destination.flush(useRetry: false) - await client.flush().promise; + test.each([ + ['api_key', undefined, core.INVALID_OR_MISSING_FIELDS_DIAGNOSTIC_MESSAGE], + [undefined, { time: [0] }, core.EVENT_ERROR_DIAGNOSTIC_MESSAGE], + ])( + 'should diagnostic track when 400 invalid response', + async (missingField, eventsWithInvalidFields, message) => { + const transportProvider = { + send: jest.fn().mockImplementationOnce(() => { + return Promise.resolve({ + status: Status.Invalid, + statusCode: 400, + body: { + error: 'error', + missingField: missingField, + eventsWithInvalidFields: eventsWithInvalidFields, + eventsWithMissingFields: {}, + eventsWithInvalidIdLengths: {}, + silencedEvents: [], + }, + }); + }), + }; + + await client.init(apiKey, { + defaultTracking: false, + }).promise; + const diagnosticTrack = jest.spyOn(client.config.diagnosticProvider as Diagnostic, 'track'); + client.config.transportProvider = transportProvider; + await client.track('event_type', { userId: 'user_0' }).promise; + + expect(diagnosticTrack).toHaveBeenCalledTimes(1); + expect(diagnosticTrack).toHaveBeenCalledWith(1, 400, message); + }, + ); - expect(diagnosticTrack).toHaveBeenCalledTimes(1); - expect(diagnosticTrack).toHaveBeenCalledWith(1, 429, core.EXCEEDED_DAILY_QUOTA_DIAGNOSTIC_MESSAGE); + test('should diagnostic track when 429 rate limit when flush', async () => { + const transportProvider = { + send: jest.fn().mockImplementationOnce(() => { + return Promise.resolve({ + status: Status.RateLimit, + statusCode: 429, + body: { + exceededDailyQuotaUsers: { user_0: 1 }, + exceededDailyQuotaDevices: {}, + throttledEvents: [], + }, + }); + }), + }; + + await client.init(apiKey, { + defaultTracking: false, + }).promise; + const diagnosticTrack = jest.spyOn(client.config.diagnosticProvider as Diagnostic, 'track'); + client.config.transportProvider = transportProvider; + client.track('event_type', { userId: 'user_0' }); + // flush() calls destination.flush(useRetry: false) + await client.flush().promise; + + expect(diagnosticTrack).toHaveBeenCalledTimes(1); + expect(diagnosticTrack).toHaveBeenCalledWith(1, 429, core.EXCEEDED_DAILY_QUOTA_DIAGNOSTIC_MESSAGE); + }); + + test('should diagnostic track when 413', async () => { + const transportProvider = { + send: jest.fn().mockImplementationOnce(() => { + return Promise.resolve({ + status: Status.PayloadTooLarge, + statusCode: 413, + body: { + error: 'error', + }, + }); + }), + }; + + await client.init(apiKey, { + defaultTracking: false, + }).promise; + const diagnosticTrack = jest.spyOn(client.config.diagnosticProvider as Diagnostic, 'track'); + client.config.transportProvider = transportProvider; + await client.track('event_type', { userId: 'user_0' }).promise; + + expect(diagnosticTrack).toHaveBeenCalledTimes(1); + expect(diagnosticTrack).toHaveBeenCalledWith(1, 413, core.PAYLOAD_TOO_LARGE_DIAGNOSTIC_MESSAGE); + }); + + test('should diagnostic track when 500 hit max retries', async () => { + const transportProvider = { + send: jest.fn().mockImplementationOnce(() => { + return Promise.resolve({ + status: Status.Invalid, + statusCode: 400, + body: { + error: 'error', + missingField: '', + eventsWithInvalidFields: {}, + eventsWithMissingFields: {}, + eventsWithInvalidIdLengths: {}, + silencedEvents: [], + }, + }); + }), + }; + + await client.init(apiKey, { + defaultTracking: false, + flushMaxRetries: 1, + }).promise; + const diagnosticTrack = jest.spyOn(client.config.diagnosticProvider as Diagnostic, 'track'); + client.config.transportProvider = transportProvider; + await client.track('event_type', { userId: 'user_0' }).promise; + + expect(diagnosticTrack).toHaveBeenCalledTimes(1); + expect(diagnosticTrack).toHaveBeenCalledWith(1, 500, core.EXCEEDED_MAX_RETRY_DIAGNOSTIC_MESSAGE); + }); }); }); diff --git a/packages/analytics-core/src/plugins/destination.ts b/packages/analytics-core/src/plugins/destination.ts index 1ec571742..88fb55815 100644 --- a/packages/analytics-core/src/plugins/destination.ts +++ b/packages/analytics-core/src/plugins/destination.ts @@ -229,13 +229,11 @@ export class Destination implements DestinationPlugin { ...res.body.silencedEvents, ].flat(); const dropIndexSet = new Set(dropIndex); - (this.config.diagnosticProvider as Diagnostic).track( - useRetry ? dropIndexSet.size : list.length, - 400, - EVENT_ERROR_DIAGNOSTIC_MESSAGE, - ); if (useRetry) { + if (dropIndexSet.size) { + (this.config.diagnosticProvider as Diagnostic).track(dropIndexSet.size, 400, EVENT_ERROR_DIAGNOSTIC_MESSAGE); + } const retry = list.filter((context, index) => { if (dropIndexSet.has(index)) { this.fulfillRequest([context], res.statusCode, res.body.error); @@ -249,6 +247,8 @@ export class Destination implements DestinationPlugin { this.config.loggerProvider.warn(getResponseBodyString(res)); } this.addToQueue(...retry); + } else { + (this.config.diagnosticProvider as Diagnostic).track(list.length, 400, EVENT_ERROR_DIAGNOSTIC_MESSAGE); } }