@serenity-js/web
Version:
Serenity/JS Screenplay Pattern library offering a flexible, web driver-agnostic approach for interacting with web-based user interfaces and components, suitable for various testing contexts
64 lines (54 loc) • 2.44 kB
text/typescript
import { ValueInspector } from '@serenity-js/core/lib/io';
/* eslint-disable @typescript-eslint/indent */
type TransformedArgument<T, U> =
T extends Array<infer E> ? Array<TransformedArgument<E, U>> :
T extends object ? { [K in keyof T]: TransformedArgument<T[K], U> }
: U;
/* eslint-enable */
type RefId = `$ref${number}`;
/**
* @group Models
*/
export class ArgumentDehydrator<T, U> {
constructor(
private readonly shouldReference: (item: any) => item is T,
private readonly transformation: (item: T) => U | Promise<U>,
) {
}
public async dehydrate(inputArgs: Array<any>): Promise<[ { argsCount: number, refsCount: number}, ...any[] ]> {
const result = await this.dehydrateRecursively(inputArgs);
return [
{ argsCount: result.args.length, refsCount: result.refsCount },
...result.args,
...result.refs
];
}
private async dehydrateRecursively(inputArgs: Array<any>, refsCount = 0): Promise<{
args: Array<TransformedArgument<T, RefId>>;
refs: Array<U>;
refsCount: number;
}> {
return inputArgs.reduce(async (acc, arg) => {
const { args, refs, refsCount } = await acc;
if (Array.isArray(arg)) {
const { args: nestedArgs, refs: nestedRefs, refsCount: currentRefsCount } = await this.dehydrateRecursively(arg, refsCount);
return {
args: [ ...args, nestedArgs, ],
refs: [ ...refs, ...nestedRefs ],
refsCount: currentRefsCount,
};
}
if (ValueInspector.isPlainObject(arg)) {
const { args: nestedArgs, refs: nestedRefs, refsCount: currentRefsCount } = await this.dehydrateRecursively(Object.values(arg), refsCount);
return {
args: [ ...args, Object.fromEntries(Object.keys(arg).map((key, i) => [ key, nestedArgs[i] ])) ],
refs: [ ...refs, ...nestedRefs ],
refsCount: currentRefsCount,
};
}
return this.shouldReference(arg)
? { args: [ ...args, `$ref${ refsCount }` ], refs: [ ...refs, await this.transformation(arg) ], refsCount: refsCount + 1 }
: { args: [ ...args, arg ], refs, refsCount };
}, Promise.resolve({ args: [], refs: [], refsCount }));
}
}