177 lines
6.2 KiB
TypeScript
177 lines
6.2 KiB
TypeScript
import type { BaseHook, Logger, Provider} from '../src';
|
|
import { OpenFeature, DefaultLogger, SafeLogger } from '../src';
|
|
|
|
class MockedLogger implements Logger {
|
|
error = jest.fn();
|
|
warn = jest.fn();
|
|
info = jest.fn();
|
|
debug = jest.fn();
|
|
}
|
|
|
|
const BEFORE_HOOK_LOG_MESSAGE = 'in before hook';
|
|
const AFTER_HOOK_LOG_MESSAGE = 'in after hook';
|
|
const ERROR_HOOK_LOG_MESSAGE = 'in error hook';
|
|
const FINALLY_HOOK_LOG_MESSAGE = 'in finally hook';
|
|
|
|
const MOCK_HOOK: BaseHook = {
|
|
before: jest.fn((hookContext) => hookContext.logger.info(BEFORE_HOOK_LOG_MESSAGE)),
|
|
after: jest.fn((hookContext) => hookContext.logger.info(AFTER_HOOK_LOG_MESSAGE)),
|
|
error: jest.fn((hookContext) => hookContext.logger.info(ERROR_HOOK_LOG_MESSAGE)),
|
|
finally: jest.fn((hookContext) => hookContext.logger.info(FINALLY_HOOK_LOG_MESSAGE)),
|
|
};
|
|
|
|
const RESOLVE_BOOL_MESSAGE = 'resolving boolean value';
|
|
const RESOLVE_STRING_MESSAGE = 'resolving string value';
|
|
const RESOLVE_NUM_MESSAGE = 'resolving number value';
|
|
const RESOLVE_OBJECT_MESSAGE = 'resolving object value';
|
|
|
|
const MOCK_PROVIDER: Provider = {
|
|
metadata: { name: 'Mock Provider' },
|
|
resolveBooleanEvaluation: jest.fn((key, value, ctx, log) => {
|
|
log.info(RESOLVE_BOOL_MESSAGE);
|
|
return Promise.resolve({ value });
|
|
}),
|
|
resolveStringEvaluation: jest.fn((key, value, ctx, log) => {
|
|
log.info(RESOLVE_STRING_MESSAGE);
|
|
return Promise.resolve({ value });
|
|
}),
|
|
resolveNumberEvaluation: jest.fn((key, value, ctx, log) => {
|
|
log.info(RESOLVE_NUM_MESSAGE);
|
|
return Promise.resolve({ value });
|
|
}),
|
|
resolveObjectEvaluation: jest.fn((key, value, ctx, log) => {
|
|
log.info(RESOLVE_OBJECT_MESSAGE);
|
|
return Promise.resolve({ value });
|
|
}),
|
|
};
|
|
|
|
describe('Logger', () => {
|
|
beforeEach(() => {
|
|
OpenFeature.setProvider(MOCK_PROVIDER);
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await OpenFeature.clearProviders();
|
|
jest.clearAllMocks();
|
|
// Resetting the default logger on the singleton
|
|
OpenFeature['_logger'] = new DefaultLogger();
|
|
});
|
|
|
|
describe('Default Logger', () => {
|
|
describe('Default Logger Functionality', () => {
|
|
it('should call console error', () => {
|
|
const defaultLogger = new DefaultLogger();
|
|
const errorSpy = jest.spyOn(global.console, 'error').mockImplementation();
|
|
defaultLogger.error('error');
|
|
expect(errorSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call console warn', () => {
|
|
const defaultLogger = new DefaultLogger();
|
|
const warnSpy = jest.spyOn(global.console, 'warn').mockImplementation();
|
|
defaultLogger.warn('warn');
|
|
expect(warnSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should not call console info', () => {
|
|
const defaultLogger = new DefaultLogger();
|
|
const infoSpy = jest.spyOn(global.console, 'info').mockImplementation();
|
|
defaultLogger.info();
|
|
expect(infoSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should not call console debug', () => {
|
|
const defaultLogger = new DefaultLogger();
|
|
const debugSpy = jest.spyOn(global.console, 'debug').mockImplementation();
|
|
defaultLogger.debug();
|
|
expect(debugSpy).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Safe Logger', () => {
|
|
it('should use the default logger because the custom logger is missing a function', () => {
|
|
const errorSpy = jest.spyOn(global.console, 'error').mockImplementation();
|
|
const safeLogger = new SafeLogger({} as Logger);
|
|
|
|
expect(errorSpy).toBeCalledWith(
|
|
expect.objectContaining({ message: 'The provided logger is missing the error method.' }),
|
|
);
|
|
// Checking the private logger
|
|
expect(safeLogger['logger']).toBeInstanceOf(DefaultLogger);
|
|
});
|
|
|
|
it('should use the default logger when a custom logger throws', () => {
|
|
const innerLogger = {
|
|
error: jest.fn(() => {
|
|
throw new Error('Logger is invalid');
|
|
}),
|
|
warn: jest.fn(() => {
|
|
throw new Error('Logger is invalid');
|
|
}),
|
|
info: jest.fn(() => {
|
|
throw new Error('Logger is invalid');
|
|
}),
|
|
debug: jest.fn(() => {
|
|
throw new Error('Logger is invalid');
|
|
}),
|
|
};
|
|
const safeLogger = new SafeLogger(innerLogger);
|
|
|
|
expect(() => safeLogger.error()).not.toThrow();
|
|
expect(innerLogger.error).toHaveBeenCalled();
|
|
|
|
expect(() => safeLogger.warn()).not.toThrow();
|
|
expect(innerLogger.warn).toHaveBeenCalled();
|
|
|
|
expect(() => safeLogger.info()).not.toThrow();
|
|
expect(innerLogger.info).toHaveBeenCalled();
|
|
|
|
expect(() => safeLogger.debug()).not.toThrow();
|
|
expect(innerLogger.debug).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should create a safe logger', () => {
|
|
OpenFeature.setLogger({} as Logger);
|
|
expect(OpenFeature['_logger']).toBeInstanceOf(SafeLogger);
|
|
});
|
|
});
|
|
|
|
it('should provide a logger to the provider', async () => {
|
|
const client = OpenFeature.getClient();
|
|
const mockedLogger = new MockedLogger();
|
|
client.setLogger(mockedLogger);
|
|
await client.getBooleanValue('test', false);
|
|
expect(mockedLogger.info).toHaveBeenCalledWith(RESOLVE_BOOL_MESSAGE);
|
|
});
|
|
|
|
it('should provide a logger to the before, after, and finally hook', async () => {
|
|
const client = OpenFeature.getClient();
|
|
const mockedLogger = new MockedLogger();
|
|
client.setLogger(mockedLogger);
|
|
client.addHooks(MOCK_HOOK);
|
|
await client.getBooleanValue('test', false);
|
|
|
|
expect(mockedLogger.info.mock.calls).toEqual([
|
|
[BEFORE_HOOK_LOG_MESSAGE],
|
|
[RESOLVE_BOOL_MESSAGE],
|
|
[AFTER_HOOK_LOG_MESSAGE],
|
|
[FINALLY_HOOK_LOG_MESSAGE],
|
|
]);
|
|
});
|
|
|
|
it('should provide a logger to the error hook', async () => {
|
|
const client = OpenFeature.getClient();
|
|
const mockedLogger = new MockedLogger();
|
|
client.setLogger(mockedLogger);
|
|
client.addHooks(MOCK_HOOK);
|
|
(MOCK_PROVIDER.resolveBooleanEvaluation as jest.Mock).mockRejectedValueOnce('Run error hook');
|
|
await client.getBooleanValue('test', false);
|
|
expect(mockedLogger.info.mock.calls).toEqual([
|
|
[BEFORE_HOOK_LOG_MESSAGE],
|
|
[ERROR_HOOK_LOG_MESSAGE],
|
|
[FINALLY_HOOK_LOG_MESSAGE],
|
|
]);
|
|
});
|
|
});
|
|
});
|