flatten fields

This commit is contained in:
Yury Semikhatsky 2024-10-16 16:42:59 -07:00
parent f4ce289715
commit 87fb05ddb2
9 changed files with 125 additions and 89 deletions

View file

@ -4,29 +4,42 @@
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
* since: v1.10
- type: ?<[string]>
Error message. Set when [Error] (or its subclass) has been thrown.
## property: TestInfoError.shortMessage
* since: v1.49
- type: ?<[string]>
Failure message.
## property: TestInfoError.stack
* since: v1.10
- type: ?<[string]>
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
* since: v1.10
- type: ?<[string]>

View file

@ -4,12 +4,41 @@
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
* since: v1.10
- type: ?<[string]>
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
* since: v1.10
- 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.
## 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
* since: v1.33
- type: ?<[string]>

View file

@ -152,21 +152,23 @@ export const TestResultView: React.FC<{
function classifyErrors(testErrors: ErrorDetails[], diffs: ImageDiff[]) {
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 attachmentName = diff.actual?.attachment.name;
return attachmentName && error.matcherResult?.actual.endsWith(attachmentName);
return attachmentName && error.actual.endsWith(attachmentName);
});
const errorSuffix = ['Call log:',
...(error.matcherResult.log?.map(line => ' - ' + line) || []),
...(error.log?.map(line => ' - ' + line) || []),
'',
error.snippet,
'',
error.callStack,
].join('\n');
if (matchingDiff) {
return {
type: 'screenshot',
diff: matchingDiff,
errorPrefix: error.matcherResult?.message,
errorPrefix: error.shortMessage,
errorSuffix
};
}

View file

@ -83,19 +83,15 @@ export type TestCase = Omit<TestCaseSummary, 'results'> & {
results: TestResult[];
};
type MatcherResult = {
name: string;
message?: string;
log?: string[];
expected?: any;
actual?: any;
};
export type ErrorDetails = {
message: string;
location?: Location;
matcherResult?: MatcherResult;
shortMessage?: string;
log?: string[];
expected?: any;
actual?: any;
snippet?: string;
callStack?: string;
};
export type TestAttachment = {

View file

@ -29,19 +29,20 @@ type Annotation = {
location?: Location;
};
type MatcherResult = {
name: string;
message?: string;
log?: string[];
expected?: any;
actual?: any;
};
type ErrorDetails = {
message: string;
location?: Location;
matcherResult?: MatcherResult;
callStack?: string;
};
type TestResultErrorDetails = ErrorDetails & {
shortMessage?: string;
log?: string[];
expected?: any;
actual?: any;
snippet?: string;
stack?: string;
};
type TestSummary = {
@ -374,8 +375,8 @@ function quotePathIfNeeded(path: string): string {
return path;
}
export function formatResultFailure(test: TestCase, result: TestResult, initialIndent: string, highlightCode: boolean): ErrorDetails[] {
const errorDetails: ErrorDetails[] = [];
export function formatResultFailure(test: TestCase, result: TestResult, initialIndent: string, highlightCode: boolean): TestResultErrorDetails[] {
const errorDetails: TestResultErrorDetails[] = [];
if (result.status === 'passed' && test.expectedStatus === 'failed') {
errorDetails.push({
@ -393,8 +394,12 @@ export function formatResultFailure(test: TestCase, result: TestResult, initialI
errorDetails.push({
message: indent(formattedError.message, initialIndent),
location: formattedError.location,
matcherResult: error.matcherResult,
shortMessage: error.shortMessage,
log: error.log,
expected: error.expected,
actual: error.actual,
snippet: error.snippet,
callStack: formattedError.callStack,
});
}
return errorDetails;
@ -474,9 +479,12 @@ export function formatError(error: TestError, highlightCode: boolean): ErrorDeta
tokens.push(snippet);
}
let callStack;
if (parsedStack && parsedStack.stackLines.length) {
tokens.push('');
tokens.push(colors.dim(parsedStack.stackLines.join('\n')));
// TODO: pass raw lines.
callStack = colors.dim(parsedStack.stackLines.join('\n'));
}
let location = error.location;
@ -486,6 +494,7 @@ export function formatError(error: TestError, highlightCode: boolean): ErrorDeta
return {
location,
message: tokens.join('\n'),
callStack,
};
}

View file

@ -222,7 +222,8 @@ class JSONReporter implements ReporterV2 {
}
private _serializeError(error: TestError): JSONReportError {
return formatError(error, true);
const { message, location } = formatError(error, true);
return { message, location };
}
private _serializeTestStep(step: TestStep): JSONReportTestStep {

View file

@ -30,26 +30,25 @@ import type { MatcherResult } from './matchers/matcherHint';
const PLAYWRIGHT_TEST_PATH = path.join(__dirname, '..');
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 + ': ' : '';
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') || []));
return {
matcherResult: filterMatcherResult(e),
...filterExpectDetails(e),
message: name + e.message,
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>;
if (!matcherResult)
return undefined;
return {};
return {
name: matcherResult.name,
message: matcherResult.shortMessage,
shortMessage: matcherResult.shortMessage,
log: matcherResult.log,
expected: matcherResult.expected,
actual: matcherResult.actual,

View file

@ -8380,31 +8380,30 @@ export interface TestInfo {
*/
export interface TestInfoError {
/**
* Expect matcher result.
* Actual value.
*/
matcherResult?: {
name: string;
actual?: any;
/**
* Failure message
* Expected value.
*/
message?: string;
/**
* Call log
*/
log?: Array<string>;
expected?: any;
actual?: any;
};
/**
* Call log.
*/
log?: Array<string>;
/**
* Error message. Set when [Error] (or its subclass) has been thrown.
*/
message?: string;
/**
* Failure message.
*/
shortMessage?: string;
/**
* Error stack. Set when [Error] (or its subclass) has been thrown.
*/

View file

@ -554,37 +554,36 @@ export interface TestCase {
* Information about an error thrown during test execution.
*/
export interface TestError {
/**
* Actual value.
*/
actual?: any;
/**
* Expected value.
*/
expected?: any;
/**
* Error location in the source code.
*/
location?: Location;
/**
* Expect matcher result.
*/
matcherResult?: {
name: string;
/**
* Failure message
*/
message?: string;
/**
* Call log
* Call log.
*/
log?: Array<string>;
expected?: any;
actual?: any;
};
/**
* Error message. Set when [Error] (or its subclass) has been thrown.
*/
message?: string;
/**
* Failure message.
*/
shortMessage?: string;
/**
* Source code snippet with highlighted error.
*/