mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
114 lines
3.7 KiB
TypeScript
114 lines
3.7 KiB
TypeScript
jest.mock('expo-observe', () => ({
|
|
Observe: {
|
|
logEvent: jest.fn(),
|
|
},
|
|
}));
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
const { Observe } = require('expo-observe');
|
|
const logEventMock = Observe.logEvent as jest.Mock;
|
|
|
|
type ErrorHandler = (error: unknown, isFatal: boolean) => void;
|
|
|
|
function withFreshObserveModule<T>(run: (mod: typeof import('@/lib/observe')) => T): T {
|
|
let result!: T;
|
|
jest.isolateModules(() => {
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
const mod = require('@/lib/observe') as typeof import('@/lib/observe');
|
|
result = run(mod);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
function installFakeErrorUtils(previousHandler: jest.Mock) {
|
|
let installedHandler: ErrorHandler = () => undefined;
|
|
const globalWithErrorUtils = global as unknown as {
|
|
ErrorUtils: { getGlobalHandler: () => unknown; setGlobalHandler: (fn: unknown) => void };
|
|
};
|
|
globalWithErrorUtils.ErrorUtils = {
|
|
getGlobalHandler: () => previousHandler,
|
|
setGlobalHandler: (fn) => {
|
|
installedHandler = fn as ErrorHandler;
|
|
},
|
|
};
|
|
return () => installedHandler;
|
|
}
|
|
|
|
describe('observe', () => {
|
|
afterEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
it('logs app_started only once per module instance', () => {
|
|
withFreshObserveModule(({ logAppStarted }) => {
|
|
logAppStarted();
|
|
logAppStarted();
|
|
});
|
|
|
|
expect(logEventMock).toHaveBeenCalledTimes(1);
|
|
expect(logEventMock).toHaveBeenCalledWith('app_started');
|
|
});
|
|
|
|
it('does not throw when Observe.logEvent fails', () => {
|
|
logEventMock.mockImplementationOnce(() => {
|
|
throw new Error('native module unavailable');
|
|
});
|
|
|
|
withFreshObserveModule(({ logAppStarted }) => {
|
|
expect(() => logAppStarted()).not.toThrow();
|
|
});
|
|
});
|
|
|
|
it('wraps the previous ErrorUtils handler, logging xprem_js_crash and delegating', () => {
|
|
const previousHandler = jest.fn();
|
|
const getInstalledHandler = installFakeErrorUtils(previousHandler);
|
|
|
|
withFreshObserveModule(({ installObserveGlobalErrorHandler }) => {
|
|
installObserveGlobalErrorHandler();
|
|
});
|
|
|
|
const error = new Error('boom');
|
|
getInstalledHandler()(error, true);
|
|
|
|
expect(logEventMock).toHaveBeenCalledWith(
|
|
'xprem_js_crash',
|
|
expect.objectContaining({
|
|
severity: 'fatal',
|
|
body: 'boom',
|
|
})
|
|
);
|
|
expect(previousHandler).toHaveBeenCalledWith(error, true);
|
|
});
|
|
|
|
it('does not log xprem_js_crash for non-fatal errors but still delegates', () => {
|
|
const previousHandler = jest.fn();
|
|
const getInstalledHandler = installFakeErrorUtils(previousHandler);
|
|
|
|
withFreshObserveModule(({ installObserveGlobalErrorHandler }) => {
|
|
installObserveGlobalErrorHandler();
|
|
});
|
|
|
|
const error = new Error('handled');
|
|
getInstalledHandler()(error, false);
|
|
|
|
expect(logEventMock).not.toHaveBeenCalled();
|
|
expect(previousHandler).toHaveBeenCalledWith(error, false);
|
|
});
|
|
|
|
it('still calls the previous handler when Observe.logEvent throws', () => {
|
|
const previousHandler = jest.fn();
|
|
const getInstalledHandler = installFakeErrorUtils(previousHandler);
|
|
logEventMock.mockImplementationOnce(() => {
|
|
throw new Error('native module unavailable');
|
|
});
|
|
|
|
withFreshObserveModule(({ installObserveGlobalErrorHandler }) => {
|
|
installObserveGlobalErrorHandler();
|
|
});
|
|
|
|
getInstalledHandler()(new Error('boom'), true);
|
|
|
|
expect(previousHandler).toHaveBeenCalledWith(expect.any(Error), true);
|
|
});
|
|
});
|