flatten fields
This commit is contained in:
parent
f4ce289715
commit
87fb05ddb2
|
|
@ -4,29 +4,42 @@
|
||||||
|
|
||||||
Information about an error thrown during test execution.
|
Information about an error thrown during test execution.
|
||||||
|
|
||||||
|
## property: TestInfoError.actual
|
||||||
|
* since: v1.49
|
||||||
|
- type: ?<[any]>
|
||||||
|
|
||||||
|
Actual value.
|
||||||
|
|
||||||
|
## property: TestInfoError.expected
|
||||||
|
* since: v1.49
|
||||||
|
- type: ?<[any]>
|
||||||
|
|
||||||
|
Expected value.
|
||||||
|
|
||||||
|
## property: TestInfoError.log
|
||||||
|
* since: v1.49
|
||||||
|
- type: ?<[Array]<[string]>>
|
||||||
|
|
||||||
|
Call log.
|
||||||
|
|
||||||
## property: TestInfoError.message
|
## property: TestInfoError.message
|
||||||
* since: v1.10
|
* since: v1.10
|
||||||
- type: ?<[string]>
|
- type: ?<[string]>
|
||||||
|
|
||||||
Error message. Set when [Error] (or its subclass) has been thrown.
|
Error message. Set when [Error] (or its subclass) has been thrown.
|
||||||
|
|
||||||
|
## property: TestInfoError.shortMessage
|
||||||
|
* since: v1.49
|
||||||
|
- type: ?<[string]>
|
||||||
|
|
||||||
|
Failure message.
|
||||||
|
|
||||||
## property: TestInfoError.stack
|
## property: TestInfoError.stack
|
||||||
* since: v1.10
|
* since: v1.10
|
||||||
- type: ?<[string]>
|
- type: ?<[string]>
|
||||||
|
|
||||||
Error stack. Set when [Error] (or its subclass) has been thrown.
|
Error stack. Set when [Error] (or its subclass) has been thrown.
|
||||||
|
|
||||||
## property: TestInfoError.matcherResult
|
|
||||||
* since: v1.49
|
|
||||||
- type: ?<[Object]>
|
|
||||||
- `name` <[string]>
|
|
||||||
- `message` ?<[string]> Failure message
|
|
||||||
- `log` ?<[Array]<[string]>> Call log
|
|
||||||
- `expected` ?<[any]>
|
|
||||||
- `actual` ?<[any]>
|
|
||||||
|
|
||||||
Expect matcher result.
|
|
||||||
|
|
||||||
## property: TestInfoError.value
|
## property: TestInfoError.value
|
||||||
* since: v1.10
|
* since: v1.10
|
||||||
- type: ?<[string]>
|
- type: ?<[string]>
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,41 @@
|
||||||
|
|
||||||
Information about an error thrown during test execution.
|
Information about an error thrown during test execution.
|
||||||
|
|
||||||
|
## property: TestError.actual
|
||||||
|
* since: v1.49
|
||||||
|
- type: ?<[any]>
|
||||||
|
|
||||||
|
Actual value.
|
||||||
|
|
||||||
|
## property: TestError.expected
|
||||||
|
* since: v1.49
|
||||||
|
- type: ?<[any]>
|
||||||
|
|
||||||
|
Expected value.
|
||||||
|
|
||||||
|
## property: TestError.log
|
||||||
|
* since: v1.49
|
||||||
|
- type: ?<[Array]<[string]>>
|
||||||
|
|
||||||
|
Call log.
|
||||||
|
|
||||||
## property: TestError.message
|
## property: TestError.message
|
||||||
* since: v1.10
|
* since: v1.10
|
||||||
- type: ?<[string]>
|
- type: ?<[string]>
|
||||||
|
|
||||||
Error message. Set when [Error] (or its subclass) has been thrown.
|
Error message. Set when [Error] (or its subclass) has been thrown.
|
||||||
|
|
||||||
|
## property: TestError.message
|
||||||
|
* since: v1.10
|
||||||
|
- type: ?<[string]>
|
||||||
|
|
||||||
|
Error message. Set when [Error] (or its subclass) has been thrown.
|
||||||
|
## property: TestError.shortMessage
|
||||||
|
* since: v1.49
|
||||||
|
- type: ?<[string]>
|
||||||
|
|
||||||
|
Failure message.
|
||||||
|
|
||||||
## property: TestError.stack
|
## property: TestError.stack
|
||||||
* since: v1.10
|
* since: v1.10
|
||||||
- type: ?<[string]>
|
- type: ?<[string]>
|
||||||
|
|
@ -28,17 +57,6 @@ The value that was thrown. Set when anything except the [Error] (or its subclass
|
||||||
|
|
||||||
Error location in the source code.
|
Error location in the source code.
|
||||||
|
|
||||||
## property: TestError.matcherResult
|
|
||||||
* since: v1.49
|
|
||||||
- type: ?<[Object]>
|
|
||||||
- `name` <[string]>
|
|
||||||
- `message` ?<[string]> Failure message
|
|
||||||
- `log` ?<[Array]<[string]>> Call log
|
|
||||||
- `expected` ?<[any]>
|
|
||||||
- `actual` ?<[any]>
|
|
||||||
|
|
||||||
Expect matcher result.
|
|
||||||
|
|
||||||
## property: TestError.snippet
|
## property: TestError.snippet
|
||||||
* since: v1.33
|
* since: v1.33
|
||||||
- type: ?<[string]>
|
- type: ?<[string]>
|
||||||
|
|
|
||||||
|
|
@ -152,21 +152,23 @@ export const TestResultView: React.FC<{
|
||||||
|
|
||||||
function classifyErrors(testErrors: ErrorDetails[], diffs: ImageDiff[]) {
|
function classifyErrors(testErrors: ErrorDetails[], diffs: ImageDiff[]) {
|
||||||
return testErrors.map(error => {
|
return testErrors.map(error => {
|
||||||
if (error.matcherResult?.name === 'toHaveScreenshot' && error.matcherResult?.actual && error.matcherResult?.expected) {
|
if (error.shortMessage?.includes('Screenshot comparison failed:') && error.actual && error.expected) {
|
||||||
const matchingDiff = diffs.find(diff => {
|
const matchingDiff = diffs.find(diff => {
|
||||||
const attachmentName = diff.actual?.attachment.name;
|
const attachmentName = diff.actual?.attachment.name;
|
||||||
return attachmentName && error.matcherResult?.actual.endsWith(attachmentName);
|
return attachmentName && error.actual.endsWith(attachmentName);
|
||||||
});
|
});
|
||||||
const errorSuffix = ['Call log:',
|
const errorSuffix = ['Call log:',
|
||||||
...(error.matcherResult.log?.map(line => ' - ' + line) || []),
|
...(error.log?.map(line => ' - ' + line) || []),
|
||||||
'',
|
'',
|
||||||
error.snippet,
|
error.snippet,
|
||||||
|
'',
|
||||||
|
error.callStack,
|
||||||
].join('\n');
|
].join('\n');
|
||||||
if (matchingDiff) {
|
if (matchingDiff) {
|
||||||
return {
|
return {
|
||||||
type: 'screenshot',
|
type: 'screenshot',
|
||||||
diff: matchingDiff,
|
diff: matchingDiff,
|
||||||
errorPrefix: error.matcherResult?.message,
|
errorPrefix: error.shortMessage,
|
||||||
errorSuffix
|
errorSuffix
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,19 +83,15 @@ export type TestCase = Omit<TestCaseSummary, 'results'> & {
|
||||||
results: TestResult[];
|
results: TestResult[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type MatcherResult = {
|
|
||||||
name: string;
|
|
||||||
message?: string;
|
|
||||||
log?: string[];
|
|
||||||
expected?: any;
|
|
||||||
actual?: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ErrorDetails = {
|
export type ErrorDetails = {
|
||||||
message: string;
|
message: string;
|
||||||
location?: Location;
|
location?: Location;
|
||||||
matcherResult?: MatcherResult;
|
shortMessage?: string;
|
||||||
|
log?: string[];
|
||||||
|
expected?: any;
|
||||||
|
actual?: any;
|
||||||
snippet?: string;
|
snippet?: string;
|
||||||
|
callStack?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TestAttachment = {
|
export type TestAttachment = {
|
||||||
|
|
|
||||||
|
|
@ -29,19 +29,20 @@ type Annotation = {
|
||||||
location?: Location;
|
location?: Location;
|
||||||
};
|
};
|
||||||
|
|
||||||
type MatcherResult = {
|
|
||||||
name: string;
|
|
||||||
message?: string;
|
|
||||||
log?: string[];
|
|
||||||
expected?: any;
|
|
||||||
actual?: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ErrorDetails = {
|
type ErrorDetails = {
|
||||||
message: string;
|
message: string;
|
||||||
location?: Location;
|
location?: Location;
|
||||||
matcherResult?: MatcherResult;
|
callStack?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TestResultErrorDetails = ErrorDetails & {
|
||||||
|
shortMessage?: string;
|
||||||
|
log?: string[];
|
||||||
|
expected?: any;
|
||||||
|
actual?: any;
|
||||||
|
|
||||||
snippet?: string;
|
snippet?: string;
|
||||||
|
stack?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type TestSummary = {
|
type TestSummary = {
|
||||||
|
|
@ -374,8 +375,8 @@ function quotePathIfNeeded(path: string): string {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatResultFailure(test: TestCase, result: TestResult, initialIndent: string, highlightCode: boolean): ErrorDetails[] {
|
export function formatResultFailure(test: TestCase, result: TestResult, initialIndent: string, highlightCode: boolean): TestResultErrorDetails[] {
|
||||||
const errorDetails: ErrorDetails[] = [];
|
const errorDetails: TestResultErrorDetails[] = [];
|
||||||
|
|
||||||
if (result.status === 'passed' && test.expectedStatus === 'failed') {
|
if (result.status === 'passed' && test.expectedStatus === 'failed') {
|
||||||
errorDetails.push({
|
errorDetails.push({
|
||||||
|
|
@ -393,8 +394,12 @@ export function formatResultFailure(test: TestCase, result: TestResult, initialI
|
||||||
errorDetails.push({
|
errorDetails.push({
|
||||||
message: indent(formattedError.message, initialIndent),
|
message: indent(formattedError.message, initialIndent),
|
||||||
location: formattedError.location,
|
location: formattedError.location,
|
||||||
matcherResult: error.matcherResult,
|
shortMessage: error.shortMessage,
|
||||||
|
log: error.log,
|
||||||
|
expected: error.expected,
|
||||||
|
actual: error.actual,
|
||||||
snippet: error.snippet,
|
snippet: error.snippet,
|
||||||
|
callStack: formattedError.callStack,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return errorDetails;
|
return errorDetails;
|
||||||
|
|
@ -474,9 +479,12 @@ export function formatError(error: TestError, highlightCode: boolean): ErrorDeta
|
||||||
tokens.push(snippet);
|
tokens.push(snippet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let callStack;
|
||||||
if (parsedStack && parsedStack.stackLines.length) {
|
if (parsedStack && parsedStack.stackLines.length) {
|
||||||
tokens.push('');
|
tokens.push('');
|
||||||
tokens.push(colors.dim(parsedStack.stackLines.join('\n')));
|
tokens.push(colors.dim(parsedStack.stackLines.join('\n')));
|
||||||
|
// TODO: pass raw lines.
|
||||||
|
callStack = colors.dim(parsedStack.stackLines.join('\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
let location = error.location;
|
let location = error.location;
|
||||||
|
|
@ -486,6 +494,7 @@ export function formatError(error: TestError, highlightCode: boolean): ErrorDeta
|
||||||
return {
|
return {
|
||||||
location,
|
location,
|
||||||
message: tokens.join('\n'),
|
message: tokens.join('\n'),
|
||||||
|
callStack,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,8 @@ class JSONReporter implements ReporterV2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _serializeError(error: TestError): JSONReportError {
|
private _serializeError(error: TestError): JSONReportError {
|
||||||
return formatError(error, true);
|
const { message, location } = formatError(error, true);
|
||||||
|
return { message, location };
|
||||||
}
|
}
|
||||||
|
|
||||||
private _serializeTestStep(step: TestStep): JSONReportTestStep {
|
private _serializeTestStep(step: TestStep): JSONReportTestStep {
|
||||||
|
|
|
||||||
|
|
@ -30,26 +30,25 @@ import type { MatcherResult } from './matchers/matcherHint';
|
||||||
const PLAYWRIGHT_TEST_PATH = path.join(__dirname, '..');
|
const PLAYWRIGHT_TEST_PATH = path.join(__dirname, '..');
|
||||||
const PLAYWRIGHT_CORE_PATH = path.dirname(require.resolve('playwright-core/package.json'));
|
const PLAYWRIGHT_CORE_PATH = path.dirname(require.resolve('playwright-core/package.json'));
|
||||||
|
|
||||||
export function filterStackTrace(e: Error): { message: string, stack: string, matcherResult: TestInfoError['matcherResult'] } {
|
export function filterStackTrace(e: Error): Omit<TestInfoError, 'value'> {
|
||||||
const name = e.name ? e.name + ': ' : '';
|
const name = e.name ? e.name + ': ' : '';
|
||||||
if (process.env.PWDEBUGIMPL)
|
if (process.env.PWDEBUGIMPL)
|
||||||
return { message: name + e.message, stack: e.stack || '', matcherResult: filterMatcherResult(e) };
|
return { message: name + e.message, stack: e.stack || '', ...filterExpectDetails(e) };
|
||||||
|
|
||||||
const stackLines = stringifyStackFrames(filteredStackTrace(e.stack?.split('\n') || []));
|
const stackLines = stringifyStackFrames(filteredStackTrace(e.stack?.split('\n') || []));
|
||||||
return {
|
return {
|
||||||
matcherResult: filterMatcherResult(e),
|
...filterExpectDetails(e),
|
||||||
message: name + e.message,
|
message: name + e.message,
|
||||||
stack: `${name}${e.message}${stackLines.map(line => '\n' + line).join('')}`
|
stack: `${name}${e.message}${stackLines.map(line => '\n' + line).join('')}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterMatcherResult(e: Error): TestInfoError['matcherResult'] | undefined {
|
function filterExpectDetails(e: Error): Pick<TestInfoError, 'shortMessage'|'log'|'expected'|'actual'> {
|
||||||
const matcherResult = (e as any).matcherResult as MatcherResult<unknown, unknown>;
|
const matcherResult = (e as any).matcherResult as MatcherResult<unknown, unknown>;
|
||||||
if (!matcherResult)
|
if (!matcherResult)
|
||||||
return undefined;
|
return {};
|
||||||
return {
|
return {
|
||||||
name: matcherResult.name,
|
shortMessage: matcherResult.shortMessage,
|
||||||
message: matcherResult.shortMessage,
|
|
||||||
log: matcherResult.log,
|
log: matcherResult.log,
|
||||||
expected: matcherResult.expected,
|
expected: matcherResult.expected,
|
||||||
actual: matcherResult.actual,
|
actual: matcherResult.actual,
|
||||||
|
|
|
||||||
31
packages/playwright/types/test.d.ts
vendored
31
packages/playwright/types/test.d.ts
vendored
|
|
@ -8380,31 +8380,30 @@ export interface TestInfo {
|
||||||
*/
|
*/
|
||||||
export interface TestInfoError {
|
export interface TestInfoError {
|
||||||
/**
|
/**
|
||||||
* Expect matcher result.
|
* Actual value.
|
||||||
*/
|
*/
|
||||||
matcherResult?: {
|
actual?: any;
|
||||||
name: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Failure message
|
* Expected value.
|
||||||
*/
|
*/
|
||||||
message?: string;
|
expected?: any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call log
|
* Call log.
|
||||||
*/
|
*/
|
||||||
log?: Array<string>;
|
log?: Array<string>;
|
||||||
|
|
||||||
expected?: any;
|
|
||||||
|
|
||||||
actual?: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error message. Set when [Error] (or its subclass) has been thrown.
|
* Error message. Set when [Error] (or its subclass) has been thrown.
|
||||||
*/
|
*/
|
||||||
message?: string;
|
message?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Failure message.
|
||||||
|
*/
|
||||||
|
shortMessage?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error stack. Set when [Error] (or its subclass) has been thrown.
|
* Error stack. Set when [Error] (or its subclass) has been thrown.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
35
packages/playwright/types/testReporter.d.ts
vendored
35
packages/playwright/types/testReporter.d.ts
vendored
|
|
@ -554,37 +554,36 @@ export interface TestCase {
|
||||||
* Information about an error thrown during test execution.
|
* Information about an error thrown during test execution.
|
||||||
*/
|
*/
|
||||||
export interface TestError {
|
export interface TestError {
|
||||||
|
/**
|
||||||
|
* Actual value.
|
||||||
|
*/
|
||||||
|
actual?: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expected value.
|
||||||
|
*/
|
||||||
|
expected?: any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error location in the source code.
|
* Error location in the source code.
|
||||||
*/
|
*/
|
||||||
location?: Location;
|
location?: Location;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expect matcher result.
|
* Call log.
|
||||||
*/
|
*/
|
||||||
matcherResult?: {
|
log?: Array<string>;
|
||||||
name: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Failure message
|
|
||||||
*/
|
|
||||||
message?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call log
|
|
||||||
*/
|
|
||||||
log?: Array<string>;
|
|
||||||
|
|
||||||
expected?: any;
|
|
||||||
|
|
||||||
actual?: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error message. Set when [Error] (or its subclass) has been thrown.
|
* Error message. Set when [Error] (or its subclass) has been thrown.
|
||||||
*/
|
*/
|
||||||
message?: string;
|
message?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Failure message.
|
||||||
|
*/
|
||||||
|
shortMessage?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Source code snippet with highlighted error.
|
* Source code snippet with highlighted error.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue