Skip to content

Commit 73ed7da

Browse files
bmeurerDevtools-frontend LUCI CQ
authored and
Devtools-frontend LUCI CQ
committed
Improve documentation for testing DevTools.
Restructure the current testing documentation with a single entry point in `test/README.md` and put the E2E and unit test documentation into a single spot (as much as possible). There's still room for improvement, but this should give us a better starting point. Fixed: 343896438 Change-Id: I2a7881aa2ca7d32c8d20b356ddb7a776c00a5047 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5776289 Reviewed-by: Danil Somsikov <dsv@chromium.org> Auto-Submit: Benedikt Meurer <bmeurer@chromium.org> Commit-Queue: Danil Somsikov <dsv@chromium.org>
1 parent 050f576 commit 73ed7da

11 files changed

+321
-125
lines changed

docs/README.md

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ below.**
2323

2424
* [Get the Code](get_the_code.md)
2525
* [UX Style Guide](./styleguide/ux/README.md)
26+
* [Testing Guide](../test/README.md)
2627
* [Contributing Changes](contributing_changes.md)
2728
* [Chrome DevTools Design Review Guidelines](design_guidelines.md)
2829
* [Release Management](release_management.md)
@@ -35,12 +36,6 @@ below.**
3536
* [How to add UMA metrics in DevTools frontend](add_uma_metrics.md)
3637
* [How to add experiments in DevTools frontend](add_experiments.md)
3738

38-
### Testing
39-
40-
* [Testing Chromium DevTools](testing.md)
41-
* [E2E test guide](../test/e2e/README.md)
42-
* [Unit test guide](unit_testing.md)
43-
4439
### Architectural Documentation
4540

4641
* [Architecture of DevTools](architecture_of_devtools.md)
Loading
Loading
Loading

front_end/testing/README.md

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,89 @@
1+
# Chromium DevTools Unit Testing Helpers
2+
13
This folder contains helpers for writing Karma unit tests, most of which exist to help render and test components.
24

3-
See the [unit testing documentation](../../docs/unit_testing.md) for more information.
5+
See the [unit testing documentation](../../test/unit/README.md) for more information.
6+
7+
[TOC]
8+
9+
## DOM Helpers
10+
11+
### Rendering a component in a test
12+
13+
When running a Karma unit test, the DOM that you create during a test is automatically cleaned up for you before the next test, ensuring that no tests are impacted by stray DOM left behind from a previous test.
14+
15+
To ensure you render your component into the test DOM, use the `renderElementIntoDOM` helper, which takes any `HTMLElement` and renders it. By using this helper you ensure that it's cleaned up at the end of the test.
16+
17+
### Asserting presence of variables for TypeScript
18+
19+
When trying to read a component's shadow DOM, TypeScript will ask that you check it's not null first:
20+
21+
```
22+
component.shadowRoot.querySelector('.foo') // TS will error here: shadowRoot may be `null`.
23+
```
24+
25+
The `assert.isNotNull` method will do this for you and fail the test if the shadow root is not present:
26+
27+
```
28+
assert.isNotNull(component.shadowRoot);
29+
component.shadowRoot.querySelector('.foo') // TS is happy!
30+
```
31+
32+
When you query elements from the DOM, you can use `assert.instanceOf` or `assertElements` to check that an element is the expected type. This will ensure the test fails if the DOM is not as expected, and satisfy TypeScript:
33+
34+
```
35+
const button = component.shadowRoot.querySelector('button.foo');
36+
assert.instanceOf(button, HTMLButtonElement);
37+
38+
const allDivs = component.shadowRoot.querySelectorAll('div');
39+
assertElements(allDivs, HTMLDivElement);
40+
```
41+
42+
## Mutation helpers
43+
44+
When building components we want to ensure that they are efficient and do not update the DOM more than necessary. We can use the mutation helpers to assert on the amount of DOM changes in a given test. These use a [Mutation Observer](https://developer.mozilla.org/en/docs/Web/API/MutationObserver) to track any mutations.
45+
46+
_Important!_: These tests are async, so you must `await` them.
47+
48+
### Expecting mutations
49+
50+
If you are expecting mutations, you can wrap the part of the test that triggers the mutation in a `withMutation` call. The first argument is an array of mutations you expect (read on for the structure of it), the second is the element to observe (will nearly always be `component.shadowRoot`, and a callback function that takes the observed shadow root. It is this function that will be executed whilst the DOM is being observed for mutations.
51+
52+
```
53+
it('adds a new button when the data changes', async () => {
54+
const component = new MyComponent();
55+
component.data = {...}
56+
renderElementIntoDOM(component);
57+
58+
await withMutations([{
59+
type: MutationType.ADD, // MutationType is an exported enum from MutationHelpers
60+
tagName: 'button',
61+
max: 2, // the maximum number of mutations to allow; defaults to 10
62+
}], component.shadowRoot, shadowRoot => {
63+
// do something that updates the component and causes mutations
64+
component.data = {...}
65+
})
66+
})
67+
```
68+
69+
This test will assert that updating the component causes _at most 2 additions_ to the component's shadow DOM. You can pass `MutationType.ADD` or `MutationType.REMOVE` as the `type` to watch for just additions/removals, or you can omit the `type` key and have the test watch for both additions and removals.
70+
71+
You don't need to wrap every test in a `withMutation` block, but if you are testing some code that should update the DOM, it's a good idea to ensure we aren't unexpectedly doing much more work than expected.
72+
73+
### Expecting no mutations
74+
75+
If you have a test where no DOM should mutate, you can use `withNoMutations`. This is the opposite of `withMutations`; it will fail the test should it detect any DOM mutations. Using this helper when testing the `ElementBreadcrumbs` component discovered that when we scrolled the breadcrumbs we caused _over 70 DOM mutations_ (!), which is what lead to the creation of this helper. It's a great way to verify that we're not doing work that can be avoided.
76+
77+
```
78+
it('does not mutate the DOM when we scroll the component', async () => {
79+
const component = new MyComponent();
80+
component.data = {...}
81+
renderElementIntoDOM(component);
82+
83+
await withNoMutations(component.shadowRoot, shadowRoot => {
84+
// Imagine there's code here to cause the component to scroll
85+
})
86+
})
87+
```
88+
89+
The above test will fail if any DOM mutations are detected.

docs/testing.md renamed to test/README.md

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,38 @@
1-
# Testing Chromium DevTools
1+
# Unit Testing
22

3-
Follow the steps outlined in [Get the Code](get_the_code.md) to checkout the DevTools front-end code.
3+
[goo.gle/devtools-testing-guide](http://goo.gle/devtools-testing-guide)
4+
5+
Follow the steps outlined in [Get the Code](../docs/get_the_code.md) to checkout the DevTools front-end code.
46

57
[TOC]
68

7-
## DevTools frontend
9+
## DevTools front-end tests
10+
11+
The `devtools-frontend` repository contains a variety of test suites, check
12+
out the individual guides below:
813

9-
Run tests with
14+
* [Unit Testing Guide](./unit/README.md)
15+
* [Interactions Testing Guide](./interactions/README.md)
16+
* [E2E Testing Guide](./e2e/README.md)
17+
* [Performance Testing Guide](./perf/README.md)
18+
19+
You can use
1020

1121
```
1222
npm test
1323
```
1424

15-
This command runs all tests in the devtools frontend repo, which are the [unit tests](../test/unit/README.md),
16-
[interactions tests](../test/interactions/README.md), [e2e tests](../test/e2e/README.md), and performance tests.
17-
18-
You can also run just a subset of tests like this:
25+
to run all tests in the devtools frontend repo. You can also run just a
26+
subset of tests like this:
1927

2028
```
2129
npm test \
2230
front_end/core/common/Color.test.ts \
2331
front_end/core/sdk
2432
```
2533

26-
27-
The current test status can be seen at the [test waterfall](https://ci.chromium.org/p/devtools-frontend/g/main/console).
28-
29-
30-
### Debugging
31-
32-
#### Debugging with VSCode
33-
34-
To run tests under the debugger, open the "Run and Debug" sidebar, select "Run unit tests in VS Code debugger" from the
35-
dropdown, and click the start button or press F5.
36-
37-
Current limitations when using VSCode for e2e and interactions tests:
38-
39-
- VSCode only attaches to the node portion of the code (mostly the test files and the test helpers), not to Chrome.
40-
- VSCode debugging only works with headless mode.
41-
42-
#### Debugging with DevTools
43-
44-
To run tests under the DevTools debugger use the `--debug` command line option.
45-
46-
For unittests this will bring up Chrome with a Karma launcher page. Wait for "Debug" button to appear and click it. A
47-
new page will open, here you can open DevTools, set breakpoints in the tests and reload page to rerun tests.
48-
49-
For e2e tests, you can debug the "DevTools under test" with DevTools-on-DevTools. Use the standard DevTools key
50-
combination to open another DevTools instance while you look at the "DevTools under test". You can set breakpoints and
51-
inspect the status of the "DevTools under test" this way. You can debug the puppeteer side by inspecting the Node.js
52-
process that runs the e2e suite. Either open `chrome://inspect` or click the Node.js icon in any open DevTools window to
53-
connect to the puppeteer process. You can step through the puppeteer test code this way.
34+
The current test status can be seen at the
35+
[test waterfall](https://ci.chromium.org/p/devtools-frontend/g/main/console).
5436

5537
### Obtaining code coverage
5638

test/e2e/README.md

Lines changed: 120 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Guide on end-to-end testing
1+
# E2E Testing
22

33
This directory hosts the end-to-end tests we run on DevTools. These tests open a target page and a DevTools frontend page, for which the DevTools frontend connects to the target page over CDP. We use [Puppeteer] to talk over CDP and all functionality of Puppeteer is available to you as well when writing end-to-end tests. We use [Mocha] as testing framework.
44

@@ -9,18 +9,132 @@ The tests therefore have a dual purpose:
99
1. Verify that core user stories are working as intended and are not broken by a particular DevTools frontend change.
1010
1. Serve as documentation and reference point for how DevTools is intended to be used.
1111

12-
## Skipping tests
12+
[TOC]
1313

14-
You can disable a test for all platforms using `it.skip`. If you are disabling a flaky test, consider disabling it only on the affected platforms. For example,
14+
## Running E2E tests
15+
16+
The end-to-end tests are implicitly run as part of `npm run test`,
17+
but that also runs all the other test suites. To run only
18+
**all end-to-end tests**, use:
19+
20+
```
21+
npm run test test/e2e
22+
```
23+
24+
To use `out/Debug` instead of the default `out/Default` target
25+
directory, use:
26+
27+
```
28+
npm run test -- -t Debug test/e2e
29+
```
30+
31+
To run the end-to-end tests in **debug mode**, use:
32+
33+
```
34+
npm run test -- --debug test/e2e
35+
```
36+
37+
To run only **specific end-to-end tests** from a single `_test.ts`
38+
file, say `console-log_test.ts` for example, use:
39+
40+
```
41+
npm run test test/e2e/console/console-log_test.ts
42+
```
43+
44+
Check the output of `npm run test -- --help` for an overview of
45+
all options.
46+
47+
## Debugging E2E tests
48+
49+
You can debug the "DevTools under test" with DevTools-on-DevTools. Use the
50+
standard DevTools key combination to open another DevTools instance while
51+
you look at the "DevTools under test". You can set breakpoints and inspect
52+
the status of the "DevTools under test" this way. You can debug the puppeteer
53+
side by inspecting the Node.js process that runs the e2e suite. Either open
54+
`chrome://inspect` or click the Node.js icon in any open DevTools window to
55+
connect to the puppeteer process. You can step through the puppeteer test
56+
code this way.
57+
58+
### Debugging E2E tests with VSCode
59+
60+
There's experimental support for running unit tests directly from
61+
within VSCode. Open the "Run and Debug" sidebar, select "Run end-to-end tests
62+
in VS Code debugger" from the dropdown, and click the start button or
63+
press F5.
64+
65+
![Debugging E2E tests with VSCode](../../docs/images/debugging-e2e-tests-with-vscode.png "Debugging E2E tests with VSCode")
66+
67+
Current limitations when using VSCode for e2e and interactions tests:
68+
69+
- VSCode only attaches to the node portion of the code (mostly the test files
70+
and the test helpers), not to Chrome.
71+
- VSCode debugging only works with headless mode.
72+
73+
## Dealing with flaky E2E tests
74+
75+
To skip a flaky E2E test, create a new bug on [crbug.com](https://crbug.com) in the
76+
`Chromium > Platform > DevTools` component, and modify the `it` or `describe`
77+
block accordingly by adding `.skip` to it, adding a preceeding comment
78+
why the test is skipp and adding the `crbug.com` reference to the test
79+
block string. For example
80+
81+
```js
82+
describe('Foo', () => {
83+
it('can return bar', () => {
84+
assert.strictEqual((new Foo()).bar(), 'bar');
85+
});
86+
87+
...
88+
});
89+
```
90+
91+
would be changed to look like this
92+
93+
```js
94+
describe('Foo', () => {
95+
// Flaking on multiple bots on CQ after recent CL xyz.
96+
it.skip('[crbug.com/12345678] can return bar', () => {
97+
assert.strictEqual((new Foo()).bar(), 'bar');
98+
});
99+
100+
...
101+
});
102+
```
103+
104+
if only the one test case should be skipped, or like this
105+
106+
```js
107+
// Flaking on multiple bots on CQ after recent CL xyz.
108+
describe.skip('[crbug.com/12345678] Foo', () => {
109+
it('can return bar', () => {
110+
assert.strictEqual((new Foo()).bar(), 'bar');
111+
});
112+
113+
...
114+
});
115+
```
116+
117+
if all the tests for `Foo` should be skipped. If you are disabling a flaky test,
118+
consider disabling it only on the affected platforms. For example:
15119

16120
```js
121+
import {it} from './relative/path/to/shared/mocha-extensions.js';
122+
123+
...
124+
125+
// Consistently flakes on Mac and Windows bots.
17126
it.skipOnPlatforms(['mac', 'win32'], '[crbug.com/xxx] ...', () => {...});
18-
it.skipOnPlatforms(['linux'], '[crbug.com/xxx] ...', () => {...});
127+
128+
// Skipped on Linux because the world isn't round.
129+
describe.skipOnPlatforms(['linux'], '[crbug.com/xxx] ...', () => {...});
19130
```
20131

21-
To use `skipOnPlatforms`, you need to import `it` from `test/shared/mocha-extensions.ts`.
132+
*** note
133+
**Note:** To use `skipOnPlatforms`, you need to import `it` or `describe`
134+
from `test/shared/mocha-extensions.ts`.
135+
***
22136

23-
## Debugging flaky tests
137+
### De-flaking E2E tests
24138

25139
The `it.repeat` helper is useful for reproducing a flaky test failure. e.g.
26140

@@ -30,8 +144,6 @@ it.repeat(20, 'find element', async () => {...});
30144

31145
`it.repeat` behaves like `it.only` in that it will cause just that single test to be run.
32146

33-
## Debugging flaky tests
34-
35147
To see if certain tests are flaky you can use the E2E stressor bots. Open a CL with your test changes and run the following command specifying your test file:
36148

37149
```sh

test/interactions/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Interaction tests
1+
# Interaction Testing
22

33
Interaction tests are used to test individual pieces of DevTools in isolation - whether that be a single UI component, or an entire panel, or something inbetween. They load up the page in the browser and use Puppeteer to query it.
44

test/navbar.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Chromium DevTools Testing Guide
2+
3+
[logo]: https://github.com/ChromeDevTools/devtools-logo/raw/master/logos/png/devtools-circle-48.png
4+
[home]: /test/README.md
5+
6+
* [Home][home]
7+
* [Unit Testing](/test/unit/README.md)
8+
* [E2E Testing](/test/e2e/README.md)
9+
* [Interaction Testing](/test/interactions/README.md)
10+
* [Performance Testing](/test/perf/README.md)
11+
* [DevTools Documentation](/docs/README.md)

test/perf/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Performance Testing
2+
3+
TBD

0 commit comments

Comments
 (0)