test: add component tests for html report (#10900)
This commit is contained in:
parent
67b16497cc
commit
e55f96d466
18
.github/workflows/tests_primary.yml
vendored
18
.github/workflows/tests_primary.yml
vendored
|
|
@ -76,3 +76,21 @@ jobs:
|
||||||
- run: xvfb-run npm run ttest
|
- run: xvfb-run npm run ttest
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
|
||||||
|
test_html_report:
|
||||||
|
name: HTML Report
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 12
|
||||||
|
- run: npm i -g npm@8
|
||||||
|
- run: npm ci
|
||||||
|
env:
|
||||||
|
DEBUG: pw:install
|
||||||
|
- run: npm run build
|
||||||
|
- run: npx playwright install --with-deps
|
||||||
|
- run: npm run htest
|
||||||
|
if: matrix.os != 'ubuntu-latest'
|
||||||
|
- run: xvfb-run npm run htest
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
"wtest": "playwright test --config=tests/config/default.config.ts --project=webkit",
|
"wtest": "playwright test --config=tests/config/default.config.ts --project=webkit",
|
||||||
"atest": "playwright test --config=tests/config/android.config.ts",
|
"atest": "playwright test --config=tests/config/android.config.ts",
|
||||||
"etest": "playwright test --config=tests/config/electron.config.ts",
|
"etest": "playwright test --config=tests/config/electron.config.ts",
|
||||||
|
"htest": "playwright test --config=packages/html-reporter",
|
||||||
"ttest": "node ./tests/playwright-test/stable-test-runner/node_modules/@playwright/test/cli test --config=tests/playwright-test/playwright-test.config.ts",
|
"ttest": "node ./tests/playwright-test/stable-test-runner/node_modules/@playwright/test/cli test --config=tests/playwright-test/playwright-test.config.ts",
|
||||||
"vtest": "cross-env PLAYWRIGHT_DOCKER=1 node ./tests/playwright-test/stable-test-runner/node_modules/@playwright/test/cli test --config=tests/playwright-test/playwright-test.config.ts",
|
"vtest": "cross-env PLAYWRIGHT_DOCKER=1 node ./tests/playwright-test/stable-test-runner/node_modules/@playwright/test/cli test --config=tests/playwright-test/playwright-test.config.ts",
|
||||||
"test": "playwright test --config=tests/config/default.config.ts",
|
"test": "playwright test --config=tests/config/default.config.ts",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"name": "html-reporter",
|
"name": "html-reporter",
|
||||||
"private": true
|
"private": true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
35
packages/html-reporter/playwright.config.ts
Normal file
35
packages/html-reporter/playwright.config.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
/**
|
||||||
|
* 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 { PlaywrightTestConfig, devices } from '@playwright/test';
|
||||||
|
|
||||||
|
const config: PlaywrightTestConfig = {
|
||||||
|
testDir: 'src',
|
||||||
|
snapshotDir: 'snapshots',
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
use: {
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
},
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: { ...devices['Desktop Chrome'] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
19
packages/html-reporter/playwright.stories.tsx
Normal file
19
packages/html-reporter/playwright.stories.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* 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 './src/theme.css';
|
||||||
|
import './src/chip.story.tsx';
|
||||||
|
import './src/headerView.story.tsx';
|
||||||
48
packages/html-reporter/src/chip.spec.ts
Normal file
48
packages/html-reporter/src/chip.spec.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 { test, expect } from '../test/componentTest';
|
||||||
|
|
||||||
|
test.use({ webpack: require.resolve('../webpack.config.js') });
|
||||||
|
|
||||||
|
test('chip expand collapse', async ({ renderComponent }) => {
|
||||||
|
const component = await renderComponent('ChipComponent');
|
||||||
|
await expect(component.locator('text=Chip body')).toBeVisible();
|
||||||
|
// expect(await component.screenshot()).toMatchSnapshot('expanded.png');
|
||||||
|
await component.locator('text=Title').click();
|
||||||
|
await expect(component.locator('text=Chip body')).not.toBeVisible();
|
||||||
|
// expect(await component.screenshot()).toMatchSnapshot('collapsed.png');
|
||||||
|
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 ({ renderComponent }) => {
|
||||||
|
const title = 'Extremely long title. '.repeat(10);
|
||||||
|
const component = await renderComponent('ChipComponent', { title });
|
||||||
|
await expect(component).toContainText('Extremely long title.');
|
||||||
|
await expect(component.locator('text=Extremely long title.')).toHaveAttribute('title', title);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('chip setExpanded is called', async ({ renderComponent }) => {
|
||||||
|
const expandedValues: boolean[] = [];
|
||||||
|
const component = await renderComponent('ChipComponentWithFunctions', {
|
||||||
|
setExpanded: (expanded: boolean) => expandedValues.push(expanded)
|
||||||
|
});
|
||||||
|
|
||||||
|
await component.locator('text=Title').click();
|
||||||
|
expect(expandedValues).toEqual([true]);
|
||||||
|
});
|
||||||
42
packages/html-reporter/src/chip.story.tsx
Normal file
42
packages/html-reporter/src/chip.story.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
* 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 React from 'react';
|
||||||
|
import { Chip } from './chip';
|
||||||
|
import { registerComponent } from '../test/component';
|
||||||
|
|
||||||
|
const ChipComponent: React.FC<{
|
||||||
|
title?: string
|
||||||
|
}> = ({ title }) => {
|
||||||
|
const [expanded, setExpanded] = React.useState(true);
|
||||||
|
return <Chip header={title || 'Title'} expanded={expanded} setExpanded={setExpanded}>
|
||||||
|
Chip body
|
||||||
|
</Chip>;
|
||||||
|
};
|
||||||
|
registerComponent('ChipComponent', ChipComponent, {
|
||||||
|
viewport: { width: 500, height: 500 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const ChipComponentWithFunctions: React.FC<{
|
||||||
|
setExpanded: (expanded: boolean) => void,
|
||||||
|
}> = ({ setExpanded }) => {
|
||||||
|
return <Chip header='Title' expanded={false} setExpanded={setExpanded}>
|
||||||
|
Chip body
|
||||||
|
</Chip>;
|
||||||
|
};
|
||||||
|
registerComponent('ChipComponentWithFunctions', ChipComponentWithFunctions, {
|
||||||
|
viewport: { width: 500, height: 500 },
|
||||||
|
});
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import './chip.css';
|
import './chip.css';
|
||||||
|
import './colors.css';
|
||||||
|
import './common.css';
|
||||||
import * as icons from './icons';
|
import * as icons from './icons';
|
||||||
|
|
||||||
export const Chip: React.FunctionComponent<{
|
export const Chip: React.FunctionComponent<{
|
||||||
|
|
@ -26,7 +28,10 @@ export const Chip: React.FunctionComponent<{
|
||||||
children?: any,
|
children?: any,
|
||||||
}> = ({ header, expanded, setExpanded, children, noInsets }) => {
|
}> = ({ header, expanded, setExpanded, children, noInsets }) => {
|
||||||
return <div className='chip'>
|
return <div className='chip'>
|
||||||
<div className={'chip-header' + (setExpanded ? ' expanded-' + expanded : '')} onClick={() => setExpanded?.(!expanded)}>
|
<div
|
||||||
|
className={'chip-header' + (setExpanded ? ' expanded-' + expanded : '')}
|
||||||
|
onClick={() => setExpanded?.(!expanded)}
|
||||||
|
title={typeof header === 'string' ? header : undefined}>
|
||||||
{setExpanded && !!expanded && icons.downArrow()}
|
{setExpanded && !!expanded && icons.downArrow()}
|
||||||
{setExpanded && !expanded && icons.rightArrow()}
|
{setExpanded && !expanded && icons.rightArrow()}
|
||||||
{header}
|
{header}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,16 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--box-shadow: rgba(0, 0, 0, 0.133) 0px 1.6px 3.6px 0px, rgba(0, 0, 0, 0.11) 0px 0.3px 0.9px 0px;
|
||||||
|
--monospace-font: "SF Mono", Monaco, Consolas, "Droid Sans Mono", Inconsolata, "Courier New",monospace;
|
||||||
|
--box-shadow-thick: rgb(0 0 0 / 10%) 0px 1.8px 1.9px,
|
||||||
|
rgb(0 0 0 / 15%) 0px 6.1px 6.3px,
|
||||||
|
rgb(0 0 0 / 10%) 0px -2px 4px,
|
||||||
|
rgb(0 0 0 / 15%) 0px -6.1px 12px,
|
||||||
|
rgb(0 0 0 / 25%) 0px 6px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
|
||||||
32
packages/html-reporter/src/headerView.css
Normal file
32
packages/html-reporter/src/headerView.css
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.header-view-status-container {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
.header-view-status-container {
|
||||||
|
float: none;
|
||||||
|
margin: 0 0 10px 0 !important;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-view-status-container .subnav-search-input {
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
65
packages/html-reporter/src/headerView.spec.ts
Normal file
65
packages/html-reporter/src/headerView.spec.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 type { Stats } from '@playwright/test/src/reporters/html';
|
||||||
|
import { test, expect } from '../test/componentTest';
|
||||||
|
|
||||||
|
test.use({ webpack: require.resolve('../webpack.config.js') });
|
||||||
|
|
||||||
|
test('should render counters', async ({ renderComponent }) => {
|
||||||
|
const stats: Stats = {
|
||||||
|
total: 100,
|
||||||
|
expected: 42,
|
||||||
|
unexpected: 31,
|
||||||
|
flaky: 17,
|
||||||
|
skipped: 10,
|
||||||
|
ok: false,
|
||||||
|
duration: 100000
|
||||||
|
};
|
||||||
|
const component = await renderComponent('HeaderView', { stats });
|
||||||
|
await expect(component.locator('a').withText('All').locator('.counter')).toHaveText('100');
|
||||||
|
await expect(component.locator('a').withText('Passed').locator('.counter')).toHaveText('42');
|
||||||
|
await expect(component.locator('a').withText('Failed').locator('.counter')).toHaveText('31');
|
||||||
|
await expect(component.locator('a').withText('Flaky').locator('.counter')).toHaveText('17');
|
||||||
|
await expect(component.locator('a').withText('Skipped').locator('.counter')).toHaveText('10');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should toggle filters', async ({ page, renderComponent }) => {
|
||||||
|
const stats: Stats = {
|
||||||
|
total: 100,
|
||||||
|
expected: 42,
|
||||||
|
unexpected: 31,
|
||||||
|
flaky: 17,
|
||||||
|
skipped: 10,
|
||||||
|
ok: false,
|
||||||
|
duration: 100000
|
||||||
|
};
|
||||||
|
const filters: string[] = [];
|
||||||
|
const component = await renderComponent('HeaderView', {
|
||||||
|
stats,
|
||||||
|
setFilterText: (filterText: string) => filters.push(filterText)
|
||||||
|
});
|
||||||
|
await component.locator('a').withText('All').click();
|
||||||
|
await component.locator('a').withText('Passed').click();
|
||||||
|
await expect(page).toHaveURL(/#\?q=s:passed/);
|
||||||
|
await component.locator('a').withText('Failed').click();
|
||||||
|
await expect(page).toHaveURL(/#\?q=s:failed/);
|
||||||
|
await component.locator('a').withText('Flaky').click();
|
||||||
|
await expect(page).toHaveURL(/#\?q=s:flaky/);
|
||||||
|
await component.locator('a').withText('Skipped').click();
|
||||||
|
await expect(page).toHaveURL(/#\?q=s:skipped/);
|
||||||
|
expect(filters).toEqual(['', 's:passed', 's:failed', 's:flaky', 's:skipped']);
|
||||||
|
});
|
||||||
22
packages/html-reporter/src/headerView.story.tsx
Normal file
22
packages/html-reporter/src/headerView.story.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
/**
|
||||||
|
* 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 { registerComponent } from '../test/component';
|
||||||
|
import { HeaderView } from './headerView';
|
||||||
|
|
||||||
|
registerComponent('HeaderView', HeaderView, {
|
||||||
|
viewport: { width: 720, height: 500 },
|
||||||
|
});
|
||||||
|
|
@ -16,7 +16,9 @@
|
||||||
|
|
||||||
import type { Stats } from '@playwright/test/src/reporters/html';
|
import type { Stats } from '@playwright/test/src/reporters/html';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import './colors.css';
|
||||||
import './common.css';
|
import './common.css';
|
||||||
|
import './headerView.css';
|
||||||
import * as icons from './icons';
|
import * as icons from './icons';
|
||||||
import { Link, navigate } from './links';
|
import { Link, navigate } from './links';
|
||||||
import { statusIcon } from './statusIcon';
|
import { statusIcon } from './statusIcon';
|
||||||
|
|
@ -36,7 +38,7 @@ export const HeaderView: React.FC<{
|
||||||
});
|
});
|
||||||
|
|
||||||
return <div className='pt-3'>
|
return <div className='pt-3'>
|
||||||
<div className='status-container ml-2 pl-2 d-flex'>
|
<div className='header-view-status-container ml-2 pl-2 d-flex'>
|
||||||
<StatsNavView stats={stats}></StatsNavView>
|
<StatsNavView stats={stats}></StatsNavView>
|
||||||
</div>
|
</div>
|
||||||
<form className='subnav-search' onSubmit={
|
<form className='subnav-search' onSubmit={
|
||||||
|
|
|
||||||
|
|
@ -14,25 +14,6 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
:root {
|
|
||||||
--box-shadow: rgba(0, 0, 0, 0.133) 0px 1.6px 3.6px 0px, rgba(0, 0, 0, 0.11) 0px 0.3px 0.9px 0px;
|
|
||||||
--monospace-font: "SF Mono", Monaco, Consolas, "Droid Sans Mono", Inconsolata, "Courier New",monospace;
|
|
||||||
--box-shadow-thick: rgb(0 0 0 / 10%) 0px 1.8px 1.9px,
|
|
||||||
rgb(0 0 0 / 15%) 0px 6.1px 6.3px,
|
|
||||||
rgb(0 0 0 / 10%) 0px -2px 4px,
|
|
||||||
rgb(0 0 0 / 15%) 0px -6.1px 12px,
|
|
||||||
rgb(0 0 0 / 25%) 0px 6px 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#root {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
color: var(--color-fg-default);
|
|
||||||
font-size: 14px;
|
|
||||||
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
}
|
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
@ -52,23 +33,8 @@ body {
|
||||||
border-top: 1px solid var(--color-border-default);
|
border-top: 1px solid var(--color-border-default);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-container {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
.report {
|
.report {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-container {
|
|
||||||
float: none;
|
|
||||||
margin: 0 0 10px 0 !important;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subnav-search-input {
|
|
||||||
border-left: none;
|
|
||||||
border-right: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import { LoadedReport } from './loadedReport';
|
||||||
import './reportView.css';
|
import './reportView.css';
|
||||||
import { TestCaseView } from './testCaseView';
|
import { TestCaseView } from './testCaseView';
|
||||||
import { TestFilesView } from './testFilesView';
|
import { TestFilesView } from './testFilesView';
|
||||||
|
import './theme.css';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
|
||||||
22
packages/html-reporter/src/theme.css
Normal file
22
packages/html-reporter/src/theme.css
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#root {
|
||||||
|
color: var(--color-fg-default);
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
77
packages/html-reporter/test/component.js
Normal file
77
packages/html-reporter/test/component.js
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const React = require('react');
|
||||||
|
const ReactDOM = require('react-dom');
|
||||||
|
|
||||||
|
const fillStyle = {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkerboardCommon = {
|
||||||
|
...fillStyle,
|
||||||
|
backgroundSize: '50px 50px',
|
||||||
|
backgroundPosition: '0 0, 25px 25px',
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkerboardLight = {
|
||||||
|
...checkerboardCommon,
|
||||||
|
backgroundColor: '#FFF',
|
||||||
|
backgroundImage: `linear-gradient(45deg, #00000008 25%, transparent 25%, transparent 75%, #00000008 75%, #00000008),
|
||||||
|
linear-gradient(45deg, #00000008 25%, transparent 25%, transparent 75%, #00000008 75%, #00000008)`
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkerboardDark = {
|
||||||
|
...checkerboardCommon,
|
||||||
|
backgroundColor: '#000',
|
||||||
|
backgroundImage: `linear-gradient(45deg, #FFFFFF12 25%, transparent 25%, transparent 75%, #FFFFFF12 75%, #FFFFFF12),
|
||||||
|
linear-gradient(45deg, #FFFFFF12 25%, transparent 25%, transparent 75%, #FFFFFF12 75%, #FFFFFF12)`
|
||||||
|
};
|
||||||
|
|
||||||
|
const Component = ({ style, children }) => {
|
||||||
|
const checkerboard = window.matchMedia('(prefers-color-scheme: dark)').matches ? checkerboardDark : checkerboardLight;
|
||||||
|
const bgStyle = { ...checkerboard };
|
||||||
|
const fgStyle = { ...fillStyle, ...style };
|
||||||
|
return React.createElement(
|
||||||
|
React.Fragment, null,
|
||||||
|
React.createElement('div', { style: bgStyle }),
|
||||||
|
React.createElement('div', { style: fgStyle, id: 'pw-root' }, children));
|
||||||
|
};
|
||||||
|
|
||||||
|
const registry = new Map();
|
||||||
|
|
||||||
|
export const registerComponent = (name, component, options) => {
|
||||||
|
registry.set(name, { component, options });
|
||||||
|
};
|
||||||
|
|
||||||
|
function render(name, params) {
|
||||||
|
const entry = registry.get(name);
|
||||||
|
ReactDOM.render(
|
||||||
|
React.createElement(Component, null, React.createElement(entry.component, params || null)),
|
||||||
|
document.getElementById('root'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function options(name) {
|
||||||
|
const entry = registry.get(name);
|
||||||
|
return entry.options;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.__playwright_render = render;
|
||||||
|
window.__playwright_options = options;
|
||||||
78
packages/html-reporter/test/componentTest.ts
Normal file
78
packages/html-reporter/test/componentTest.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
/**
|
||||||
|
* 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 * as path from 'path';
|
||||||
|
import { test as baseTest, Locator } from '@playwright/test';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
__playwright_render: (component: string, props: any) => void;
|
||||||
|
__playwright_options: (component: string) => { viewport: { width: number, height: number } };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestFixtures = {
|
||||||
|
renderComponent: (component: string, params?: any) => Promise<Locator>;
|
||||||
|
webpack: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const test = baseTest.extend<TestFixtures>({
|
||||||
|
webpack: '',
|
||||||
|
renderComponent: async ({ page, webpack }, use, testInfo) => {
|
||||||
|
const webpackConfig = require(webpack);
|
||||||
|
const outputPath = webpackConfig.output.path;
|
||||||
|
const filename = webpackConfig.output.filename.replace('[name]', 'playwright');
|
||||||
|
await use(async (component: string, optionalParams?: Object) => {
|
||||||
|
await page.route('http://component/index.html', route => {
|
||||||
|
route.fulfill({
|
||||||
|
body: `<html>
|
||||||
|
<meta name='color-scheme' content='dark light'>
|
||||||
|
<style>html, body { padding: 0; margin: 0; background: #aaa; }</style>
|
||||||
|
<div id='root' style='width: 100%; height: 100%;'></div>
|
||||||
|
</html>`,
|
||||||
|
contentType: 'text/html'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
await page.goto('http://component/index.html');
|
||||||
|
|
||||||
|
await page.addScriptTag({ path: path.resolve(__dirname, outputPath, filename) });
|
||||||
|
const options = await page.evaluate((component: string) => {
|
||||||
|
return window.__playwright_options(component);
|
||||||
|
}, component);
|
||||||
|
await page.setViewportSize(options.viewport);
|
||||||
|
|
||||||
|
const params = { ...optionalParams };
|
||||||
|
for (const [key, value] of Object.entries(params)) {
|
||||||
|
if (typeof value === 'function') {
|
||||||
|
const functionName = '__pw_func_' + key;
|
||||||
|
await page.exposeFunction(functionName, value);
|
||||||
|
(params as any)[key] = functionName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await page.evaluate(v => {
|
||||||
|
const params = v.params;
|
||||||
|
for (const [key, value] of Object.entries(params)) {
|
||||||
|
if (typeof value === 'string' && (value as string).startsWith('__pw_func_'))
|
||||||
|
(params as any)[key] = window[value];
|
||||||
|
}
|
||||||
|
window.__playwright_render(v.component, params);
|
||||||
|
}, { component, params });
|
||||||
|
return page.locator('#pw-root');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export { expect } from '@playwright/test';
|
||||||
|
|
@ -25,6 +25,7 @@ module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
zip: require.resolve('@zip.js/zip.js/dist/zip-no-worker-inflate.min.js'),
|
zip: require.resolve('@zip.js/zip.js/dist/zip-no-worker-inflate.min.js'),
|
||||||
app: path.join(__dirname, 'src', 'index.tsx'),
|
app: path.join(__dirname, 'src', 'index.tsx'),
|
||||||
|
playwright: path.join(__dirname, 'playwright.stories.tsx'),
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.ts', '.js', '.tsx', '.jsx']
|
extensions: ['.ts', '.js', '.tsx', '.jsx']
|
||||||
|
|
@ -59,6 +60,7 @@ module.exports = {
|
||||||
title: 'Playwright Test Report',
|
title: 'Playwright Test Report',
|
||||||
template: path.join(__dirname, 'src', 'index.html'),
|
template: path.join(__dirname, 'src', 'index.html'),
|
||||||
inject: true,
|
inject: true,
|
||||||
|
excludeChunks: ['playwright'],
|
||||||
}),
|
}),
|
||||||
new BundleJsPlugin(),
|
new BundleJsPlugin(),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue