diff --git a/packages/html-reporter/playwright.config.ts b/packages/html-reporter/playwright.config.ts
index 39f093f84e..cfeb7b0afa 100644
--- a/packages/html-reporter/playwright.config.ts
+++ b/packages/html-reporter/playwright.config.ts
@@ -21,6 +21,11 @@ const config: PlaywrightTestConfig = {
snapshotDir: 'snapshots',
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
+ reporter: process.env.CI ? [
+ ['html', { open: 'never' }],
+ ] : [
+ ['html', { open: 'on-failure' }]
+ ],
use: {
trace: 'on-first-retry',
},
diff --git a/packages/html-reporter/screenshots/chip-spec-tsx-expand-collapse-collapsed.png b/packages/html-reporter/screenshots/chip-spec-tsx-expand-collapse-collapsed.png
new file mode 100644
index 0000000000..754825671b
Binary files /dev/null and b/packages/html-reporter/screenshots/chip-spec-tsx-expand-collapse-collapsed.png differ
diff --git a/packages/html-reporter/screenshots/chip-spec-tsx-expand-collapse-expanded.png b/packages/html-reporter/screenshots/chip-spec-tsx-expand-collapse-expanded.png
new file mode 100644
index 0000000000..7470a497a6
Binary files /dev/null and b/packages/html-reporter/screenshots/chip-spec-tsx-expand-collapse-expanded.png differ
diff --git a/packages/html-reporter/screenshots/chip-spec-tsx-render-long-title-long-title.png b/packages/html-reporter/screenshots/chip-spec-tsx-render-long-title-long-title.png
new file mode 100644
index 0000000000..56792f2a32
Binary files /dev/null and b/packages/html-reporter/screenshots/chip-spec-tsx-render-long-title-long-title.png differ
diff --git a/packages/html-reporter/screenshots/headerView-spec-tsx-should-render-counters-counters.png b/packages/html-reporter/screenshots/headerView-spec-tsx-should-render-counters-counters.png
new file mode 100644
index 0000000000..a667a752bd
Binary files /dev/null and b/packages/html-reporter/screenshots/headerView-spec-tsx-should-render-counters-counters.png differ
diff --git a/packages/html-reporter/screenshots/testCaseView-spec-tsx-should-render-test-case-testcase-expanded.png b/packages/html-reporter/screenshots/testCaseView-spec-tsx-should-render-test-case-testcase-expanded.png
new file mode 100644
index 0000000000..07512656f5
Binary files /dev/null and b/packages/html-reporter/screenshots/testCaseView-spec-tsx-should-render-test-case-testcase-expanded.png differ
diff --git a/packages/html-reporter/screenshots/testCaseView-spec-tsx-should-render-test-case-testcase.png b/packages/html-reporter/screenshots/testCaseView-spec-tsx-should-render-test-case-testcase.png
new file mode 100644
index 0000000000..144ed6c3ec
Binary files /dev/null and b/packages/html-reporter/screenshots/testCaseView-spec-tsx-should-render-test-case-testcase.png differ
diff --git a/packages/html-reporter/src/chip.spec.tsx b/packages/html-reporter/src/chip.spec.tsx
index 7b75d45cde..b0bbf9e2db 100644
--- a/packages/html-reporter/src/chip.spec.tsx
+++ b/packages/html-reporter/src/chip.spec.tsx
@@ -15,36 +15,36 @@
*/
import React from 'react';
-import { test, expect } from '../test/componentTest';
-import { Chip, AutoChip } from './chip';
+import { expect, test } from '../test/componentTest';
+import { AutoChip, Chip } from './chip';
test.use({ webpack: require.resolve('../webpack.config.js') });
test.use({ viewport: { width: 500, height: 500 } });
-test('chip expand collapse', async ({ render }) => {
+test('expand collapse', async ({ render, capture }) => {
const component = await render(
Chip body
);
await expect(component.locator('text=Chip body')).toBeVisible();
- // expect(await component.screenshot()).toMatchSnapshot('expanded.png');
+ await capture(component, 'expanded');
await component.locator('text=Title').click();
await expect(component.locator('text=Chip body')).not.toBeVisible();
- // expect(await component.screenshot()).toMatchSnapshot('collapsed.png');
+ await capture(component, 'collapsed');
await component.locator('text=Title').click();
await expect(component.locator('text=Chip body')).toBeVisible();
- // expect(await component.screenshot()).toMatchSnapshot('expanded.png');
});
-test('chip render long title', async ({ render }) => {
+test('render long title', async ({ render, capture }) => {
const title = 'Extremely long title. '.repeat(10);
const component = await render(
Chip body
);
await expect(component).toContainText('Extremely long title.');
await expect(component.locator('text=Extremely long title.')).toHaveAttribute('title', title);
+ await capture(component, 'long-title');
});
-test('chip setExpanded is called', async ({ render }) => {
+test('setExpanded is called', async ({ render, capture }) => {
const expandedValues: boolean[] = [];
const component = await render( expandedValues.push(expanded)}>
diff --git a/packages/html-reporter/src/headerView.spec.tsx b/packages/html-reporter/src/headerView.spec.tsx
index 39d7f276d2..399d60c951 100644
--- a/packages/html-reporter/src/headerView.spec.tsx
+++ b/packages/html-reporter/src/headerView.spec.tsx
@@ -21,7 +21,7 @@ import { HeaderView } from './headerView';
test.use({ webpack: require.resolve('../webpack.config.js') });
test.use({ viewport: { width: 720, height: 200 } });
-test('should render counters', async ({ render }) => {
+test('should render counters', async ({ render, capture }) => {
const component = await render( {
await expect(component.locator('a', { hasText: 'Failed' }).locator('.counter')).toHaveText('31');
await expect(component.locator('a', { hasText: 'Flaky' }).locator('.counter')).toHaveText('17');
await expect(component.locator('a', { hasText: 'Skipped' }).locator('.counter')).toHaveText('10');
+ await capture(component, 'counters');
});
test('should toggle filters', async ({ page, render: render }) => {
diff --git a/packages/html-reporter/src/testCaseView.spec.tsx b/packages/html-reporter/src/testCaseView.spec.tsx
index 39ce0c57a3..628cb976fc 100644
--- a/packages/html-reporter/src/testCaseView.spec.tsx
+++ b/packages/html-reporter/src/testCaseView.spec.tsx
@@ -59,8 +59,9 @@ const testCase: TestCase = {
results: [result]
};
-test('should render counters', async ({ render }) => {
+test('should render test case', async ({ render, capture }) => {
const component = await render();
+ await capture(component, 'testcase');
await expect(component.locator('text=Annotation text').first()).toBeVisible();
await component.locator('text=Annotations').click();
await expect(component.locator('text=Annotation text')).not.toBeVisible();
@@ -70,4 +71,5 @@ test('should render counters', async ({ render }) => {
await expect(component.locator('text=Inner step')).toBeVisible();
await expect(component.locator('text=test.spec.ts:42')).toBeVisible();
await expect(component.locator('text=My test')).toBeVisible();
+ await capture(component, 'testcase-expanded');
});
diff --git a/packages/html-reporter/src/testResultView.tsx b/packages/html-reporter/src/testResultView.tsx
index dbf804d74e..64cc27109d 100644
--- a/packages/html-reporter/src/testResultView.tsx
+++ b/packages/html-reporter/src/testResultView.tsx
@@ -26,6 +26,8 @@ import { AttachmentLink } from './links';
import { statusIcon } from './statusIcon';
import './testResultView.css';
+const imageDiffNames = ['expected', 'actual', 'diff'];
+
export const TestResultView: React.FC<{
test: TestCase,
result: TestResult,
@@ -34,16 +36,13 @@ export const TestResultView: React.FC<{
const { screenshots, videos, traces, otherAttachments, attachmentsMap } = React.useMemo(() => {
const attachmentsMap = new Map();
const attachments = result?.attachments || [];
- const otherAttachments: TestAttachment[] = [];
- const screenshots = attachments.filter(a => a.name === 'screenshot');
+ const otherAttachments = new Set(attachments);
+ const screenshots = attachments.filter(a => a.contentType.startsWith('image/') && !imageDiffNames.includes(a.name));
const videos = attachments.filter(a => a.name === 'video');
const traces = attachments.filter(a => a.name === 'trace');
- const knownNames = new Set(['screenshot', 'image', 'expected', 'actual', 'diff', 'video', 'trace']);
- for (const a of attachments) {
+ for (const a of attachments)
attachmentsMap.set(a.name, a);
- if (!knownNames.has(a.name))
- otherAttachments.push(a);
- }
+ [...screenshots, ...videos, ...traces].forEach(a => otherAttachments.delete(a));
return { attachmentsMap, screenshots, videos, otherAttachments, traces };
}, [ result ]);
@@ -92,8 +91,8 @@ export const TestResultView: React.FC<{
)}
}
- {!!otherAttachments.length &&
- {otherAttachments.map((a, i) => )}
+ {!!otherAttachments.size &&
+ {[...otherAttachments].map((a, i) => )}
}
;
};
diff --git a/packages/html-reporter/test/componentTest.ts b/packages/html-reporter/test/componentTest.ts
index bac8e2de4a..3511c571e4 100644
--- a/packages/html-reporter/test/componentTest.ts
+++ b/packages/html-reporter/test/componentTest.ts
@@ -25,6 +25,7 @@ declare global {
type TestFixtures = {
render: (component: { type: string, props: Object }) => Promise;
+ capture: (locator: Locator, name: string) => Promise;
webpack: string;
};
@@ -68,6 +69,18 @@ export const test = baseTest.extend({
return page.locator('#pw-root');
});
},
+
+ capture: async ({}, use, testInfo) => {
+ await use(async (locator: Locator, name: string) => {
+ const screenshotPath = path.join(__dirname, '..', 'screenshots', sanitizeForFilePath(path.basename(testInfo.file) + '-' + testInfo.title + '-' + name) + '.png');
+ testInfo.attachments.push({ name, path: screenshotPath, contentType: 'image/png' });
+ await locator.screenshot({ path: screenshotPath });
+ });
+ }
});
+export function sanitizeForFilePath(s: string) {
+ return s.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, '-');
+}
+
export { expect } from '@playwright/test';