Skip to content

feat(ui-mode): enhance status-line to show passed, failed, and skipped test counts #35859

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions packages/trace-viewer/src/ui/statusLine.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

.status-line {
display: block;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be display: flex with align-items: center. You'll have to fix some other things, but as it is the ellipsis is misaligned from the text baseline as it's not currently vertically centered.

width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 30px;
height: 30px;
margin-left: 5px;
cursor: default;
}

.status-line > span:not(:first-child) {
display: inline-flex;
align-items: center;
gap: 4px;
user-select: none;
margin-left: 8px;
}

.status-line-count {
display: inline-flex;
align-items: center;
gap: 8px;
}

.status-passed {
color: var(--vscode-debugIcon-restartForeground);
}

.status-failed {
color: var(--vscode-list-errorForeground);
}

.status-skipped {
color: var(--vscode-foreground);
}
51 changes: 51 additions & 0 deletions packages/trace-viewer/src/ui/statusLine.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import '@web/third_party/vscode/codicon.css';
import '@web/common.css';
import './statusLine.css';
import React from 'react';
import { clsx } from '@web/uiUtils';
import { testStatusIcon } from './testUtils';

interface StatusLineProps {
passed: number;
failed: number;
skipped: number;
total: number;
isRunning: boolean;
}

export const StatusLine: React.FC<StatusLineProps> = ({ passed, failed, skipped, total, isRunning }) => {
const count = passed + failed + skipped;
return (
<div data-testid='status-line' className='status-line' title={`${passed} passed, ${failed} failed, ${skipped} skipped`}>
<span className='status-line-count'>
<i className={clsx('codicon', isRunning ? testStatusIcon('running') : testStatusIcon('none'))} />
<span data-testid='test-count'>{count}/{total}</span>
</span>
<span className='status-passed'>
<i className={clsx('codicon', testStatusIcon('passed'))} />{passed || 0}
</span>
<span className='status-failed'>
<i className={clsx('codicon', testStatusIcon('failed'))} />{failed || 0}
</span>
<span className='status-skipped'>
<i className={clsx('codicon', testStatusIcon('skipped'))} />{skipped || 0}
</span>
</div>
);
};
16 changes: 0 additions & 16 deletions packages/trace-viewer/src/ui/uiModeView.css
Original file line number Diff line number Diff line change
Expand Up @@ -82,22 +82,6 @@
margin-bottom: 30px;
}

.status-line {
flex: auto;
white-space: nowrap;
line-height: 22px;
padding-left: 10px;
display: flex;
flex-direction: row;
align-items: center;
height: 30px;
}

.status-line > div {
overflow: hidden;
text-overflow: ellipsis;
}

.ui-mode-sidebar input[type=search] {
flex: auto;
padding: 0 5px;
Expand Down
15 changes: 8 additions & 7 deletions packages/trace-viewer/src/ui/uiModeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { TestListView } from './uiModeTestListView';
import { TraceView } from './uiModeTraceView';
import { SettingsView } from './settingsView';
import { DefaultSettingsView } from './defaultSettingsView';
import { StatusLine } from './statusLine';

let xtermSize = { cols: 80, rows: 24 };
const xtermDataSource: XtermDataSource = {
Expand Down Expand Up @@ -460,13 +461,13 @@ export const UIModeView: React.FC<{}> = ({
testModel={testModel}
runTests={() => runTests('bounce-if-busy', visibleTestIds)} />
<Toolbar noMinHeight={true}>
{!isRunningTest && !progress && <div className='section-title'>Tests</div>}
{!isRunningTest && progress && <div data-testid='status-line' className='status-line'>
<div>{progress.passed}/{progress.total} passed ({(progress.passed / progress.total) * 100 | 0}%)</div>
</div>}
{isRunningTest && progress && <div data-testid='status-line' className='status-line'>
<div>Running {progress.passed}/{runningState.testIds.size} passed ({(progress.passed / runningState.testIds.size) * 100 | 0}%)</div>
</div>}
<StatusLine
passed={progress?.passed ?? 0}
failed={progress?.failed ?? 0}
skipped={progress?.skipped ?? 0}
total={progress ? (isRunningTest ? runningState.testIds.size : progress.total) : visibleTestIds.size}
isRunning={!!isRunningTest}
/>
<ToolbarButton icon='play' title='Run all — F5' onClick={() => runTests('bounce-if-busy', visibleTestIds)} disabled={isRunningTest || isLoading}></ToolbarButton>
<ToolbarButton icon='debug-stop' title={'Stop — ' + (isMac ? '⇧F5' : 'Shift + F5')} onClick={() => testServerConnection?.stopTests({})} disabled={!isRunningTest || isLoading}></ToolbarButton>
<ToolbarButton icon='eye' title='Watch all' toggled={watchAll} onClick={() => {
Expand Down
6 changes: 5 additions & 1 deletion tests/playwright-test/ui-mode-metadata.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ test('should render html report git info metadata', async ({ runUITest }) => {
});

await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)');
const statusLine = page.getByTestId('status-line');
await expect(statusLine.getByTestId('test-count')).toHaveText('1/1');
await expect(statusLine.locator('.status-passed')).toHaveText('1');
await expect(statusLine.locator('.status-failed')).toHaveText('0');
await expect(statusLine.locator('.status-skipped')).toHaveText('0');
await page.getByTitle('Toggle output').click();

await expect(page.getByTestId('output')).toContainText('ci.link: https://playwright.dev');
Expand Down
6 changes: 5 additions & 1 deletion tests/playwright-test/ui-mode-test-annotations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ test('should display annotations', async ({ runUITest }) => {
`,
});
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)');
const statusLine = page.getByTestId('status-line');
await expect(statusLine.getByTestId('test-count')).toHaveText('1/1');
await expect(statusLine.locator('.status-passed')).toHaveText('1');
await expect(statusLine.locator('.status-failed')).toHaveText('0');
await expect(statusLine.locator('.status-skipped')).toHaveText('0');
await page.getByRole('treeitem', { name: 'suite' }).locator('.codicon-chevron-right').click();
await page.getByText('annotation test').click();
await page.getByText('Annotations', { exact: true }).click();
Expand Down
30 changes: 25 additions & 5 deletions tests/playwright-test/ui-mode-test-attachments.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ test('should contain text attachment', async ({ runUITest }) => {
});
await page.getByText('attach test').click();
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)');
const statusLine = page.getByTestId('status-line');
await expect(statusLine.getByTestId('test-count')).toHaveText('1/1');
await expect(statusLine.locator('.status-passed')).toHaveText('1');
await expect(statusLine.locator('.status-failed')).toHaveText('0');
await expect(statusLine.locator('.status-skipped')).toHaveText('0');
await page.getByText('Attachments').click();

await page.locator('.tab-attachments').getByText('text attachment').click();
Expand Down Expand Up @@ -69,7 +73,11 @@ test('should contain binary attachment', async ({ runUITest }) => {
});
await page.getByText('attach test').click();
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)');
const statusLine = page.getByTestId('status-line');
await expect(statusLine.getByTestId('test-count')).toHaveText('1/1');
await expect(statusLine.locator('.status-passed')).toHaveText('1');
await expect(statusLine.locator('.status-failed')).toHaveText('0');
await expect(statusLine.locator('.status-skipped')).toHaveText('0');
await page.getByText('Attachments').click();
const downloadPromise = page.waitForEvent('download');
await page.getByRole('link', { name: 'download' }).click();
Expand All @@ -89,7 +97,11 @@ test('should contain string attachment', async ({ runUITest }) => {
});
await page.getByText('attach test').click();
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)');
const statusLine = page.getByTestId('status-line');
await expect(statusLine.getByTestId('test-count')).toHaveText('1/1');
await expect(statusLine.locator('.status-passed')).toHaveText('1');
await expect(statusLine.locator('.status-failed')).toHaveText('0');
await expect(statusLine.locator('.status-skipped')).toHaveText('0');
await page.getByText('Attachments').click();
await page.getByText('attach "note"', { exact: true }).click();
const downloadPromise = page.waitForEvent('download');
Expand All @@ -116,7 +128,11 @@ test('should linkify string attachments', async ({ runUITest, server }) => {
});
await page.getByText('attach test').click();
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)');
const statusLine = page.getByTestId('status-line');
await expect(statusLine.getByTestId('test-count')).toHaveText('1/1');
await expect(statusLine.locator('.status-passed')).toHaveText('1');
await expect(statusLine.locator('.status-failed')).toHaveText('0');
await expect(statusLine.locator('.status-skipped')).toHaveText('0');
await page.getByText('Attachments').click();

const attachmentsPane = page.locator('.attachments-tab');
Expand Down Expand Up @@ -162,7 +178,11 @@ test('should link from attachment step to attachments view', async ({ runUITest

await page.getByText('attach test').click();
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)');
const statusLine = page.getByTestId('status-line');
await expect(statusLine.getByTestId('test-count')).toHaveText('1/1');
await expect(statusLine.locator('.status-passed')).toHaveText('1');
await expect(statusLine.locator('.status-failed')).toHaveText('0');
await expect(statusLine.locator('.status-skipped')).toHaveText('0');
await page.getByRole('tab', { name: 'Attachments' }).click();

const panel = page.getByRole('tabpanel', { name: 'Attachments' });
Expand Down
6 changes: 5 additions & 1 deletion tests/playwright-test/ui-mode-test-output.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,11 @@ test('should print beforeAll console messages once', async ({ runUITest }, testI
await page.getByTitle('Run all').click();
await page.getByText('Console').click();
await page.getByText('print').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)');
const statusLine = page.getByTestId('status-line');
await expect(statusLine.getByTestId('test-count')).toHaveText('1/1');
await expect(statusLine.locator('.status-passed')).toHaveText('1');
await expect(statusLine.locator('.status-failed')).toHaveText('0');
await expect(statusLine.locator('.status-skipped')).toHaveText('0');
await expect(page.locator('.console-tab .console-line-message')).toHaveText([
'before all log',
'test log',
Expand Down
Loading
Loading