,
-}> = ({ header, initialExpanded, noInsets, children, dataTestId, targetRef }) => {
- const [expanded, setExpanded] = React.useState(initialExpanded || initialExpanded === undefined);
- return
- {children}
- ;
+ revealId?: string,
+}> = ({ header, initialExpanded, noInsets, children, dataTestId, revealId }) => {
+ const [expanded, setExpanded] = React.useState(initialExpanded ?? true);
+ const onChangeReveal = React.useCallback((isRevealed: boolean) => {
+ if (isRevealed)
+ setExpanded(true);
+ }, [setExpanded]);
+ return
+
+ {children}
+
+ ;
};
diff --git a/packages/html-reporter/src/links.tsx b/packages/html-reporter/src/links.tsx
index 4b48090e0a..1db8bd9b2d 100644
--- a/packages/html-reporter/src/links.tsx
+++ b/packages/html-reporter/src/links.tsx
@@ -113,3 +113,30 @@ export function generateTraceUrl(traces: TestAttachment[]) {
}
const kMissingContentType = 'x-playwright/missing';
+
+
+export function useRevealed(revealId?: string) {
+ const searchParams = React.useContext(SearchParamsContext);
+ if (revealId === undefined)
+ return false;
+ return searchParams.get('reveal') === revealId;
+}
+
+export function Reveal({ revealId, onChange, children }: React.PropsWithChildren<{ revealId?: string, onChange?(isRevealed: boolean, ref: HTMLDivElement): void }>) {
+ const isRevealed = useRevealed(revealId);
+
+ const ref = React.useRef
(null);
+ React.useEffect(() => {
+ if (!ref.current)
+ return;
+
+ const preventDefault = onChange?.(isRevealed, ref.current);
+ if (preventDefault)
+ return;
+
+ if (isRevealed)
+ ref.current?.scrollIntoView({ block: 'start', inline: 'start' });
+ }, [isRevealed, onChange]);
+
+ return {children}
;
+}
diff --git a/packages/html-reporter/src/reportView.tsx b/packages/html-reporter/src/reportView.tsx
index e8a5c3b250..cf0f5e5e56 100644
--- a/packages/html-reporter/src/reportView.tsx
+++ b/packages/html-reporter/src/reportView.tsx
@@ -101,7 +101,6 @@ const TestCaseViewLoader: React.FC<{
const searchParams = React.useContext(SearchParamsContext);
const [test, setTest] = React.useState();
const testId = searchParams.get('testId');
- const anchor = (searchParams.get('anchor') || '') as 'video' | 'diff' | '';
const run = +(searchParams.get('run') || '0');
const { prev, next } = React.useMemo(() => {
@@ -133,7 +132,6 @@ const TestCaseViewLoader: React.FC<{
next={next}
prev={prev}
test={test}
- anchor={anchor}
run={run}
/>;
};
diff --git a/packages/html-reporter/src/testCaseView.spec.tsx b/packages/html-reporter/src/testCaseView.spec.tsx
index 892ad51b7f..b7a9f9405b 100644
--- a/packages/html-reporter/src/testCaseView.spec.tsx
+++ b/packages/html-reporter/src/testCaseView.spec.tsx
@@ -63,7 +63,7 @@ const testCase: TestCase = {
};
test('should render test case', async ({ mount }) => {
- const component = await mount();
+ const component = await mount();
await expect(component.getByText('Annotation text', { exact: false }).first()).toBeVisible();
await expect(component.getByText('Hidden annotation')).toBeHidden();
await component.getByText('Annotations').click();
@@ -79,7 +79,7 @@ test('should render test case', async ({ mount }) => {
test('should render copy buttons for annotations', async ({ mount, page, context }) => {
await context.grantPermissions(['clipboard-read', 'clipboard-write']);
- const component = await mount();
+ const component = await mount();
await expect(component.getByText('Annotation text', { exact: false }).first()).toBeVisible();
await component.getByText('Annotation text', { exact: false }).first().hover();
await expect(component.locator('.test-case-annotation').getByLabel('Copy to clipboard').first()).toBeVisible();
@@ -108,7 +108,7 @@ const annotationLinkRenderingTestCase: TestCase = {
};
test('should correctly render links in annotations', async ({ mount }) => {
- const component = await mount();
+ const component = await mount();
const firstLink = await component.getByText('https://playwright.dev/docs/intro').first();
await expect(firstLink).toBeVisible();
@@ -181,7 +181,7 @@ const testCaseSummary: TestCaseSummary = {
test('should correctly render links in attachments', async ({ mount }) => {
- const component = await mount();
+ const component = await mount();
await component.getByText('first attachment').click();
const body = await component.getByText('The body with https://playwright.dev/docs/intro link');
await expect(body).toBeVisible();
@@ -194,7 +194,7 @@ test('should correctly render links in attachments', async ({ mount }) => {
});
test('should correctly render links in attachment name', async ({ mount }) => {
- const component = await mount();
+ const component = await mount();
const link = component.getByText('attachment with inline link').locator('a');
await expect(link).toHaveAttribute('href', 'https://github.com/microsoft/playwright/issues/31284');
await expect(link).toHaveText('https://github.com/microsoft/playwright/issues/31284');
@@ -204,7 +204,7 @@ test('should correctly render links in attachment name', async ({ mount }) => {
});
test('should correctly render prev and next', async ({ mount }) => {
- const component = await mount();
+ const component = await mount();
await expect(component).toMatchAriaSnapshot(`
- text: group
- link "« previous"
diff --git a/packages/html-reporter/src/testCaseView.tsx b/packages/html-reporter/src/testCaseView.tsx
index 320722fa9b..4e9785ad8a 100644
--- a/packages/html-reporter/src/testCaseView.tsx
+++ b/packages/html-reporter/src/testCaseView.tsx
@@ -33,9 +33,8 @@ export const TestCaseView: React.FC<{
test: TestCase | undefined,
next: TestCaseSummary | undefined,
prev: TestCaseSummary | undefined,
- anchor: 'video' | 'diff' | '',
run: number,
-}> = ({ projectNames, test, run, anchor, next, prev }) => {
+}> = ({ projectNames, test, run, next, prev }) => {
const [selectedResultIndex, setSelectedResultIndex] = React.useState(run);
const searchParams = React.useContext(SearchParamsContext);
const filterParam = searchParams.has('q') ? '&q=' + searchParams.get('q') : '';
@@ -79,7 +78,7 @@ export const TestCaseView: React.FC<{
test.results.map((result, index) => ({
id: String(index),
title: {statusIcon(result.status)} {retryLabel(index)}
,
- render: () =>
+ render: () =>
})) || []} selectedTab={String(selectedResultIndex)} setSelectedTab={id => setSelectedResultIndex(+id)} />}
;
};
diff --git a/packages/html-reporter/src/testFileView.tsx b/packages/html-reporter/src/testFileView.tsx
index 4d6890ad33..52a79ab7b4 100644
--- a/packages/html-reporter/src/testFileView.tsx
+++ b/packages/html-reporter/src/testFileView.tsx
@@ -75,12 +75,12 @@ function imageDiffBadge(test: TestCaseSummary): JSX.Element | undefined {
const resultWithImageDiff = test.results.find(result => result.attachments.some(attachment => {
return attachment.contentType.startsWith('image/') && !!attachment.name.match(/-(expected|actual|diff)/);
}));
- return resultWithImageDiff ?
{image()} : undefined;
+ return resultWithImageDiff ?
{image()} : undefined;
}
function videoBadge(test: TestCaseSummary): JSX.Element | undefined {
const resultWithVideo = test.results.find(result => result.attachments.some(attachment => attachment.name === 'video'));
- return resultWithVideo ?
{video()} : undefined;
+ return resultWithVideo ?
{video()} : undefined;
}
function traceBadge(test: TestCaseSummary): JSX.Element | undefined {
diff --git a/packages/html-reporter/src/testResultView.tsx b/packages/html-reporter/src/testResultView.tsx
index 3a562f3fcf..79a4331ac7 100644
--- a/packages/html-reporter/src/testResultView.tsx
+++ b/packages/html-reporter/src/testResultView.tsx
@@ -64,9 +64,7 @@ function groupImageDiffs(screenshots: Set
): ImageDiff[] {
export const TestResultView: React.FC<{
test: TestCase,
result: TestResult,
- anchor: 'video' | 'diff' | '',
-}> = ({ result, anchor }) => {
-
+}> = ({ result }) => {
const { screenshots, videos, traces, otherAttachments, diffs, errors, htmls } = React.useMemo(() => {
const attachments = result?.attachments || [];
const screenshots = new Set(attachments.filter(a => a.contentType.startsWith('image/')));
@@ -80,20 +78,6 @@ export const TestResultView: React.FC<{
return { screenshots: [...screenshots], videos, traces, otherAttachments, diffs, errors, htmls };
}, [result]);
- const videoRef = React.useRef(null);
- const imageDiffRef = React.useRef(null);
-
- const [scrolled, setScrolled] = React.useState(false);
- React.useEffect(() => {
- if (scrolled)
- return;
- setScrolled(true);
- if (anchor === 'video')
- videoRef.current?.scrollIntoView({ block: 'start', inline: 'start' });
- if (anchor === 'diff')
- imageDiffRef.current?.scrollIntoView({ block: 'start', inline: 'start' });
- }, [scrolled, anchor, setScrolled, videoRef]);
-
return
{!!errors.length &&
{errors.map((error, index) => {
@@ -107,8 +91,8 @@ export const TestResultView: React.FC<{
}
{diffs.map((diff, index) =>
-
-
+
+
)}
@@ -132,7 +116,7 @@ export const TestResultView: React.FC<{
}
}
- {!!videos.length &&
+ {!!videos.length &&
{videos.map((a, i) =>