implement mergeExpects
This commit is contained in:
parent
9a160c6f67
commit
22f9d71019
|
|
@ -105,11 +105,13 @@ export const printReceivedStringContainExpectedResult = (
|
||||||
|
|
||||||
type ExpectMessage = string | { message?: string };
|
type ExpectMessage = string | { message?: string };
|
||||||
|
|
||||||
function createMatchers(actual: unknown, info: ExpectMetaInfo, prefix: string[]): any {
|
function createMatchers(actual: unknown, info: ExpectMetaInfo, prefix: string[], parentPrefixes: string[][]): any {
|
||||||
return new Proxy(expectLibrary(actual), new ExpectMetaInfoProxyHandler(info, prefix));
|
return new Proxy(expectLibrary(actual), new ExpectMetaInfoProxyHandler(info, [prefix, ...parentPrefixes]));
|
||||||
}
|
}
|
||||||
|
|
||||||
function createExpect(info: ExpectMetaInfo, prefix: string[] = []) {
|
const getPrefixSymbol = Symbol('get prefix');
|
||||||
|
|
||||||
|
function createExpect(info: ExpectMetaInfo, prefix: string[] = [], parentPrefixes: string[][] = []) {
|
||||||
const expectInstance: Expect<{}> = new Proxy(expectLibrary, {
|
const expectInstance: Expect<{}> = new Proxy(expectLibrary, {
|
||||||
apply: function(target: any, thisArg: any, argumentsList: [unknown, ExpectMessage?]) {
|
apply: function(target: any, thisArg: any, argumentsList: [unknown, ExpectMessage?]) {
|
||||||
const [actual, messageOrOptions] = argumentsList;
|
const [actual, messageOrOptions] = argumentsList;
|
||||||
|
|
@ -120,10 +122,10 @@ function createExpect(info: ExpectMetaInfo, prefix: string[] = []) {
|
||||||
throw new Error('`expect.poll()` accepts only function as a first argument');
|
throw new Error('`expect.poll()` accepts only function as a first argument');
|
||||||
newInfo.generator = actual as any;
|
newInfo.generator = actual as any;
|
||||||
}
|
}
|
||||||
return createMatchers(actual, newInfo, prefix);
|
return createMatchers(actual, newInfo, prefix, parentPrefixes);
|
||||||
},
|
},
|
||||||
|
|
||||||
get: function(target: any, property: string) {
|
get: function(target: any, property: string | typeof getPrefixSymbol) {
|
||||||
if (property === 'configure')
|
if (property === 'configure')
|
||||||
return configure;
|
return configure;
|
||||||
|
|
||||||
|
|
@ -149,7 +151,7 @@ function createExpect(info: ExpectMetaInfo, prefix: string[] = []) {
|
||||||
}
|
}
|
||||||
expectLibrary.extend(wrappedMatchers);
|
expectLibrary.extend(wrappedMatchers);
|
||||||
|
|
||||||
return createExpect(info, qualifier);
|
return createExpect(info, qualifier, parentPrefixes);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,6 +161,9 @@ function createExpect(info: ExpectMetaInfo, prefix: string[] = []) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (property === getPrefixSymbol)
|
||||||
|
return { prefix, parentPrefixes };
|
||||||
|
|
||||||
if (property === 'poll') {
|
if (property === 'poll') {
|
||||||
return (actual: unknown, messageOrOptions?: ExpectMessage & { timeout?: number, intervals?: number[] }) => {
|
return (actual: unknown, messageOrOptions?: ExpectMessage & { timeout?: number, intervals?: number[] }) => {
|
||||||
const poll = isString(messageOrOptions) ? {} : messageOrOptions || {};
|
const poll = isString(messageOrOptions) ? {} : messageOrOptions || {};
|
||||||
|
|
@ -247,22 +252,24 @@ type ExpectMetaInfo = {
|
||||||
|
|
||||||
class ExpectMetaInfoProxyHandler implements ProxyHandler<any> {
|
class ExpectMetaInfoProxyHandler implements ProxyHandler<any> {
|
||||||
private _info: ExpectMetaInfo;
|
private _info: ExpectMetaInfo;
|
||||||
private _prefix: string[];
|
private _prefixes: string[][];
|
||||||
|
|
||||||
constructor(info: ExpectMetaInfo, prefix: string[]) {
|
constructor(info: ExpectMetaInfo, prefixes: string[][]) {
|
||||||
this._info = { ...info };
|
this._info = { ...info };
|
||||||
this._prefix = prefix;
|
this._prefixes = prefixes;
|
||||||
}
|
}
|
||||||
|
|
||||||
get(target: Object, matcherName: string | symbol, receiver: any): any {
|
get(target: Object, matcherName: string | symbol, receiver: any): any {
|
||||||
let matcher = Reflect.get(target, matcherName, receiver);
|
let matcher = Reflect.get(target, matcherName, receiver);
|
||||||
|
|
||||||
if (typeof matcherName === 'string') {
|
if (typeof matcherName === 'string') {
|
||||||
for (let i = this._prefix.length; i > 0; i--) {
|
for (const prefix of this._prefixes) {
|
||||||
const qualifiedName = `${this._prefix.slice(0, i).join(':')}$${matcherName}`;
|
for (let i = prefix.length; i > 0; i--) {
|
||||||
if (Reflect.has(target, qualifiedName)) {
|
const qualifiedName = `${prefix.slice(0, i).join(':')}$${matcherName}`;
|
||||||
matcher = Reflect.get(target, qualifiedName, receiver);
|
if (Reflect.has(target, qualifiedName)) {
|
||||||
break;
|
matcher = Reflect.get(target, qualifiedName, receiver);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -397,5 +404,11 @@ function computeArgsSuffix(matcherName: string, args: any[]) {
|
||||||
export const expect: Expect<{}> = createExpect({}).extend(customMatchers);
|
export const expect: Expect<{}> = createExpect({}).extend(customMatchers);
|
||||||
|
|
||||||
export function mergeExpects(...expects: any[]) {
|
export function mergeExpects(...expects: any[]) {
|
||||||
return expect;
|
const parentPrefixes = expects.flatMap(e => {
|
||||||
|
const internals = e[getPrefixSymbol];
|
||||||
|
if (!internals) // non-playwright expects mutate the global expect, so we don't need to do anything special
|
||||||
|
return [];
|
||||||
|
return [internals.prefix, ...internals.parentPrefixes];
|
||||||
|
});
|
||||||
|
return createExpect({}, undefined, parentPrefixes);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,41 +18,6 @@ import path from 'path';
|
||||||
import { test, expect, parseTestRunnerOutput, stripAnsi } from './playwright-test-fixtures';
|
import { test, expect, parseTestRunnerOutput, stripAnsi } from './playwright-test-fixtures';
|
||||||
const { spawnAsync } = require('../../packages/playwright-core/lib/utils');
|
const { spawnAsync } = require('../../packages/playwright-core/lib/utils');
|
||||||
|
|
||||||
test('should be able to call expect.extend in config', async ({ runInlineTest }) => {
|
|
||||||
const result = await runInlineTest({
|
|
||||||
'helper.ts': `
|
|
||||||
import { test as base, expect } from '@playwright/test';
|
|
||||||
expect.extend({
|
|
||||||
toBeWithinRange(received, floor, ceiling) {
|
|
||||||
const pass = received >= floor && received <= ceiling;
|
|
||||||
if (pass) {
|
|
||||||
return {
|
|
||||||
message: () =>
|
|
||||||
'passed',
|
|
||||||
pass: true,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
message: () => 'failed',
|
|
||||||
pass: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
export const test = base;
|
|
||||||
`,
|
|
||||||
'expect-test.spec.ts': `
|
|
||||||
import { test } from './helper';
|
|
||||||
test('numeric ranges', () => {
|
|
||||||
test.expect(100).toBeWithinRange(90, 110);
|
|
||||||
test.expect(101).not.toBeWithinRange(0, 100);
|
|
||||||
});
|
|
||||||
`
|
|
||||||
});
|
|
||||||
expect(result.exitCode).toBe(0);
|
|
||||||
expect(result.passed).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should not expand huge arrays', async ({ runInlineTest }) => {
|
test('should not expand huge arrays', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'expect-test.spec.ts': `
|
'expect-test.spec.ts': `
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue