generic-interceptor
Version:
Provide proxy handler for getting properties and executing functions
175 lines (168 loc) • 8.52 kB
text/typescript
import { DeepPartial, Required as UtilRequired } from "utility-types";
import {
CallbackEnding,
ExecutionFunction,
FunctionCallbackPayload,
NonFunctionFieldValue,
OnErrorAdditionalPayload,
OnErrorPayload,
OnSuccessAdditionalPayload,
OnSuccessPayload,
ProcessingResult,
ProcessingType,
interceptor,
InterceptorOptions,
} from "../../src";
import { TestStrategyIt, TestStrategyResult } from "./enum";
import { JestFunction } from "./jest";
export const parameterName = "parameterName";
export const functionError: OnErrorAdditionalPayload["functionError"] = Error();
export const functionResult: OnSuccessAdditionalPayload["functionResult"] = "RESULT";
export const callbackEnding: CallbackEnding = "callbackToPromiseFunctionName";
export interface CommonDataset {
options: InterceptorOptions<boolean>;
functionArgs: FunctionCallbackPayload["functionArgs"];
}
export interface ErrorDataset {
functionError: OnErrorAdditionalPayload["functionError"];
}
export interface ResultDataset {
functionResult: OnSuccessAdditionalPayload["functionResult"];
}
export type Dataset = CommonDataset & (ErrorDataset | ResultDataset | {});
export type Strategy = { [parameterName]: ExecutionFunction | NonFunctionFieldValue };
export type StrategyFactory<TestStrategyName extends TestStrategyIt, TestResultKey extends TestStrategyResult> = (
dataset: Omit<CommonDataset, "options"> & {
options: TestStrategyName extends TestStrategyIt.callbackEndingStrategy
? UtilRequired<CommonDataset["options"], "callbackEnding">
: CommonDataset["options"];
} & (TestResultKey extends TestStrategyResult.functionError ? ErrorDataset : ResultDataset),
) => Strategy;
export type CaseItFunction = (strategyFactory: StrategyFactory<TestStrategyIt, TestStrategyResult>) => JestFunction;
export type CaseTemplate = { [key in TestStrategyIt]: { [key2 in TestStrategyResult]: CaseItFunction } };
export const loadStrategyToTemplate =
(
caseTemplate: CaseTemplate,
strategy: { [key in TestStrategyIt]: { [key2 in TestStrategyResult]: StrategyFactory<key, key2> } },
) =>
(strategyName: TestStrategyIt, testResult: TestStrategyResult) =>
caseTemplate[strategyName][testResult](strategy[strategyName][testResult]);
export const prepareProxy = (strategy: Strategy, dataset: Dataset) => new Proxy(strategy, interceptor(dataset.options));
export const prepareDataset = <T extends ErrorDataset | ResultDataset | {}>(data: DeepPartial<CommonDataset> & T) => {
data.options = data.options || ({} as InterceptorOptions<boolean>);
data.options.onSuccess = data.options.onSuccess || (() => {});
data.options.onError = data.options.onError || (() => {});
data.options.onNonFunction = data.options.onNonFunction || (() => {});
data.options.onBefore = data.options.onBefore || (() => {});
data.options.passId = data.options.passId || false;
data.functionArgs = data.functionArgs || [1, 2, 3];
return data as CommonDataset & T;
};
export const caseTemplate: CaseTemplate = {
[TestStrategyIt.synchronousStrategy]: {
[TestStrategyResult.functionError]: (strategyFactory) => () => {
const dataset = prepareDataset({ options: { onError: jest.fn() }, functionError });
const strategy = strategyFactory(dataset);
const proxy = prepareProxy(strategy, dataset);
expect(() => proxy[parameterName](...dataset.functionArgs)).toThrow(dataset.functionError);
expect(dataset.options.onError).toHaveBeenCalledTimes(1);
expect(dataset.options.onError).toHaveBeenCalledWith({
functionError: dataset.functionError,
functionArgs: dataset.functionArgs,
fieldValue: strategy[parameterName],
fieldKey: parameterName,
processingResult: ProcessingResult.failed,
processingStrategy: ProcessingType.synchronous,
fieldValueType: typeof proxy[parameterName],
} as OnErrorPayload<false>);
},
[TestStrategyResult.functionSuccess]: (strategyFactory) => () => {
const dataset = prepareDataset({ functionResult, options: { onSuccess: jest.fn() } });
const strategy = strategyFactory(dataset);
const proxy = prepareProxy(strategy, dataset);
expect(proxy[parameterName](...dataset.functionArgs)).toEqual(dataset.functionResult);
expect(dataset.options.onSuccess).toHaveBeenCalledTimes(1);
expect(dataset.options.onSuccess).toHaveBeenCalledWith({
functionResult: dataset.functionResult,
functionArgs: dataset.functionArgs,
fieldValue: strategy[parameterName],
fieldKey: parameterName,
processingResult: ProcessingResult.succeed,
processingStrategy: ProcessingType.synchronous,
fieldValueType: typeof proxy[parameterName],
} as OnSuccessPayload<false>);
},
},
[TestStrategyIt.callbackEndingStrategy]: {
[TestStrategyResult.functionError]: (strategyFactory) => async () => {
const dataset = prepareDataset({ options: { onError: jest.fn(), callbackEnding }, functionError });
const strategy = strategyFactory(dataset);
const proxy = prepareProxy(strategy, dataset);
await expect(() =>
proxy[parameterName](...dataset.functionArgs)[dataset.options.callbackEnding](),
).rejects.toEqual(dataset.functionError);
expect(dataset.options.onError).toHaveBeenCalledTimes(1);
expect(dataset.options.onError).toHaveBeenCalledWith({
functionError: dataset.functionError,
functionArgs: dataset.functionArgs,
fieldValue: strategy[parameterName],
fieldKey: parameterName,
processingResult: ProcessingResult.failed,
processingStrategy: ProcessingType.callbackEnding,
fieldValueType: typeof proxy[parameterName],
} as OnErrorPayload<false>);
},
[TestStrategyResult.functionSuccess]: (strategyFactory) => async () => {
const dataset = prepareDataset({ functionResult, options: { onSuccess: jest.fn(), callbackEnding } });
const strategy = strategyFactory(dataset);
const proxy = prepareProxy(strategy, dataset);
await expect(proxy[parameterName](...dataset.functionArgs)[dataset.options.callbackEnding]()).resolves.toEqual(
dataset.functionResult,
);
expect(dataset.options.onSuccess).toHaveBeenCalledTimes(1);
expect(dataset.options.onSuccess).toHaveBeenCalledWith({
functionResult: dataset.functionResult,
functionArgs: dataset.functionArgs,
fieldValue: strategy[parameterName],
fieldKey: parameterName,
processingResult: ProcessingResult.succeed,
processingStrategy: ProcessingType.callbackEnding,
fieldValueType: typeof proxy[parameterName],
} as OnSuccessPayload<false>);
},
},
[TestStrategyIt.promiseStrategy]: {
[TestStrategyResult.functionError]: (strategyFactory) => async () => {
const dataset = prepareDataset({ options: { onError: jest.fn() }, functionError });
const strategy = strategyFactory(dataset);
const proxy = prepareProxy(strategy, dataset);
await expect(() => proxy[parameterName](...dataset.functionArgs)).rejects.toEqual(dataset.functionError);
expect(dataset.options.onError).toHaveBeenCalledTimes(1);
expect(dataset.options.onError).toHaveBeenCalledWith({
functionError: dataset.functionError,
functionArgs: dataset.functionArgs,
fieldValue: strategy[parameterName],
fieldKey: parameterName,
processingResult: ProcessingResult.failed,
processingStrategy: ProcessingType.promise,
fieldValueType: typeof proxy[parameterName],
} as OnErrorPayload<false>);
},
[TestStrategyResult.functionSuccess]: (strategyFactory) => async () => {
const dataset = prepareDataset({ functionResult, options: { onSuccess: jest.fn() } });
const strategy = strategyFactory(dataset);
const proxy = prepareProxy(strategy, dataset);
await expect(proxy[parameterName](...dataset.functionArgs)).resolves.toEqual(dataset.functionResult);
expect(dataset.options.onSuccess).toHaveBeenCalledTimes(1);
expect(dataset.options.onSuccess).toHaveBeenCalledWith({
functionResult: dataset.functionResult,
functionArgs: dataset.functionArgs,
fieldValue: strategy[parameterName],
fieldKey: parameterName,
processingResult: ProcessingResult.succeed,
processingStrategy: ProcessingType.promise,
fieldValueType: typeof proxy[parameterName],
} as OnSuccessPayload<false>);
},
},
};