mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Use asynchandler library for handlers
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import type { AsyncHandler } from 'asynchronous-handlers';
|
||||
import type { ResourceIdentifier } from '../../../../src/http/representation/ResourceIdentifier';
|
||||
import type { BaseRouterHandlerArgs } from '../../../../src/server/util/BaseRouterHandler';
|
||||
import { BaseRouterHandler } from '../../../../src/server/util/BaseRouterHandler';
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
|
||||
class SimpleRouterHandler extends BaseRouterHandler<AsyncHandler<{ method: string; target: ResourceIdentifier }>> {
|
||||
public constructor(args: BaseRouterHandlerArgs<AsyncHandler<{ method: string; target: ResourceIdentifier }>>) {
|
||||
|
||||
@@ -4,7 +4,9 @@ import {
|
||||
createAggregateError,
|
||||
errorTermsToMetadata,
|
||||
extractErrorTerms,
|
||||
toHttpError,
|
||||
} from '../../../../src/util/errors/HttpErrorUtil';
|
||||
import { InternalServerError } from '../../../../src/util/errors/InternalServerError';
|
||||
import { toPredicateTerm } from '../../../../src/util/TermUtil';
|
||||
|
||||
describe('HttpErrorUtil', (): void => {
|
||||
@@ -48,6 +50,23 @@ describe('HttpErrorUtil', (): void => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#toHttpError', (): void => {
|
||||
it('keeps the error if it is an HttpError.', async(): Promise<void> => {
|
||||
const error = new InternalServerError('internal');
|
||||
expect(toHttpError(error)).toBe(error);
|
||||
});
|
||||
|
||||
it('converts an error to an InternalServerError.', async(): Promise<void> => {
|
||||
const error = new Error('error');
|
||||
expect(toHttpError(error)).toEqual(new InternalServerError('error'));
|
||||
});
|
||||
|
||||
it('converts unknown data to an InternalServerError.', async(): Promise<void> => {
|
||||
const error = 'error';
|
||||
expect(toHttpError(error)).toEqual(new InternalServerError('Unknown error: error'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('#createAggregateError', (): void => {
|
||||
const error401 = new HttpError(401, 'UnauthorizedHttpError');
|
||||
const error415 = new HttpError(415, 'UnsupportedMediaTypeHttpError');
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import { StaticAsyncHandler } from '../../../util/StaticAsyncHandler';
|
||||
|
||||
describe('An AsyncHandler', (): void => {
|
||||
it('supports any input by default.', async(): Promise<void> => {
|
||||
class EmptyHandler<T> extends AsyncHandler<T, null> {
|
||||
public async handle(): Promise<null> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const handler = new EmptyHandler<string>();
|
||||
await expect(handler.canHandle('test')).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('calls canHandle and handle when handleSafe is called.', async(): Promise<void> => {
|
||||
const handlerTrue: AsyncHandler<any, any> = new StaticAsyncHandler(true, null);
|
||||
const canHandleFn = jest.fn(async(input: any): Promise<void> => input);
|
||||
const handleFn = jest.fn(async(input: any): Promise<any> => input);
|
||||
|
||||
handlerTrue.canHandle = canHandleFn;
|
||||
handlerTrue.handle = handleFn;
|
||||
await expect(handlerTrue.handleSafe('test')).resolves.toBe('test');
|
||||
expect(canHandleFn).toHaveBeenCalledTimes(1);
|
||||
expect(handleFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not call handle when canHandle errors during a handleSafe call.', async(): Promise<void> => {
|
||||
const handlerFalse: AsyncHandler<any, any> = new StaticAsyncHandler(false, null);
|
||||
const canHandleFn = jest.fn(async(): Promise<void> => {
|
||||
throw new Error('test');
|
||||
});
|
||||
const handleFn = jest.fn(async(input: any): Promise<any> => input);
|
||||
|
||||
handlerFalse.canHandle = canHandleFn;
|
||||
handlerFalse.handle = handleFn;
|
||||
await expect(handlerFalse.handleSafe('test')).rejects.toThrow(Error);
|
||||
expect(canHandleFn).toHaveBeenCalledTimes(1);
|
||||
expect(handleFn).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
import { InternalServerError } from '../../../../src/util/errors/InternalServerError';
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import { BooleanHandler } from '../../../../src/util/handlers/BooleanHandler';
|
||||
import { StaticAsyncHandler } from '../../../util/StaticAsyncHandler';
|
||||
|
||||
describe('A BooleanHandler', (): void => {
|
||||
let handlerFalse: AsyncHandler<any, false>;
|
||||
let handlerTrue: AsyncHandler<any, true>;
|
||||
let handlerError: AsyncHandler<any, never>;
|
||||
let handlerCanNotHandle: AsyncHandler<any, any>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
handlerFalse = new StaticAsyncHandler(true, false);
|
||||
handlerTrue = new StaticAsyncHandler(true, true);
|
||||
handlerError = new StaticAsyncHandler(true, null) as any;
|
||||
handlerError.handle = (): never => {
|
||||
throw new InternalServerError();
|
||||
};
|
||||
handlerCanNotHandle = new StaticAsyncHandler(false, null);
|
||||
});
|
||||
|
||||
it('can handle the input if any of its handlers can.', async(): Promise<void> => {
|
||||
const handler = new BooleanHandler([ handlerFalse, handlerCanNotHandle ]);
|
||||
await expect(handler.canHandle(null)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('errors if none of its handlers supports the input.', async(): Promise<void> => {
|
||||
const handler = new BooleanHandler([ handlerCanNotHandle, handlerCanNotHandle ]);
|
||||
await expect(handler.canHandle(null)).rejects.toThrow('Not supported, Not supported');
|
||||
});
|
||||
|
||||
it('returns true if any of its handlers returns true.', async(): Promise<void> => {
|
||||
const handler = new BooleanHandler([ handlerFalse, handlerTrue, handlerCanNotHandle ]);
|
||||
await expect(handler.handle(null)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('returns false if none of its handlers returns true.', async(): Promise<void> => {
|
||||
const handler = new BooleanHandler([ handlerFalse, handlerError, handlerCanNotHandle ]);
|
||||
await expect(handler.handle(null)).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it('throw an internal error when calling handle with unsupported input.', async(): Promise<void> => {
|
||||
const handler = new BooleanHandler([ handlerCanNotHandle, handlerCanNotHandle ]);
|
||||
await expect(handler.handle(null)).rejects.toThrow(InternalServerError);
|
||||
});
|
||||
|
||||
it('returns the same handle results with handleSafe.', async(): Promise<void> => {
|
||||
const handler = new BooleanHandler([ handlerFalse, handlerTrue, handlerCanNotHandle ]);
|
||||
await expect(handler.handleSafe(null)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('throws the canHandle error when calling handleSafe with unsupported input.', async(): Promise<void> => {
|
||||
const handler = new BooleanHandler([ handlerCanNotHandle, handlerCanNotHandle ]);
|
||||
await expect(handler.handleSafe(null)).rejects.toThrow('Not supported, Not supported');
|
||||
});
|
||||
});
|
||||
@@ -1,84 +0,0 @@
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import {
|
||||
CachedHandler,
|
||||
} from '../../../../src/util/handlers/CachedHandler';
|
||||
|
||||
describe('A CachedHandler', (): void => {
|
||||
const input: any = { field1: { key: 'value' }, field2: { key: 'value' }, field3: { key: 'value2' }};
|
||||
const output = 'response';
|
||||
let source: jest.Mocked<AsyncHandler<any, string>>;
|
||||
let handler: CachedHandler<any, string>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
source = {
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue(output),
|
||||
} as any;
|
||||
handler = new CachedHandler(source);
|
||||
});
|
||||
|
||||
it('can handle input if its source can.', async(): Promise<void> => {
|
||||
await expect(handler.canHandle(input)).resolves.toBeUndefined();
|
||||
expect(source.canHandle).toHaveBeenCalledTimes(1);
|
||||
source.canHandle.mockRejectedValue(new Error('bad input'));
|
||||
await expect(handler.canHandle(input)).rejects.toThrow('bad input');
|
||||
expect(source.canHandle).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('returns the source result.', async(): Promise<void> => {
|
||||
await expect(handler.handle(input)).resolves.toBe(output);
|
||||
expect(source.handle).toHaveBeenCalledTimes(1);
|
||||
expect(source.handle).toHaveBeenLastCalledWith(input);
|
||||
});
|
||||
|
||||
it('caches the result.', async(): Promise<void> => {
|
||||
await expect(handler.handle(input)).resolves.toBe(output);
|
||||
await expect(handler.handle(input)).resolves.toBe(output);
|
||||
expect(source.handle).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('caches on the object itself.', async(): Promise<void> => {
|
||||
const copy = { ...input };
|
||||
await expect(handler.handle(input)).resolves.toBe(output);
|
||||
await expect(handler.handle(copy)).resolves.toBe(output);
|
||||
expect(source.handle).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('can handle the input if it has a cached result.', async(): Promise<void> => {
|
||||
await expect(handler.handle(input)).resolves.toBe(output);
|
||||
source.canHandle.mockRejectedValue(new Error('bad input'));
|
||||
await expect(handler.canHandle(input)).resolves.toBeUndefined();
|
||||
expect(source.canHandle).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('cannot handle input with multiple keys if the first key is already missing.', async(): Promise<void> => {
|
||||
handler = new CachedHandler(source, [ 'field1', 'field3' ]);
|
||||
|
||||
await expect(handler.canHandle(input)).resolves.toBeUndefined();
|
||||
expect(source.canHandle).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('can use a specific field of the input as key.', async(): Promise<void> => {
|
||||
handler = new CachedHandler(source, [ 'field1' ]);
|
||||
|
||||
const copy = { ...input };
|
||||
await expect(handler.handle(input)).resolves.toBe(output);
|
||||
await expect(handler.handle(copy)).resolves.toBe(output);
|
||||
expect(source.handle).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('can use multiple fields of the object as keys.', async(): Promise<void> => {
|
||||
handler = new CachedHandler(source, [ 'field1', 'field3' ]);
|
||||
|
||||
const copy = { ...input };
|
||||
copy.field2 = { other: 'field' };
|
||||
await expect(handler.handle(input)).resolves.toBe(output);
|
||||
await expect(handler.handle(copy)).resolves.toBe(output);
|
||||
expect(source.handle).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('rejects empty field arrays.', async(): Promise<void> => {
|
||||
expect((): any => new CachedHandler(source, []))
|
||||
.toThrow('The fields parameter needs to have at least 1 entry if defined.');
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { AsyncHandler } from 'asynchronous-handlers';
|
||||
import type { KeyValueStorage } from '../../../../src/storage/keyvalue/KeyValueStorage';
|
||||
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import { ConditionalHandler } from '../../../../src/util/handlers/ConditionalHandler';
|
||||
|
||||
describe('A ConditionalHandler', (): void => {
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import { filterHandlers, findHandler } from '../../../../src/util/handlers/HandlerUtil';
|
||||
import { StaticAsyncHandler } from '../../../util/StaticAsyncHandler';
|
||||
|
||||
describe('HandlerUtil', (): void => {
|
||||
describe('findHandler', (): void => {
|
||||
let handlerTrue: AsyncHandler<any, any>;
|
||||
let handlerFalse: AsyncHandler<any, any>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
handlerTrue = new StaticAsyncHandler(true, null);
|
||||
handlerFalse = new StaticAsyncHandler(false, null);
|
||||
});
|
||||
|
||||
it('finds a matching handler.', async(): Promise<void> => {
|
||||
await expect(findHandler([ handlerFalse, handlerTrue ], null)).resolves.toBe(handlerTrue);
|
||||
});
|
||||
|
||||
it('errors if there is no matching handler.', async(): Promise<void> => {
|
||||
await expect(findHandler([ handlerFalse, handlerFalse ], null)).rejects.toThrow('Not supported, Not supported');
|
||||
});
|
||||
|
||||
it('supports non-native Errors.', async(): Promise<void> => {
|
||||
jest.spyOn(handlerFalse, 'canHandle').mockRejectedValue('apple');
|
||||
await expect(findHandler([ handlerFalse ], null)).rejects.toThrow('Unknown error: apple');
|
||||
});
|
||||
});
|
||||
|
||||
describe('filterHandlers', (): void => {
|
||||
let handlerTrue: AsyncHandler<any, any>;
|
||||
let handlerFalse: AsyncHandler<any, any>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
handlerTrue = new StaticAsyncHandler(true, null);
|
||||
handlerFalse = new StaticAsyncHandler(false, null);
|
||||
});
|
||||
|
||||
it('finds matching handlers.', async(): Promise<void> => {
|
||||
await expect(filterHandlers([ handlerTrue, handlerFalse, handlerTrue ], null))
|
||||
.resolves.toEqual([ handlerTrue, handlerTrue ]);
|
||||
});
|
||||
|
||||
it('errors if there is no matching handler.', async(): Promise<void> => {
|
||||
await expect(filterHandlers([ handlerFalse, handlerFalse ], null))
|
||||
.rejects.toThrow('Not supported, Not supported');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { AsyncHandler } from 'asynchronous-handlers';
|
||||
import type { Operation } from '../../../../src/http/Operation';
|
||||
import { BasicRepresentation } from '../../../../src/http/representation/BasicRepresentation';
|
||||
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import {
|
||||
MethodFilterHandler,
|
||||
} from '../../../../src/util/handlers/MethodFilterHandler';
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import { ParallelHandler } from '../../../../src/util/handlers/ParallelHandler';
|
||||
|
||||
describe('A ParallelHandler', (): void => {
|
||||
const handlers: jest.Mocked<AsyncHandler<string, string>>[] = [
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue('0'),
|
||||
},
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue('1'),
|
||||
},
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue('2'),
|
||||
},
|
||||
] as any;
|
||||
const composite: ParallelHandler<string, string> = new ParallelHandler<string, string>(handlers);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
describe('canHandle', (): void => {
|
||||
it('succeeds if all handlers succeed.', async(): Promise<void> => {
|
||||
await expect(composite.canHandle('abc')).resolves.toBeUndefined();
|
||||
|
||||
expect(handlers[0].canHandle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[1].canHandle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[2].canHandle).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(handlers[0].canHandle).toHaveBeenCalledWith('abc');
|
||||
expect(handlers[1].canHandle).toHaveBeenCalledWith('abc');
|
||||
expect(handlers[2].canHandle).toHaveBeenCalledWith('abc');
|
||||
});
|
||||
|
||||
it('fails if one handler fails.', async(): Promise<void> => {
|
||||
const error = new Error('failure');
|
||||
handlers[1].canHandle.mockRejectedValueOnce(error);
|
||||
await expect(composite.canHandle('abc')).rejects.toThrow(error);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handle', (): void => {
|
||||
it('succeeds if all handlers succeed.', async(): Promise<void> => {
|
||||
await expect(composite.handle('abc')).resolves.toEqual([ '0', '1', '2' ]);
|
||||
|
||||
expect(handlers[0].handle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[1].handle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[2].handle).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(handlers[0].handle).toHaveBeenCalledWith('abc');
|
||||
expect(handlers[1].handle).toHaveBeenCalledWith('abc');
|
||||
expect(handlers[2].handle).toHaveBeenCalledWith('abc');
|
||||
});
|
||||
|
||||
it('fails if one handler fails.', async(): Promise<void> => {
|
||||
const error = new Error('failure');
|
||||
handlers[1].handle.mockRejectedValueOnce(error);
|
||||
await expect(composite.handle('abc')).rejects.toThrow(error);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleSafe', (): void => {
|
||||
it('succeeds if all handlers succeed.', async(): Promise<void> => {
|
||||
await expect(composite.handleSafe('abc')).resolves.toEqual([ '0', '1', '2' ]);
|
||||
|
||||
expect(handlers[0].canHandle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[1].canHandle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[2].canHandle).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(handlers[0].canHandle).toHaveBeenCalledWith('abc');
|
||||
expect(handlers[1].canHandle).toHaveBeenCalledWith('abc');
|
||||
expect(handlers[2].canHandle).toHaveBeenCalledWith('abc');
|
||||
|
||||
expect(handlers[0].handle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[1].handle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[2].handle).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(handlers[0].handle).toHaveBeenCalledWith('abc');
|
||||
expect(handlers[1].handle).toHaveBeenCalledWith('abc');
|
||||
expect(handlers[2].handle).toHaveBeenCalledWith('abc');
|
||||
});
|
||||
|
||||
it('fails if one canHandle fails.', async(): Promise<void> => {
|
||||
const error = new Error('failure');
|
||||
handlers[1].canHandle.mockRejectedValueOnce(error);
|
||||
await expect(composite.handleSafe('abc')).rejects.toThrow(error);
|
||||
|
||||
expect(handlers[0].handle).toHaveBeenCalledTimes(0);
|
||||
expect(handlers[1].handle).toHaveBeenCalledTimes(0);
|
||||
expect(handlers[2].handle).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('fails if one handle fails.', async(): Promise<void> => {
|
||||
const error = new Error('failure');
|
||||
handlers[1].handle.mockRejectedValueOnce(error);
|
||||
await expect(composite.handleSafe('abc')).rejects.toThrow(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,72 +0,0 @@
|
||||
import type { AsyncHandler, ClusterManager } from '../../../../src';
|
||||
import { NotImplementedHttpError, ProcessHandler } from '../../../../src';
|
||||
|
||||
function createClusterManager(workers: number, primary: boolean): jest.Mocked<ClusterManager> {
|
||||
return {
|
||||
isSingleThreaded: jest.fn().mockReturnValue(workers === 1),
|
||||
isWorker: jest.fn().mockReturnValue(!primary),
|
||||
isPrimary: jest.fn().mockReturnValue(primary),
|
||||
} as any;
|
||||
}
|
||||
|
||||
describe('A ProcessHandler', (): void => {
|
||||
const source: jest.Mocked<AsyncHandler<string, string>> = {
|
||||
canHandle: jest.fn(),
|
||||
handleSafe: jest.fn().mockResolvedValue('handledSafely'),
|
||||
handle: jest.fn().mockResolvedValue('handled'),
|
||||
};
|
||||
|
||||
describe('allowing only worker processes', (): void => {
|
||||
it('can create a ProcessHandler.', (): void => {
|
||||
expect((): ProcessHandler<string, string> =>
|
||||
new ProcessHandler(source, createClusterManager(1, true), false)).toBeDefined();
|
||||
});
|
||||
|
||||
it('can delegate to its source when run singlethreaded from worker.', async(): Promise<void> => {
|
||||
const ph = new ProcessHandler(source, createClusterManager(1, false), false);
|
||||
await expect(ph.handleSafe('test')).resolves.toBe('handled');
|
||||
});
|
||||
|
||||
it('can delegate to its source when run singlethreaded from primary.', async(): Promise<void> => {
|
||||
const ph = new ProcessHandler(source, createClusterManager(1, true), false);
|
||||
await expect(ph.handleSafe('test')).resolves.toBe('handled');
|
||||
});
|
||||
|
||||
it('can delegate to its source when run multithreaded from worker.', async(): Promise<void> => {
|
||||
const ph = new ProcessHandler(source, createClusterManager(2, false), false);
|
||||
await expect(ph.handleSafe('test')).resolves.toBe('handled');
|
||||
});
|
||||
|
||||
it('errors when run multithreaded from primary.', async(): Promise<void> => {
|
||||
const ph = new ProcessHandler(source, createClusterManager(2, true), false);
|
||||
await expect(ph.handleSafe('test')).rejects.toThrow(NotImplementedHttpError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('allowing only the primary process', (): void => {
|
||||
it('can create a ProcessHandler.', (): void => {
|
||||
expect((): ProcessHandler<string, string> =>
|
||||
new ProcessHandler(source, createClusterManager(1, true), true)).toBeDefined();
|
||||
});
|
||||
|
||||
it('can delegate to its source when run singlethreaded from worker.', async(): Promise<void> => {
|
||||
const ph = new ProcessHandler(source, createClusterManager(1, false), true);
|
||||
await expect(ph.handleSafe('test')).resolves.toBe('handled');
|
||||
});
|
||||
|
||||
it('can delegate to its source when run singlethreaded from primary.', async(): Promise<void> => {
|
||||
const ph = new ProcessHandler(source, createClusterManager(1, true), true);
|
||||
await expect(ph.handleSafe('test')).resolves.toBe('handled');
|
||||
});
|
||||
|
||||
it('can delegate to its source when run multithreaded from primary.', async(): Promise<void> => {
|
||||
const ph = new ProcessHandler(source, createClusterManager(2, true), true);
|
||||
await expect(ph.handleSafe('test')).resolves.toBe('handled');
|
||||
});
|
||||
|
||||
it('errors when run multithreaded from worker.', async(): Promise<void> => {
|
||||
const ph = new ProcessHandler(source, createClusterManager(2, false), true);
|
||||
await expect(ph.handleSafe('test')).rejects.toThrow(NotImplementedHttpError);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,64 +0,0 @@
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import { SequenceHandler } from '../../../../src/util/handlers/SequenceHandler';
|
||||
|
||||
describe('A SequenceHandler', (): void => {
|
||||
const handlers: jest.Mocked<AsyncHandler<string, string>>[] = [
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue('0'),
|
||||
} as any,
|
||||
{
|
||||
canHandle: jest.fn().mockRejectedValue(new Error('not supported')),
|
||||
handle: jest.fn().mockRejectedValue(new Error('should not be called')),
|
||||
} as any,
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue('2'),
|
||||
} as any,
|
||||
];
|
||||
let composite: SequenceHandler<string, string>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
composite = new SequenceHandler<string, string>(handlers);
|
||||
});
|
||||
|
||||
it('can handle all input.', async(): Promise<void> => {
|
||||
await expect(composite.canHandle('test')).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('runs all supported handlers.', async(): Promise<void> => {
|
||||
await composite.handleSafe('test');
|
||||
|
||||
expect(handlers[0].canHandle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[0].canHandle).toHaveBeenLastCalledWith('test');
|
||||
expect(handlers[0].handle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[0].handle).toHaveBeenLastCalledWith('test');
|
||||
|
||||
expect(handlers[1].canHandle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[1].canHandle).toHaveBeenLastCalledWith('test');
|
||||
expect(handlers[1].handle).toHaveBeenCalledTimes(0);
|
||||
|
||||
expect(handlers[2].canHandle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[2].canHandle).toHaveBeenLastCalledWith('test');
|
||||
expect(handlers[2].handle).toHaveBeenCalledTimes(1);
|
||||
expect(handlers[2].handle).toHaveBeenLastCalledWith('test');
|
||||
});
|
||||
|
||||
it('returns the result of the last supported handler.', async(): Promise<void> => {
|
||||
await expect(composite.handleSafe('test')).resolves.toBe('2');
|
||||
|
||||
handlers[2].canHandle.mockRejectedValueOnce(new Error('not supported'));
|
||||
await expect(composite.handleSafe('test')).resolves.toBe('0');
|
||||
});
|
||||
|
||||
it('returns undefined if no handler is supported.', async(): Promise<void> => {
|
||||
handlers[0].canHandle.mockRejectedValueOnce(new Error('not supported'));
|
||||
handlers[2].canHandle.mockRejectedValueOnce(new Error('not supported'));
|
||||
await expect(composite.handleSafe('test')).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('errors if a handler errors.', async(): Promise<void> => {
|
||||
handlers[2].handle.mockRejectedValueOnce(new Error('failure'));
|
||||
await expect(composite.handleSafe('test')).rejects.toThrow('failure');
|
||||
});
|
||||
});
|
||||
@@ -1,18 +0,0 @@
|
||||
import { StaticHandler } from '../../../../src/util/handlers/StaticHandler';
|
||||
|
||||
describe('A StaticHandler', (): void => {
|
||||
it('can handle everything.', async(): Promise<void> => {
|
||||
const handler = new StaticHandler();
|
||||
await expect(handler.canHandle(null)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns the stored value.', async(): Promise<void> => {
|
||||
const handler = new StaticHandler('apple');
|
||||
await expect(handler.handle()).resolves.toBe('apple');
|
||||
});
|
||||
|
||||
it('returns undefined if there is no stored value.', async(): Promise<void> => {
|
||||
const handler = new StaticHandler();
|
||||
await expect(handler.handle()).resolves.toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
import { BadRequestHttpError } from '../../../../src/util/errors/BadRequestHttpError';
|
||||
import { StaticThrowHandler } from '../../../../src/util/handlers/StaticThrowHandler';
|
||||
import { SOLID_ERROR } from '../../../../src/util/Vocabularies';
|
||||
|
||||
describe('A StaticThrowHandler', (): void => {
|
||||
const error = new BadRequestHttpError();
|
||||
const handler = new StaticThrowHandler(error);
|
||||
|
||||
it('can handle all requests.', async(): Promise<void> => {
|
||||
await expect(handler.canHandle({})).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('always throws an instance of the given error.', async(): Promise<void> => {
|
||||
await expect(handler.handle()).rejects.toThrow(error);
|
||||
});
|
||||
|
||||
it('creates a new instance every time.', async(): Promise<void> => {
|
||||
/* eslint-disable jest/no-conditional-expect */
|
||||
try {
|
||||
await handler.handle();
|
||||
} catch (error: unknown) {
|
||||
expect(BadRequestHttpError.isInstance(error)).toBe(true);
|
||||
// Change the metadata
|
||||
(error as BadRequestHttpError).metadata.add(SOLID_ERROR.terms.target, 'http://example.com/foo');
|
||||
}
|
||||
try {
|
||||
await handler.handle();
|
||||
} catch (error: unknown) {
|
||||
expect(BadRequestHttpError.isInstance(error)).toBe(true);
|
||||
// Metadata should not have the change
|
||||
expect((error as BadRequestHttpError).metadata.has(SOLID_ERROR.terms.target)).toBe(false);
|
||||
}
|
||||
/* eslint-enable jest/no-conditional-expect */
|
||||
});
|
||||
});
|
||||
@@ -1,23 +1,23 @@
|
||||
import { ArrayUnionHandler } from '../../../../src/util/handlers/ArrayUnionHandler';
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import type { AsyncHandler } from 'asynchronous-handlers';
|
||||
import { StatusArrayUnionHandler } from '../../../../src/util/handlers/StatusArrayUnionHandler';
|
||||
|
||||
describe('An ArrayUnionHandler', (): void => {
|
||||
describe('A StatusArrayUnionHandler', (): void => {
|
||||
let handlers: jest.Mocked<AsyncHandler<string, number[]>>[];
|
||||
let handler: ArrayUnionHandler<AsyncHandler<string, number[]>>;
|
||||
let handler: StatusArrayUnionHandler<AsyncHandler<string, number[]>>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
handlers = [
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue([ 1, 2 ]),
|
||||
} as any,
|
||||
} satisfies Partial<AsyncHandler<string, number[]>> as any,
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue([ 3, 4 ]),
|
||||
} as any,
|
||||
} satisfies Partial<AsyncHandler<string, number[]>> as any,
|
||||
];
|
||||
|
||||
handler = new ArrayUnionHandler(handlers);
|
||||
handler = new StatusArrayUnionHandler(handlers);
|
||||
});
|
||||
|
||||
it('merges the array results.', async(): Promise<void> => {
|
||||
26
test/unit/util/handlers/StatusBooleanHandler.test.ts
Normal file
26
test/unit/util/handlers/StatusBooleanHandler.test.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import type { AsyncHandler } from 'asynchronous-handlers';
|
||||
import { StatusBooleanHandler } from '../../../../src/util/handlers/StatusBooleanHandler';
|
||||
|
||||
describe('A StatusBooleanHandler', (): void => {
|
||||
let handlers: jest.Mocked<AsyncHandler<string, boolean>>[];
|
||||
let handler: StatusBooleanHandler<string>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
handlers = [
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue(false),
|
||||
} satisfies Partial<AsyncHandler<string, boolean>> as any,
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue(true),
|
||||
} satisfies Partial<AsyncHandler<string, boolean>> as any,
|
||||
];
|
||||
|
||||
handler = new StatusBooleanHandler(handlers);
|
||||
});
|
||||
|
||||
it('returns true if one of the handlers returns true.', async(): Promise<void> => {
|
||||
await expect(handler.handleSafe('input')).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
50
test/unit/util/handlers/StatusHandler.test.ts
Normal file
50
test/unit/util/handlers/StatusHandler.test.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import type { AsyncHandler } from 'asynchronous-handlers';
|
||||
import { BadRequestHttpError } from '../../../../src/util/errors/BadRequestHttpError';
|
||||
import { ForbiddenHttpError } from '../../../../src/util/errors/ForbiddenHttpError';
|
||||
import { InternalServerError } from '../../../../src/util/errors/InternalServerError';
|
||||
import { MethodNotAllowedHttpError } from '../../../../src/util/errors/MethodNotAllowedHttpError';
|
||||
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
|
||||
import { StatusHandler } from '../../../../src/util/handlers/StatusHandler';
|
||||
import { getError } from '../../../util/Util';
|
||||
|
||||
describe('A StatusHandler', (): void => {
|
||||
it('converts non-HttpErrors to an HttpError.', async(): Promise<void> => {
|
||||
const handler: AsyncHandler<string, void> = {
|
||||
canHandle: jest.fn().mockRejectedValue(new Error('canHandle')),
|
||||
handle: jest.fn().mockRejectedValue(new Error('handle')),
|
||||
handleSafe: jest.fn().mockRejectedValue(new Error('handleSafe')),
|
||||
};
|
||||
const statusHandler = new StatusHandler(handler);
|
||||
|
||||
const canHandleError = await getError(async(): Promise<void> => statusHandler.canHandle('input'));
|
||||
expect(InternalServerError.isInstance(canHandleError)).toBe(true);
|
||||
expect(canHandleError.message).toBe('canHandle');
|
||||
|
||||
const handleError = await getError(async(): Promise<void> => statusHandler.handle('input'));
|
||||
expect(InternalServerError.isInstance(handleError)).toBe(true);
|
||||
expect(handleError.message).toBe('handle');
|
||||
|
||||
const handleSafeError = await getError(async(): Promise<void> => statusHandler.handleSafe('input'));
|
||||
expect(InternalServerError.isInstance(handleSafeError)).toBe(true);
|
||||
expect(handleSafeError.message).toBe('handleSafe');
|
||||
});
|
||||
|
||||
it('converts AggregateErrors to HttpErrors.', async(): Promise<void> => {
|
||||
const handler: AsyncHandler<string, void> = {
|
||||
canHandle: jest.fn().mockRejectedValue(new MethodNotAllowedHttpError()),
|
||||
handle: jest.fn().mockRejectedValue(new AggregateError([
|
||||
new MethodNotAllowedHttpError(),
|
||||
new ForbiddenHttpError(),
|
||||
], 'error')),
|
||||
handleSafe: jest.fn().mockRejectedValue(new AggregateError([
|
||||
new MethodNotAllowedHttpError(),
|
||||
new NotImplementedHttpError(),
|
||||
], 'error')),
|
||||
};
|
||||
const statusHandler = new StatusHandler(handler);
|
||||
|
||||
await expect(statusHandler.canHandle('input')).rejects.toThrow(MethodNotAllowedHttpError);
|
||||
await expect(statusHandler.handle('input')).rejects.toThrow(BadRequestHttpError);
|
||||
await expect(statusHandler.handleSafe('input')).rejects.toThrow(InternalServerError);
|
||||
});
|
||||
});
|
||||
43
test/unit/util/handlers/StatusUnionHandler.test.ts
Normal file
43
test/unit/util/handlers/StatusUnionHandler.test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import type { AsyncHandler } from 'asynchronous-handlers';
|
||||
import { StatusUnionHandler } from '../../../../src/util/handlers/StatusUnionHandler';
|
||||
|
||||
class SimpleUnionHandler extends StatusUnionHandler<AsyncHandler<any, string>> {
|
||||
protected async combine(results: string[]): Promise<string> {
|
||||
return results.join('');
|
||||
}
|
||||
}
|
||||
|
||||
describe('A StatusUnionHandler', (): void => {
|
||||
const input = { data: 'text' };
|
||||
let handlers: jest.Mocked<AsyncHandler<any, string>>[];
|
||||
let handler: SimpleUnionHandler;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
handlers = [
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue('a'),
|
||||
} satisfies Partial<AsyncHandler<any, string>> as any,
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue('b'),
|
||||
} satisfies Partial<AsyncHandler<any, string>> as any,
|
||||
];
|
||||
|
||||
handler = new SimpleUnionHandler(handlers, true);
|
||||
});
|
||||
|
||||
it('calls the combine function when calling canHandle.', async(): Promise<void> => {
|
||||
await expect(handler.canHandle(input)).resolves.toBeUndefined();
|
||||
|
||||
expect(handlers[0].canHandle).toHaveBeenLastCalledWith(input);
|
||||
expect(handlers[1].canHandle).toHaveBeenLastCalledWith(input);
|
||||
});
|
||||
|
||||
it('calls the combine function on handle calls.', async(): Promise<void> => {
|
||||
await expect(handler.handle(input)).resolves.toBe('ab');
|
||||
|
||||
expect(handlers[0].handle).toHaveBeenLastCalledWith(input);
|
||||
expect(handlers[1].handle).toHaveBeenLastCalledWith(input);
|
||||
});
|
||||
});
|
||||
26
test/unit/util/handlers/StatusWaterfallHandler.test.ts
Normal file
26
test/unit/util/handlers/StatusWaterfallHandler.test.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import type { AsyncHandler } from 'asynchronous-handlers';
|
||||
import { StatusWaterfallHandler } from '../../../../src/util/handlers/StatusWaterfallHandler';
|
||||
|
||||
describe('A StatusBooleanHandler', (): void => {
|
||||
let handlers: jest.Mocked<AsyncHandler<string, boolean>>[];
|
||||
let handler: StatusWaterfallHandler<string, boolean>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
handlers = [
|
||||
{
|
||||
canHandle: jest.fn().mockRejectedValue(new Error('no handle')),
|
||||
handle: jest.fn().mockResolvedValue(false),
|
||||
} satisfies Partial<AsyncHandler<string, boolean>> as any,
|
||||
{
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue(true),
|
||||
} satisfies Partial<AsyncHandler<string, boolean>> as any,
|
||||
];
|
||||
|
||||
handler = new StatusWaterfallHandler(handlers);
|
||||
});
|
||||
|
||||
it('returns true if one of the handlers returns true.', async(): Promise<void> => {
|
||||
await expect(handler.handleSafe('input')).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -1,81 +0,0 @@
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import { UnionHandler } from '../../../../src/util/handlers/UnionHandler';
|
||||
|
||||
class SimpleUnionHandler extends UnionHandler<AsyncHandler<any, string>> {
|
||||
protected async combine(results: string[]): Promise<string> {
|
||||
return results.join('');
|
||||
}
|
||||
}
|
||||
|
||||
describe('A UnionHandler', (): void => {
|
||||
const input = { data: 'text' };
|
||||
let handlers: jest.Mocked<AsyncHandler<any, string>>[];
|
||||
let handler: SimpleUnionHandler;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
handlers = [
|
||||
{ canHandle: jest.fn(), handle: jest.fn().mockResolvedValue('a') } as any,
|
||||
{ canHandle: jest.fn(), handle: jest.fn().mockResolvedValue('b') } as any,
|
||||
];
|
||||
|
||||
handler = new SimpleUnionHandler(handlers);
|
||||
});
|
||||
|
||||
it('can handle a request if at least one extractor can handle it.', async(): Promise<void> => {
|
||||
await expect(handler.canHandle(input)).resolves.toBeUndefined();
|
||||
|
||||
handlers[0].canHandle.mockRejectedValue(new Error('bad request'));
|
||||
await expect(handler.canHandle(input)).resolves.toBeUndefined();
|
||||
|
||||
handlers[1].canHandle.mockRejectedValue(new Error('bad request'));
|
||||
await expect(handler.canHandle(input)).rejects.toThrow('bad request');
|
||||
|
||||
await expect(handler.handleSafe(input)).rejects.toThrow('bad request');
|
||||
});
|
||||
|
||||
it('requires all handlers to support the input if requireAll is true.', async(): Promise<void> => {
|
||||
handler = new SimpleUnionHandler(handlers, true);
|
||||
await expect(handler.canHandle(input)).resolves.toBeUndefined();
|
||||
|
||||
handlers[0].canHandle.mockRejectedValue(new Error('bad request'));
|
||||
await expect(handler.canHandle(input)).rejects.toThrow('bad request');
|
||||
|
||||
await expect(handler.handleSafe(input)).rejects.toThrow('bad request');
|
||||
});
|
||||
|
||||
it('calls all handlers that support the input.', async(): Promise<void> => {
|
||||
handlers[0].canHandle.mockRejectedValue(new Error('bad request'));
|
||||
await expect(handler.handle(input)).resolves.toBe('b');
|
||||
await expect(handler.handleSafe(input)).resolves.toBe('b');
|
||||
});
|
||||
|
||||
it('calls all handlers if requireAll is true.', async(): Promise<void> => {
|
||||
handler = new SimpleUnionHandler(handlers, true);
|
||||
await expect(handler.handleSafe(input)).resolves.toBe('ab');
|
||||
|
||||
// `handle` call does not need to check `canHandle` values anymore
|
||||
handlers[0].canHandle.mockRejectedValue(new Error('bad request'));
|
||||
await expect(handler.handle(input)).resolves.toBe('ab');
|
||||
});
|
||||
|
||||
it('requires all handlers to succeed if requireAll is true.', async(): Promise<void> => {
|
||||
handler = new SimpleUnionHandler(handlers, true);
|
||||
|
||||
handlers[0].handle.mockRejectedValue(new Error('bad request'));
|
||||
await expect(handler.handleSafe(input)).rejects.toThrow('bad request');
|
||||
});
|
||||
|
||||
it('does not require all handlers to succeed if ignoreErrors is true.', async(): Promise<void> => {
|
||||
handler = new SimpleUnionHandler(handlers, true, true);
|
||||
|
||||
handlers[0].handle.mockRejectedValueOnce(new Error('bad request'));
|
||||
await expect(handler.handleSafe(input)).resolves.toBe('b');
|
||||
|
||||
handlers[1].handle.mockRejectedValueOnce(new Error('bad request'));
|
||||
await expect(handler.handleSafe(input)).resolves.toBe('a');
|
||||
|
||||
handlers[0].handle.mockRejectedValueOnce(new Error('bad request'));
|
||||
handlers[1].handle.mockRejectedValueOnce(new Error('bad request'));
|
||||
await expect(handler.handleSafe(input)).resolves.toBe('');
|
||||
});
|
||||
});
|
||||
@@ -1,18 +0,0 @@
|
||||
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
|
||||
import { UnsupportedAsyncHandler } from '../../../../src/util/handlers/UnsupportedAsyncHandler';
|
||||
|
||||
describe('An UnsupportedAsyncHandler', (): void => {
|
||||
it('throws a default error when no message is set.', async(): Promise<void> => {
|
||||
const handler = new UnsupportedAsyncHandler();
|
||||
await expect(handler.canHandle()).rejects.toThrow(NotImplementedHttpError);
|
||||
await expect(handler.handle()).rejects.toThrow(NotImplementedHttpError);
|
||||
await expect(handler.handleSafe(null)).rejects.toThrow(NotImplementedHttpError);
|
||||
});
|
||||
|
||||
it('throws the specified error when a message is set.', async(): Promise<void> => {
|
||||
const handler = new UnsupportedAsyncHandler('custom error');
|
||||
await expect(handler.canHandle()).rejects.toThrow('custom error');
|
||||
await expect(handler.handle()).rejects.toThrow('custom error');
|
||||
await expect(handler.handleSafe(null)).rejects.toThrow('custom error');
|
||||
});
|
||||
});
|
||||
@@ -1,86 +0,0 @@
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import { WaterfallHandler } from '../../../../src/util/handlers/WaterfallHandler';
|
||||
import { StaticAsyncHandler } from '../../../util/StaticAsyncHandler';
|
||||
|
||||
describe('A WaterfallHandler', (): void => {
|
||||
describe('with no handlers', (): void => {
|
||||
it('can never handle data.', async(): Promise<void> => {
|
||||
const handler = new WaterfallHandler([]);
|
||||
|
||||
await expect(handler.canHandle(null)).rejects.toThrow(Error);
|
||||
});
|
||||
|
||||
it('errors if its handle function is called.', async(): Promise<void> => {
|
||||
const handler = new WaterfallHandler([]);
|
||||
|
||||
await expect(handler.handle(null)).rejects.toThrow(Error);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with multiple handlers', (): void => {
|
||||
let handlerTrue: AsyncHandler<any, any>;
|
||||
let handlerFalse: AsyncHandler<any, any>;
|
||||
let canHandleFn: jest.Mock<Promise<void>, [any]>;
|
||||
let handleFn: jest.Mock<Promise<void>, [any]>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
handlerTrue = new StaticAsyncHandler(true, null);
|
||||
handlerFalse = new StaticAsyncHandler(false, null);
|
||||
|
||||
canHandleFn = jest.fn(async(input: any): Promise<any> => input);
|
||||
handleFn = jest.fn(async(input: any): Promise<any> => input);
|
||||
handlerTrue.canHandle = canHandleFn;
|
||||
handlerTrue.handle = handleFn;
|
||||
});
|
||||
|
||||
it('can handle data if a handler supports it.', async(): Promise<void> => {
|
||||
const handler = new WaterfallHandler([ handlerFalse, handlerTrue ]);
|
||||
|
||||
await expect(handler.canHandle(null)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('can not handle data if no handler supports it.', async(): Promise<void> => {
|
||||
const handler = new WaterfallHandler([ handlerFalse, handlerFalse ]);
|
||||
|
||||
await expect(handler.canHandle(null)).rejects.toThrow('Not supported, Not supported');
|
||||
});
|
||||
|
||||
it('throws unknown errors if no Error objects are thrown.', async(): Promise<void> => {
|
||||
handlerFalse.canHandle = async(): Promise<void> => {
|
||||
// eslint-disable-next-line ts/no-throw-literal
|
||||
throw 'apple';
|
||||
};
|
||||
const handler = new WaterfallHandler([ handlerFalse, handlerFalse ]);
|
||||
|
||||
await expect(handler.canHandle(null)).rejects.toThrow('Unknown error: apple, Unknown error: apple');
|
||||
});
|
||||
|
||||
it('handles data if a handler supports it.', async(): Promise<void> => {
|
||||
const handler = new WaterfallHandler([ handlerFalse, handlerTrue ]);
|
||||
|
||||
await expect(handler.handle('test')).resolves.toBe('test');
|
||||
expect(canHandleFn).toHaveBeenCalledTimes(1);
|
||||
expect(handleFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('errors if the handle function is called but no handler supports the data.', async(): Promise<void> => {
|
||||
const handler = new WaterfallHandler([ handlerFalse, handlerFalse ]);
|
||||
|
||||
await expect(handler.handle('test')).rejects.toThrow('All handlers failed');
|
||||
});
|
||||
|
||||
it('only calls the canHandle function once of its handlers when handleSafe is called.', async(): Promise<void> => {
|
||||
const handler = new WaterfallHandler([ handlerFalse, handlerTrue ]);
|
||||
|
||||
await expect(handler.handleSafe('test')).resolves.toBe('test');
|
||||
expect(canHandleFn).toHaveBeenCalledTimes(1);
|
||||
expect(handleFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('throws the canHandle error when calling handleSafe if the data is not supported.', async(): Promise<void> => {
|
||||
const handler = new WaterfallHandler([ handlerFalse, handlerFalse ]);
|
||||
|
||||
await expect(handler.handleSafe(null)).rejects.toThrow('Not supported, Not supported');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { AsyncHandler } from 'asynchronous-handlers';
|
||||
import { NotFoundHttpError, StaticTemplateEngine } from '../../../../src';
|
||||
import type { AsyncHandler, TemplateEngineInput } from '../../../../src';
|
||||
import type { TemplateEngineInput } from '../../../../src';
|
||||
import Dict = NodeJS.Dict;
|
||||
|
||||
describe('A StaticTemplateEngine', (): void => {
|
||||
|
||||
Reference in New Issue
Block a user