-
+
+
-
- >
+
+ );
+};
+
+export const CodeSnippet = ({ code, children, testId }: React.PropsWithChildren<{ code: string; testId?: string; }>) => {
+ const html = React.useMemo(() => ansiErrorToHtml(code), [code]);
+ return (
+
);
};
const ansiRegex = new RegExp('([\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~])))', 'g');
-export function stripAnsiEscapes(str: string): string {
+function stripAnsiEscapes(str: string): string {
return str.replace(ansiRegex, '');
}
const PromptButton: React.FC<{
error: string;
-}> = ({ error }) => {
- const [copied, setCopied] = React.useState(false);
+ result?: TestResult;
+}> = ({ error, result }) => {
const gitCommitInfo = React.useContext(GitCommitInfoContext);
- if (!gitCommitInfo)
- return undefined;
+ const prompt = React.useMemo(() => {
+ const diff = gitCommitInfo?.['pull.diff'] ?? gitCommitInfo?.['revision.diff'];
+ const pageSnapshot = result?.attachments.find(a => a.name === 'pageSnapshot')?.body;
- const diff = gitCommitInfo['pull.diff'] ?? gitCommitInfo['revision.diff'];
- if (!diff)
- return undefined;
+ return [
+ 'You are a helpful assistant. Help me understand the error cause. Here is the error:',
+ stripAnsiEscapes(error),
+ 'And this is the code diff:',
+ diff,
+ 'And this is how the page looked:',
+ pageSnapshot,
+ ].join('\n\n');
+ }, [gitCommitInfo, result])
- const showFireworks = () => {
- const fireworksContainer = document.createElement('div');
- fireworksContainer.className = 'fireworks-container';
- document.body.appendChild(fireworksContainer);
-
- setTimeout(() => {
- document.body.removeChild(fireworksContainer);
- }, 2000);
- };
-
- return (
-
- );
+ return
} title="Copy prompt to clipboard" />;
};
export const TestScreenshotErrorView: React.FC<{
diff --git a/packages/html-reporter/src/testResultView.tsx b/packages/html-reporter/src/testResultView.tsx
index 502edbd23e..41054a9a41 100644
--- a/packages/html-reporter/src/testResultView.tsx
+++ b/packages/html-reporter/src/testResultView.tsx
@@ -24,7 +24,7 @@ import { Anchor, AttachmentLink, generateTraceUrl, testResultHref } from './link
import { statusIcon } from './statusIcon';
import type { ImageDiff } from '@web/shared/imageDiffView';
import { ImageDiffView } from '@web/shared/imageDiffView';
-import { TestErrorView, TestScreenshotErrorView } from './testErrorView';
+import { CodeSnippet, PromptButton, TestErrorView, TestScreenshotErrorView } from './testErrorView';
import * as icons from './icons';
import './testResultView.css';
@@ -90,7 +90,7 @@ export const TestResultView: React.FC<{
{errors.map((error, index) => {
if (error.type === 'screenshot')
return
;
- return
;
+ return
;
})}
}
{!!result.steps.length &&
@@ -182,7 +182,7 @@ const StepTreeItem: React.FC<{
{step.count > 1 && <> ✕ {step.count}>}
{step.location && — {step.location.file}:{step.location.line}}
} loadChildren={step.steps.length || step.snippet ? () => {
- const snippet = step.snippet ? [] : [];
+ const snippet = step.snippet ? [] : [];
const steps = step.steps.map((s, i) => );
return snippet.concat(steps);
} : undefined} depth={depth}/>;
diff --git a/packages/playwright/src/reporters/html.ts b/packages/playwright/src/reporters/html.ts
index e258f22798..1cfc0c6040 100644
--- a/packages/playwright/src/reporters/html.ts
+++ b/packages/playwright/src/reporters/html.ts
@@ -446,6 +446,17 @@ class HtmlBuilder {
return a;
}
+ if (a.name === 'pageSnapshot') {
+ try {
+ const body = fs.readFileSync(a.path!, { encoding: 'utf-8' });
+ return {
+ name: 'pageSnapshot',
+ contentType: a.contentType,
+ body,
+ }
+ } catch {}
+ }
+
if (a.path) {
let fileName = a.path;
try {