-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
468 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
packages/telemetry/browser-telemetry/__tests__/singleton/singletonInstance.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { fallbackLogger } from '../../src/logging'; | ||
import { getTelemetryInstance, initTelemetry, resetTelemetryInstance } from '../../src/singleton'; | ||
|
||
beforeEach(() => { | ||
resetTelemetryInstance(); | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
it('warns and keeps existing instance when initialized multiple times', () => { | ||
const mockLogger = { | ||
error: jest.fn(), | ||
warn: jest.fn(), | ||
info: jest.fn(), | ||
debug: jest.fn(), | ||
}; | ||
|
||
initTelemetry({ logger: mockLogger }); | ||
const instanceA = getTelemetryInstance(); | ||
initTelemetry({ logger: mockLogger }); | ||
const instanceB = getTelemetryInstance(); | ||
|
||
expect(mockLogger.warn).toHaveBeenCalledWith( | ||
expect.stringMatching(/Telemetry has already been initialized/), | ||
); | ||
|
||
expect(instanceA).toBe(instanceB); | ||
}); | ||
|
||
it('warns when getting telemetry instance before initialization', () => { | ||
const spy = jest.spyOn(fallbackLogger, 'warn'); | ||
|
||
getTelemetryInstance(); | ||
|
||
expect(spy).toHaveBeenCalledWith(expect.stringMatching(/Telemetry has not been initialized/)); | ||
}); |
149 changes: 149 additions & 0 deletions
149
packages/telemetry/browser-telemetry/__tests__/singleton/singletonMethods.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import { Breadcrumb, LDClientTracking } from '../../src/api'; | ||
import { BrowserTelemetry } from '../../src/api/BrowserTelemetry'; | ||
import { BrowserTelemetryInspector } from '../../src/api/client/BrowserTelemetryInspector'; | ||
import { getTelemetryInstance } from '../../src/singleton/singletonInstance'; | ||
import { | ||
addBreadcrumb, | ||
captureError, | ||
captureErrorEvent, | ||
close, | ||
inspectors, | ||
register, | ||
} from '../../src/singleton/singletonMethods'; | ||
|
||
jest.mock('../../src/singleton/singletonInstance'); | ||
|
||
const mockTelemetry: jest.Mocked<BrowserTelemetry> = { | ||
inspectors: jest.fn(), | ||
captureError: jest.fn(), | ||
captureErrorEvent: jest.fn(), | ||
addBreadcrumb: jest.fn(), | ||
register: jest.fn(), | ||
close: jest.fn(), | ||
}; | ||
|
||
const mockGetTelemetryInstance = getTelemetryInstance as jest.Mock; | ||
|
||
beforeEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
it('returns empty array when telemetry is not initialized for inspectors', () => { | ||
mockGetTelemetryInstance.mockReturnValue(undefined); | ||
expect(() => inspectors()).not.toThrow(); | ||
expect(inspectors()).toEqual([]); | ||
}); | ||
|
||
it('returns inspectors when telemetry is initialized', () => { | ||
const mockInspectors: BrowserTelemetryInspector[] = [ | ||
{ name: 'test-inspector', type: 'flag-used', synchronous: true, method: () => {} }, | ||
]; | ||
mockGetTelemetryInstance.mockReturnValue(mockTelemetry); | ||
mockTelemetry.inspectors.mockReturnValue(mockInspectors); | ||
|
||
expect(inspectors()).toBe(mockInspectors); | ||
}); | ||
|
||
it('does not crash when calling captureError with no telemetry instance', () => { | ||
mockGetTelemetryInstance.mockReturnValue(undefined); | ||
const error = new Error('test error'); | ||
|
||
expect(() => captureError(error)).not.toThrow(); | ||
|
||
expect(mockTelemetry.captureError).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('captures errors when telemetry is initialized', () => { | ||
mockGetTelemetryInstance.mockReturnValue(mockTelemetry); | ||
const error = new Error('test error'); | ||
|
||
captureError(error); | ||
|
||
expect(mockTelemetry.captureError).toHaveBeenCalledWith(error); | ||
}); | ||
|
||
it('it does not crash when calling captureErrorEvent with no telemetry instance', () => { | ||
mockGetTelemetryInstance.mockReturnValue(undefined); | ||
const errorEvent = new ErrorEvent('error', { error: new Error('test error') }); | ||
|
||
expect(() => captureErrorEvent(errorEvent)).not.toThrow(); | ||
|
||
expect(mockTelemetry.captureErrorEvent).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('captures error event when telemetry is initialized', () => { | ||
mockGetTelemetryInstance.mockReturnValue(mockTelemetry); | ||
const errorEvent = new ErrorEvent('error', { error: new Error('test error') }); | ||
|
||
captureErrorEvent(errorEvent); | ||
|
||
expect(mockTelemetry.captureErrorEvent).toHaveBeenCalledWith(errorEvent); | ||
}); | ||
|
||
it('does not crash when calling addBreadcrumb with no telemetry instance', () => { | ||
mockGetTelemetryInstance.mockReturnValue(undefined); | ||
const breadcrumb: Breadcrumb = { | ||
type: 'custom', | ||
data: { test: 'data' }, | ||
timestamp: Date.now(), | ||
class: 'custom', | ||
level: 'info', | ||
}; | ||
|
||
expect(() => addBreadcrumb(breadcrumb)).not.toThrow(); | ||
|
||
expect(mockTelemetry.addBreadcrumb).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('adds breadcrumb when telemetry is initialized', () => { | ||
mockGetTelemetryInstance.mockReturnValue(mockTelemetry); | ||
const breadcrumb: Breadcrumb = { | ||
type: 'custom', | ||
data: { test: 'data' }, | ||
timestamp: Date.now(), | ||
class: 'custom', | ||
level: 'info', | ||
}; | ||
|
||
addBreadcrumb(breadcrumb); | ||
|
||
expect(mockTelemetry.addBreadcrumb).toHaveBeenCalledWith(breadcrumb); | ||
}); | ||
|
||
it('does not crash when calling register with no telemetry instance', () => { | ||
mockGetTelemetryInstance.mockReturnValue(undefined); | ||
const mockClient: jest.Mocked<LDClientTracking> = { | ||
track: jest.fn(), | ||
}; | ||
|
||
expect(() => register(mockClient)).not.toThrow(); | ||
|
||
expect(mockTelemetry.register).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('registers client when telemetry is initialized', () => { | ||
mockGetTelemetryInstance.mockReturnValue(mockTelemetry); | ||
const mockClient: jest.Mocked<LDClientTracking> = { | ||
track: jest.fn(), | ||
}; | ||
|
||
register(mockClient); | ||
|
||
expect(mockTelemetry.register).toHaveBeenCalledWith(mockClient); | ||
}); | ||
|
||
it('does not crash when calling close with no telemetry instance', () => { | ||
mockGetTelemetryInstance.mockReturnValue(undefined); | ||
|
||
expect(() => close()).not.toThrow(); | ||
|
||
expect(mockTelemetry.close).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('closes when telemetry is initialized', () => { | ||
mockGetTelemetryInstance.mockReturnValue(mockTelemetry); | ||
|
||
close(); | ||
|
||
expect(mockTelemetry.close).toHaveBeenCalled(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
packages/telemetry/browser-telemetry/src/api/client/BrowserTelemetryInspector.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/** | ||
* A less constrained version of the LDInspection interface in order to allow for greater compatibility between | ||
* SDK versions. | ||
* | ||
* This interface is not intended for use by application developers and is instead intended as a compatibility bridge | ||
* to support multiple SDK versions. | ||
*/ | ||
export interface BrowserTelemetryInspector { | ||
/** | ||
* The telemetry package only requires flag-detail-changed inspectors and flag-used inspectors. | ||
*/ | ||
type: 'flag-used' | 'flag-detail-changed'; | ||
|
||
/** | ||
* The name of the inspector, used for debugging purposes. | ||
*/ | ||
name: string; | ||
/** | ||
* Whether the inspector is synchronous. | ||
*/ | ||
synchronous: boolean; | ||
/** | ||
* The method to call when the inspector is triggered. | ||
* | ||
* The typing here is intentionally loose to allow for greater compatibility between SDK versions. | ||
* This function should ONLY be called by an SDK instance and not by an application developer. | ||
*/ | ||
method: (...args: any[]) => void; | ||
} |
Oops, something went wrong.