diff --git a/package.json b/package.json index 3c58cdccf..625d8e62c 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,8 @@ ], "moduleNameMapper": { "^flipper$": "/src/index.tsx" - } + }, + "clearMocks": true }, "devDependencies": { "@jest-runner/electron": "^2.0.1", diff --git a/src/fb-stubs/__mocks__/Logger.tsx b/src/fb-stubs/__mocks__/Logger.tsx index f6ee86300..d6504f851 100644 --- a/src/fb-stubs/__mocks__/Logger.tsx +++ b/src/fb-stubs/__mocks__/Logger.tsx @@ -9,7 +9,16 @@ import {Store} from '../../reducers/index'; import {getStringFromErrorLike} from '../../utils/errors'; -import {Args, Logger, TrackType} from '../../fb-interfaces/Logger'; +import {Args, Logger} from '../../fb-interfaces/Logger'; + +const instance = { + track: jest.fn(), + trackTimeSince: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + debug: jest.fn(), +}; export function extractError( ...data: Array @@ -22,30 +31,10 @@ export function extractError( }; } -export class FBLogger implements Logger { - constructor(_store?: Store, _args?: Args) {} - - track(_type: TrackType, _event: string, _data?: any, _plugin?: string) {} - - trackTimeSince(_mark: string, _eventName?: string) {} - - info = (..._data: Array) => {}; - - warn = (..._data: Array) => {}; - - error = (..._data: Array) => {}; - - debug = (..._data: Array) => {}; - - getLogs(): Array { - return []; - } -} - export function init(_store: Store, _args?: Args): Logger { - return new FBLogger(); + return instance; } export function getInstance(): Logger { - return new FBLogger(); + return instance; } diff --git a/src/utils/__tests__/metrics.node.tsx b/src/utils/__tests__/metrics.node.tsx new file mode 100644 index 000000000..3051ef3c5 --- /dev/null +++ b/src/utils/__tests__/metrics.node.tsx @@ -0,0 +1,146 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +jest.mock('../../fb-stubs/Logger'); +try { + jest.mock('../../fb/Logger'); +} catch { + // Allowed to fail when fb modules are not present. +} + +import {reportPlatformFailures, reportPluginFailures} from '../metrics'; +import {getInstance} from '../../fb/Logger'; +import {CancelledPromiseError} from '../errors'; +import {mocked} from 'ts-jest/utils'; + +const logger = mocked(getInstance()); + +test('reportPlatformFailures logs failures correctly', async () => { + await reportPlatformFailures( + Promise.reject(new Error('Broken Feature')), + 'test-event', + ).catch(() => { + // This is expected to throw + }); + + expect(logger.track.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "success-rate", + "test-event", + Object { + "error": "Broken Feature", + "supportedOperation": 1, + "value": 0, + }, + ], + ] + `); +}); + +test('reportPlatformFailures logs cancelled operations correctly', async () => { + await reportPlatformFailures( + Promise.reject(new CancelledPromiseError('Operation cancelled')), + 'test-event', + ).catch(() => { + // This is expected to throw + }); + + expect(logger.track.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "operation-cancelled", + "test-event", + ], + ] + `); +}); + +test('reportPlatformFailures logs success correctly', async () => { + await reportPlatformFailures(Promise.resolve('woohoo!'), 'test-event'); + + expect(logger.track.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "success-rate", + "test-event", + Object { + "value": 1, + }, + ], + ] + `); +}); + +test('reportPluginFailures logs failures correctly', async () => { + await reportPluginFailures( + Promise.reject(new Error('Broken Feature')), + 'test-event', + 'test-plugin', + ).catch(() => { + // This is expected to throw + }); + + expect(logger.track.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "success-rate", + "test-event", + Object { + "error": "Broken Feature", + "supportedOperation": 1, + "value": 0, + }, + "test-plugin", + ], + ] + `); +}); + +test('reportPluginFailures logs cancelled operations correctly', async () => { + await reportPluginFailures( + Promise.reject(new CancelledPromiseError('Operation cancelled')), + 'test-event', + 'test-plugin', + ).catch(() => { + // This is expected to throw + }); + + expect(logger.track.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "operation-cancelled", + "test-event", + undefined, + "test-plugin", + ], + ] + `); +}); + +test('reportPluginFailures logs success correctly', async () => { + await reportPluginFailures( + Promise.resolve('woohoo!'), + 'test-event', + 'test-plugin', + ); + + expect(logger.track.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "success-rate", + "test-event", + Object { + "value": 1, + }, + "test-plugin", + ], + ] + `); +}); diff --git a/src/utils/metrics.tsx b/src/utils/metrics.tsx index fc8484f0c..a971b7a0c 100644 --- a/src/utils/metrics.tsx +++ b/src/utils/metrics.tsx @@ -73,11 +73,11 @@ export function reportPluginFailures( }, rejectionReason => { if (rejectionReason instanceof CancelledPromiseError) { - logPlatformSuccessRate(name, { + logPluginSuccessRate(name, plugin, { kind: 'cancelled', }); } else { - logPlatformSuccessRate(name, { + logPluginSuccessRate(name, plugin, { kind: 'failure', supportedOperation: !(rejectionReason instanceof UnsupportedError), error: rejectionReason,