chore: fix the test view mobile layout (#23061)

Fixes https://github.com/microsoft/playwright/issues/23036
This commit is contained in:
Pavel Feldman 2023-05-16 12:47:37 -07:00 committed by GitHub
parent 62146b946c
commit 37b2853b7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 31 additions and 66 deletions

View File

@ -21,7 +21,6 @@
background-color: var(--color-canvas-subtle);
padding: 0 8px;
border-bottom: none;
margin-top: 24px;
font-weight: 600;
line-height: 38px;
white-space: nowrap;

View File

@ -50,7 +50,6 @@ test('should toggle filters', async ({ page, mount }) => {
}}
filterText=''
setFilterText={(filterText: string) => filters.push(filterText)}
projectNames={[]}
>
</HeaderView>);
await component.locator('a', { hasText: 'All' }).click();
@ -64,52 +63,3 @@ test('should toggle filters', async ({ page, mount }) => {
await expect(page).toHaveURL(/#\?q=s:skipped/);
expect(filters).toEqual(['', 's:passed', 's:failed', 's:flaky', 's:skipped']);
});
test('should show the project names', async ({ mount }) => {
const stats = {
total: 100,
expected: 42,
unexpected: 31,
flaky: 17,
skipped: 10,
ok: false,
duration: 100000
};
await test.step('with 1 project', async () => {
const component = await mount(<HeaderView
stats={stats}
filterText=''
setFilterText={() => {}}
projectNames={['my-project']}
>
</HeaderView>);
await expect(component.getByText('Project: my-project')).toBeVisible();
await component.unmount();
});
await test.step('with 1 project and empty projectName', async () => {
const component = await mount(<HeaderView
stats={stats}
filterText=''
setFilterText={() => {}}
projectNames={['']}
>
</HeaderView>);
await expect(component.getByText('Project:')).toBeHidden();
await component.unmount();
});
await test.step('with more than 1 project', async () => {
const component = await mount(<HeaderView
stats={stats}
filterText=''
setFilterText={() => {}}
projectNames={['great-project', 'my-project']}
>
</HeaderView>);
await expect(component.getByText('my-project')).toBeHidden();
await expect(component.getByText('great-project')).toBeHidden();
await component.unmount();
});
});

View File

@ -22,14 +22,12 @@ import './headerView.css';
import * as icons from './icons';
import { Link, navigate } from './links';
import { statusIcon } from './statusIcon';
import { msToString } from './uiUtils';
export const HeaderView: React.FC<React.PropsWithChildren<{
stats: Stats,
filterText: string,
setFilterText: (filterText: string) => void,
projectNames: string[],
}>> = ({ stats, filterText, setFilterText, projectNames }) => {
}>> = ({ stats, filterText, setFilterText }) => {
React.useEffect(() => {
const popstateFn = () => {
const params = new URLSearchParams(window.location.hash.slice(1));
@ -60,10 +58,6 @@ export const HeaderView: React.FC<React.PropsWithChildren<{
}}></input>
</form>
</div>
<div className='pt-2'>
{projectNames.length === 1 && !!projectNames[0] && <span data-testid="project-name" style={{ color: 'var(--color-fg-subtle)', float: 'left' }}>Project: {projectNames[0]}</span>}
<span data-testid="overall-duration" style={{ color: 'var(--color-fg-subtle)', paddingRight: '10px', float: 'right' }}>Total time: {msToString(stats.duration)}</span>
</div>
</>);
};

View File

@ -55,7 +55,7 @@ test('should switch to actual', async ({ mount }) => {
for (let i = 0; i < imageCount; ++i) {
const image = images.nth(i);
const box = await image.boundingBox();
expect(box).toEqual({ x: 400, y: 108, width: 200, height: 200 });
expect(box).toEqual({ x: 400, y: 124, width: 200, height: 200 });
}
});
@ -70,7 +70,7 @@ test('should switch to expected', async ({ mount }) => {
for (let i = 0; i < imageCount; ++i) {
const image = images.nth(i);
const box = await image.boundingBox();
expect(box).toEqual({ x: 400, y: 108, width: 200, height: 200 });
expect(box).toEqual({ x: 400, y: 124, width: 200, height: 200 });
}
});
@ -79,5 +79,5 @@ test('should show diff by default', async ({ mount }) => {
const image = component.locator('img');
const box = await image.boundingBox();
expect(box).toEqual({ x: 400, y: 108, width: 200, height: 200 });
expect(box).toEqual({ x: 400, y: 124, width: 200, height: 200 });
});

View File

@ -50,10 +50,17 @@ export const ReportView: React.FC<{
return <div className='htmlreport vbox px-4 pb-4'>
<main>
{report?.json() && <HeaderView stats={report.json().stats} filterText={filterText} setFilterText={setFilterText} projectNames={report.json().projectNames}></HeaderView>}
{report?.json() && <HeaderView stats={report.json().stats} filterText={filterText} setFilterText={setFilterText}></HeaderView>}
{report?.json().metadata && <MetadataView {...report?.json().metadata as Metainfo} />}
<Route predicate={testFilesRoutePredicate}>
<TestFilesView report={report?.json()} filter={filter} expandedFiles={expandedFiles} setExpandedFiles={setExpandedFiles}></TestFilesView>
<TestFilesView
report={report?.json()}
filter={filter}
expandedFiles={expandedFiles}
setExpandedFiles={setExpandedFiles}
projectNames={report?.json().projectNames || []}
stats={report?.json().stats || { duration: 0 }}
/>
</Route>
<Route predicate={testCaseRoutePredicate}>
{!!report && <TestCaseViewLoader report={report}></TestCaseViewLoader>}

View File

@ -33,6 +33,7 @@
height: 48px;
min-width: 70px;
box-shadow: inset 0 -1px 0 var(--color-border-muted) !important;
margin-bottom: 16px;
}
.tabbed-pane-tab-strip:focus {

View File

@ -42,7 +42,8 @@
line-height: 1.25 !important;
}
.test-case-location {
.test-case-location,
.test-case-duration {
flex: none;
align-items: center;
padding: 0 8px 24px;

View File

@ -24,6 +24,7 @@ import { statusIcon } from './statusIcon';
import './testCaseView.css';
import { TestResultView } from './testResultView';
import { hashStringToInt, matchTags } from './labelUtils';
import { msToString } from './uiUtils';
export const TestCaseView: React.FC<{
projectNames: string[],
@ -42,7 +43,11 @@ export const TestCaseView: React.FC<{
return <div className='test-case-column vbox'>
{test && <div className='test-case-path'>{test.path.join(' ')}</div>}
{test && <div className='test-case-title'>{test?.title}</div>}
{test && <div className='test-case-location'>{test.location.file}:{test.location.line}</div>}
{test && <div className='hbox'>
<div className='test-case-location'>{test.location.file}:{test.location.line}</div>
<div style={{ flex: 'auto' }}></div>
<div className='test-case-duration'>{msToString(test.duration)}</div>
</div>}
{test && (!!test.projectName || labels) && <div className='test-case-project-labels-row'>
{test && !!test.projectName && <ProjectLink projectNames={projectNames} projectName={test.projectName}></ProjectLink>}
{labels && <LabelsLinkView labels={labels} />}

View File

@ -19,13 +19,16 @@ import * as React from 'react';
import type { Filter } from './filter';
import { TestFileView } from './testFileView';
import './testFileView.css';
import { msToString } from './uiUtils';
export const TestFilesView: React.FC<{
report?: HTMLReport,
expandedFiles: Map<string, boolean>,
setExpandedFiles: (value: Map<string, boolean>) => void,
filter: Filter,
}> = ({ report, filter, expandedFiles, setExpandedFiles }) => {
stats: { duration: number },
projectNames: string[],
}> = ({ report, filter, expandedFiles, setExpandedFiles, projectNames, stats }) => {
const filteredFiles = React.useMemo(() => {
const result: { file: TestFileSummary, defaultExpanded: boolean }[] = [];
let visibleTests = 0;
@ -38,6 +41,11 @@ export const TestFilesView: React.FC<{
return result;
}, [report, filter]);
return <>
<div className='p-2' style={{ display: 'flex' }}>
{projectNames.length === 1 && !!projectNames[0] && <div data-testid="project-name" style={{ color: 'var(--color-fg-subtle)' }}>Project: {projectNames[0]}</div>}
<div style={{ flex: 'auto' }}></div>
<div data-testid="overall-duration" style={{ color: 'var(--color-fg-subtle)' }}>Total time: {msToString(stats.duration)}</div>
</div>
{report && filteredFiles.map(({ file, defaultExpanded }) => {
return <TestFileView
key={`file-${file.fileId}`}