Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion packages/analytics-core/src/core-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from './types/event/event';
import { IIdentify, OrderedIdentifyOperations } from './identify';
import { IRevenue } from './revenue';
import { CLIENT_NOT_INITIALIZED, OPT_OUT_MESSAGE } from './types/messages';
import { CLIENT_NOT_INITIALIZED, EMPTY_EVENT_TYPE_MESSAGE, OPT_OUT_MESSAGE } from './types/messages';
import { Timeline } from './timeline';
import {
createGroupEvent,
Expand Down Expand Up @@ -239,6 +239,14 @@ export class AmplitudeCore implements CoreClient, PluginHost {
return buildResult(event, 0, OPT_OUT_MESSAGE);
}

// The event server 400s a blank event type, which also forces the rest of its
// upload batch to be retried, so drop it before it ever reaches a destination.
const eventType: unknown = event.event_type;
if (typeof eventType !== 'string' || eventType.trim().length === 0) {
Comment thread
Mercy811 marked this conversation as resolved.
this.config.loggerProvider.warn(EMPTY_EVENT_TYPE_MESSAGE);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a warning or an error? I feel like this justifies an "error" because it's something customers will want surfaced quickly so they can take corrective action right away.

return buildResult(event, 0, EMPTY_EVENT_TYPE_MESSAGE);
}

if (event.event_type === SpecialEventType.IDENTIFY) {
// Do not update this.userProperties here.
// It is only set synchronously in identify() or setIdentity()
Expand Down
1 change: 1 addition & 0 deletions packages/analytics-core/src/types/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export const SUCCESS_MESSAGE = 'Event tracked successfully';
export const UNEXPECTED_ERROR_MESSAGE = 'Unexpected error occurred';
export const MAX_RETRIES_EXCEEDED_MESSAGE = 'Event rejected due to exceeded retry count';
export const OPT_OUT_MESSAGE = 'Event skipped due to optOut config';
export const EMPTY_EVENT_TYPE_MESSAGE = 'Event skipped due to empty event type';
export const MISSING_API_KEY_MESSAGE = 'Event rejected due to missing API key';
export const INVALID_API_KEY = 'Invalid API key';
export const CLIENT_NOT_INITIALIZED = 'Client not initialized';
34 changes: 33 additions & 1 deletion packages/analytics-core/test/core-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Event, IdentifyEvent, SpecialEventType, UserProperties } from '../src/t
import { Plugin, EnrichmentPlugin } from '../src/types/plugin';
import { Status } from '../src/types/status';
import { AmplitudeCore, Identify, Revenue } from '../src/index';
import { CLIENT_NOT_INITIALIZED, OPT_OUT_MESSAGE } from '../src/types/messages';
import { CLIENT_NOT_INITIALIZED, EMPTY_EVENT_TYPE_MESSAGE, OPT_OUT_MESSAGE } from '../src/types/messages';
import { useDefaultConfig } from './helpers/default';
import { IdentifyOperation } from '../src/identify';
import { UNSET_VALUE } from '../src/types/constants';
Expand Down Expand Up @@ -483,6 +483,38 @@ describe('core-client', () => {
expect(onIdentityChanged).toHaveBeenCalledTimes(1);
expect(onIdentityChanged).toHaveBeenCalledWith({ userProperties: undefined });
});

test.each([
['an empty', ''],
['a whitespace-only', ' '],
['a missing', undefined],
])('should drop an event with %s event type', async (_description, eventType) => {
const client = new AmplitudeCore();
const loggerProvider = { ...mockLoggerProvider, warn: jest.fn() };
client.config = { ...mockConfig, loggerProvider } as BrowserConfig;
const push = jest.spyOn(client.timeline, 'push');

const event = { event_type: eventType } as Event;
const result = await client.process(event);

expect(result).toEqual({ event, code: 0, message: EMPTY_EVENT_TYPE_MESSAGE });
expect(push).toHaveBeenCalledTimes(0);
expect(loggerProvider.warn).toHaveBeenCalledTimes(1);
expect(loggerProvider.warn).toHaveBeenCalledWith(EMPTY_EVENT_TYPE_MESSAGE);
});

test('should not drop an event with a valid event type', async () => {
const client = new AmplitudeCore();
const loggerProvider = { ...mockLoggerProvider, warn: jest.fn() };
client.config = { ...mockConfig, loggerProvider } as BrowserConfig;
const push = jest.spyOn(client.timeline, 'push').mockReturnValueOnce(Promise.resolve(success));

const result = await client.process({ event_type: 'event_type' });

expect(result).toBe(success);
expect(push).toHaveBeenCalledTimes(1);
expect(loggerProvider.warn).toHaveBeenCalledTimes(0);
});
});

describe('setOptOut', () => {
Expand Down
Loading