-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcreateExpectMethod.ts
More file actions
137 lines (118 loc) · 4.63 KB
/
Copy pathcreateExpectMethod.ts
File metadata and controls
137 lines (118 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import {LogEventStatus, LogEventType, RESOLVED_PROMISE, RETRY_KEY} from '../../constants/internal';
import {getFullPackConfig} from '../config';
import {E2edError} from '../error';
import {getDurationWithUnits} from '../getDurationWithUnits';
import {log} from '../log';
import {setReadonlyProperty} from '../object';
import {addTimeoutToPromise} from '../promise';
import {Selector} from '../selectors';
import {isThenable} from '../typeGuards';
import {removeStyleFromString, valueToString, wrapStringForLogs} from '../valueToString';
import {additionalMatchers} from './additionalMatchers';
import {applyAdditionalMatcher} from './applyAdditionalMatcher';
import type {Fn, SelectorPropertyRetryData} from '../../types/internal';
import type {Expect} from './Expect';
import type {AssertionFunction, ExpectMethod} from './types';
import {expect} from '@playwright/test';
const additionalAssertionTimeoutInMs = 1_000;
/**
* Creates method of `Expect` class.
* @internal
*/
export const createExpectMethod = (
key: string,
getAssertionMessage?: AssertionFunction<string>,
): ExpectMethod =>
// eslint-disable-next-line no-restricted-syntax
function method(...args: Parameters<ExpectMethod>) {
const {assertionTimeout} = getFullPackConfig();
const timeout = assertionTimeout + additionalAssertionTimeoutInMs;
const message = getAssertionMessage === undefined ? key : getAssertionMessage(...args);
const selectorPropertyRetryData = (
this.actualValue as {[RETRY_KEY]?: SelectorPropertyRetryData}
)?.[RETRY_KEY];
const timeoutWithUnits = getDurationWithUnits(timeout);
const timeoutError = new E2edError(
`"${key}" assertion promise rejected after ${timeoutWithUnits} timeout`,
);
const runAssertion = (value: unknown): Promise<Expect> => {
const additionalMatcher = additionalMatchers[key as keyof typeof additionalMatchers];
const ctx: Expect = {actualValue: value, description: this.description};
if (additionalMatcher !== undefined) {
return addTimeoutToPromise(
applyAdditionalMatcher(
additionalMatcher as Fn<unknown[], Promise<unknown>>,
ctx,
args,
selectorPropertyRetryData,
),
timeout,
timeoutError,
).catch((assertError: Error) => {
setReadonlyProperty(ctx, 'error', assertError);
return ctx;
});
}
const assertion = expect(value, ctx.description) as unknown as Record<
string,
Fn<unknown[], Promise<unknown>>
>;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return addTimeoutToPromise(assertion[key]!(...args), timeout, timeoutError).then(
() => ctx,
(assertError: Error) => {
setReadonlyProperty(ctx, 'error', assertError);
return ctx;
},
);
};
const assertionPromise: Promise<Expect> = RESOLVED_PROMISE.then(() => {
if (isThenable(this.actualValue)) {
return addTimeoutToPromise(
this.actualValue as Promise<unknown>,
timeout,
timeoutError,
).then(runAssertion);
}
return runAssertion(this.actualValue);
});
return assertionPromise.then(({actualValue, additionalLogFields, error}) => {
const logMessage = `Assert: ${this.description}`;
const logPayload = {
assertionArguments: args,
...additionalLogFields,
error: error?.message === undefined ? undefined : removeStyleFromString(error.message),
logEventStatus: error ? LogEventStatus.Failed : LogEventStatus.Passed,
selector:
selectorPropertyRetryData?.selector.description ??
(this.actualValue instanceof Selector ? this.actualValue.description : undefined),
...(selectorPropertyRetryData
? {
selectorProperty: selectorPropertyRetryData.property,
selectorPropertyArgs: selectorPropertyRetryData.args,
}
: undefined),
};
return addTimeoutToPromise(Promise.resolve(actualValue), timeout, timeoutError)
.then(
(value) =>
log(
logMessage,
{
actualValue: value,
assertion: wrapStringForLogs(`value ${valueToString(value)} ${message}`),
...logPayload,
},
LogEventType.InternalAssert,
),
(actualValueResolveError: Error) => {
log(logMessage, {actualValueResolveError, ...logPayload}, LogEventType.InternalAssert);
},
)
.then(() => {
if (error) {
throw error;
}
});
});
};