blob: eda1b9ccaf6cb33c5098d260431e4ad05a06107d [file] [log] [blame] [view]
Peter Kastingcf49b7b792017-12-18 23:27:451# Testing Chrome browser UI with TestBrowserUi
taptedf38739a2017-02-09 04:34:522
Peter Kastingcf49b7b792017-12-18 23:27:453\#include "[chrome/browser/ui/test/test_browser_ui.h]"
taptedf38739a2017-02-09 04:34:524
Peter Kastingcf49b7b792017-12-18 23:27:455`TestBrowserUi` (and convenience class `TestBrowserDialog`) provide ways to
6register an `InProcessBrowserTest` testing harness with a framework that invokes
7Chrome browser UI in a consistent way. They optionally provide a way to invoke
8UI "interactively". This allows screenshots to be generated easily, with the
9same test data, to assist with UI review. `TestBrowserUi` also provides a UI
10registry so pieces of UI can be systematically checked for subtle changes and
11regressions.
taptedf38739a2017-02-09 04:34:5212
13[TOC]
14
Peter Kastingcf49b7b792017-12-18 23:27:4515## How to register UI
taptedf38739a2017-02-09 04:34:5216
Peter Kastingcf49b7b792017-12-18 23:27:4517If registering existing UI, there's a chance it already has a test harness
18inheriting, using, or with `typedef InProcessBrowserTest` (or a descendant of
19it). If so, using `TestBrowserDialog` (for a dialog) is straightforward, and
20`TestBrowserUi` (for other types of UI) relatively so. Assume the existing
21`InProcessBrowserTest` is in `foo_browsertest.cc`:
taptedf38739a2017-02-09 04:34:5222
Peter Kastingcf49b7b792017-12-18 23:27:4523 class FooUiTest : public InProcessBrowserTest { ...
taptedf38739a2017-02-09 04:34:5224
Peter Kastingcf49b7b792017-12-18 23:27:4525Change this to inherit from `DialogBrowserTest` (for dialogs) or `UiBrowserTest`
26(for non-dialogs), and override `ShowUi(std::string)`. For non-dialogs, also
27override `VerifyUi()` and `WaitForUserDismissal()`. See
28[Advanced Usage](#Advanced-Usage) for details.
taptedf38739a2017-02-09 04:34:5229
30```cpp
Peter Kastingcf49b7b792017-12-18 23:27:4531class FooUiTest : public UiBrowserTest {
taptedf38739a2017-02-09 04:34:5232 public:
33 ..
Peter Kastingcf49b7b792017-12-18 23:27:4534 // UiBrowserTest:
35 void ShowUi(const std::string& name) override {
36 /* Show Ui attached to browser() and leave it open. */
37 }
38 // These next two are not necessary if subclassing DialogBrowserTest.
39 bool VerifyUi() override {
40 /* Return true if the UI was successfully shown. */
41 }
42 void WaitForUserDismissal() override {
43 /* Block until the UI has been dismissed. */
taptedf38739a2017-02-09 04:34:5244 }
45 ..
46};
47```
48
Peter Kastingcf49b7b792017-12-18 23:27:4549Finally, add test invocations using the usual GTest macros, in
50`foo_browsertest.cc`:
taptedf38739a2017-02-09 04:34:5251
52```cpp
Peter Kastingcf49b7b792017-12-18 23:27:4553IN_PROC_BROWSER_TEST_F(FooUiTest, InvokeUi_default) {
54 ShowAndVerifyUi();
taptedf38739a2017-02-09 04:34:5255}
56```
57
58Notes:
59
Peter Kastingcf49b7b792017-12-18 23:27:4560* The body of the test is always just "`ShowAndVerifyUi();`".
61* "`default`" is the `std::string` passed to `ShowUi()` and can be
taptedf38739a2017-02-09 04:34:5262 customized. See
Peter Kastingcf49b7b792017-12-18 23:27:4563 [Testing additional UI "styles"](#Testing-additional-ui-styles).
64* The text before `default` (in this case) must always be "`InvokeUi_`".
taptedf38739a2017-02-09 04:34:5265
66### Concrete examples
67
68* [chrome/browser/ui/ask_google_for_suggestions_dialog_browsertest.cc]
Peter Kastingcf49b7b792017-12-18 23:27:4569* [chrome/browser/infobars/infobars_browsertest.cc]
taptedf38739a2017-02-09 04:34:5270
71## Running the tests
72
Peter Kastingcf49b7b792017-12-18 23:27:4573List the available pieces of UI with
taptedf38739a2017-02-09 04:34:5274
Peter Kastingcf49b7b792017-12-18 23:27:4575 $ ./browser_tests --gtest_filter=BrowserUiTest.Invoke
taptedf38739a2017-02-09 04:34:5276
Peter Kastingcf49b7b792017-12-18 23:27:4577E.g. `FooUiTest.InvokeUi_default` should be listed. To show the UI
taptedf38739a2017-02-09 04:34:5278interactively, run
79
Peter Boströme2732ef2018-02-21 21:53:2480 $ ./browser_tests --gtest_filter=BrowserUiTest.Invoke \
81 --test-launcher-interactive --ui=FooUiTest.InvokeUi_default
taptedf38739a2017-02-09 04:34:5282
83### Implementation
84
Peter Kastingcf49b7b792017-12-18 23:27:4585`BrowserUiTest.Invoke` searches for gtests that have "`InvokeUi_`" in their
86names, so they can be collected in a list. Providing a `--ui` argument will
Peter Boströme2732ef2018-02-21 21:53:2487invoke that test case in a subprocess. Including `--test-launcher-interactive`
88will set up an environment for that subprocess that allows interactivity, e.g.,
89to take screenshots. The test ends once the UI is dismissed.
taptedf38739a2017-02-09 04:34:5290
Peter Kastingcf49b7b792017-12-18 23:27:4591The `FooUiTest.InvokeUi_default` test case **will still be run in the usual
92browser_tests test suite**. Ensure it passes, and isn’t flaky. This will
93give your UI some regression test coverage. `ShowAndVerifyUi()` checks to ensure
94UI is actually created when it invokes `ShowUi("default")`.
taptedf38739a2017-02-09 04:34:5295
Peter Kastingcf49b7b792017-12-18 23:27:4596### BrowserUiTest.Invoke
taptedf38739a2017-02-09 04:34:5297
98This is also run in browser_tests but, when run that way, the test case just
99lists the registered test harnesses (it does *not* iterate over them). A
Peter Kastingcf49b7b792017-12-18 23:27:45100subprocess is never created unless --ui is passed on the command line.
taptedf38739a2017-02-09 04:34:52101
102## Advanced Usage
103
104If your test harness inherits from a descendant of `InProcessBrowserTest` (one
Peter Kastingcf49b7b792017-12-18 23:27:45105example: [ExtensionBrowserTest]) then the `SupportsTestUi<>` and
106`SupportsTestDialog` templates are provided. E.g.
taptedf38739a2017-02-09 04:34:52107
108```cpp
109class ExtensionInstallDialogViewTestBase : public ExtensionBrowserTest { ...
110```
111
112becomes
113
114```cpp
115class ExtensionInstallDialogViewTestBase :
116 public SupportsTestDialog<ExtensionBrowserTest> { ...
117```
118
Peter Kastingcf49b7b792017-12-18 23:27:45119If you need to do any setup before `ShowUi()` is called, or any teardown in the
120non-interactive case, you can override the `PreShow()` and `DismissUi()
121methods.
taptedf38739a2017-02-09 04:34:52122
Peter Kastingcf49b7b792017-12-18 23:27:45123### Testing additional UI "styles"
124
125Add additional test cases, with a different string after "`InvokeUi_`".
taptedf38739a2017-02-09 04:34:52126Example:
127
128```cpp
Peter Kastingcf49b7b792017-12-18 23:27:45129IN_PROC_BROWSER_TEST_F(CardUnmaskViewBrowserTest, InvokeUi_expired) {
130 ShowAndVerifyUi();
taptedf38739a2017-02-09 04:34:52131}
132
Peter Kastingcf49b7b792017-12-18 23:27:45133IN_PROC_BROWSER_TEST_F(CardUnmaskViewBrowserTest, InvokeUi_valid) {
134 ShowAndVerifyUi();
taptedf38739a2017-02-09 04:34:52135}
136```
137
138The strings "`expired`" or “`valid`” will be given as arguments to
Peter Kastingcf49b7b792017-12-18 23:27:45139`ShowUi(std::string)`.
taptedf38739a2017-02-09 04:34:52140
141## Rationale
142
143Bug reference: [Issue 654151](http://crbug.com/654151).
144
Peter Kastingcf49b7b792017-12-18 23:27:45145Chrome has a lot of browser UI; often for obscure use-cases and often hard to
146invoke. It has traditionally been difficult to be systematic while checking UI
147for possible regressions. For example, to investigate changes to shared layout
148parameters which are testable only with visual inspection.
taptedf38739a2017-02-09 04:34:52149
150For Chrome UI review, screenshots need to be taken. Iterating over all the
Peter Kastingcf49b7b792017-12-18 23:27:45151"styles" that UI may appear with is fiddly. E.g. a login or particular web
taptedf38739a2017-02-09 04:34:52152server setup may be required. It’s important to provide a consistent “look” for
153UI review (e.g. same test data, same browser size, anchoring position, etc.).
154
Peter Kastingcf49b7b792017-12-18 23:27:45155Some UI lacks tests. Some UI has zero coverage on the bots. UI elements can have
156tricky lifetimes and common mistakes are repeated. TestBrowserUi runs simple
157"Show UI" regression tests and can be extended to do more.
taptedf38739a2017-02-09 04:34:52158
Peter Kastingcf49b7b792017-12-18 23:27:45159Even discovering the full set of UI present for each platform in Chrome is
taptedf38739a2017-02-09 04:34:52160[difficult](http://crbug.com/686239).
161
162### Why browser_tests?
163
164* `browser_tests` already provides a `browser()->window()` of a consistent
165 size that can be used as a dialog anchor and to take screenshots for UI
166 review.
167 * UI review have requested that screenshots be provided with the entire
Peter Kastingcf49b7b792017-12-18 23:27:45168 browser window so that the relative size of the UI element/change under
taptedf38739a2017-02-09 04:34:52169 review can be assessed.
170
Peter Kastingcf49b7b792017-12-18 23:27:45171* Some UI already has a test harness with appropriate setup (e.g. test data)
172 running in browser_tests.
173 * Supporting `BrowserUiTest` should require minimal setup and minimal
taptedf38739a2017-02-09 04:34:52174 ongoing maintenance.
175
176* An alternative is to maintain a working end-to-end build target executable
177 to do this, but this has additional costs (and is hard).
Peter Kastingc6fd7f2d2020-03-10 21:21:08178 * E.g. setup/teardown of low-level functions
179 (`InitializeGLOneOffPlatform()`, etc.).
taptedf38739a2017-02-09 04:34:52180
181* Why not chrome.exe?
Peter Kastingcf49b7b792017-12-18 23:27:45182 * E.g. a scrappy chrome:// page with links to invoke UI would be great!
taptedf38739a2017-02-09 04:34:52183 * But...
Peter Kastingcf49b7b792017-12-18 23:27:45184 * UI may have test data (e.g. credit card info) which shouldn’t be in
185 the release build.
186 * UI may use EmbeddedTestServer.
taptedf38739a2017-02-09 04:34:52187 * Higher maintenance cost - can’t leverage existing test harnesses.
188
189## Future Work
190
Peter Kastingcf49b7b792017-12-18 23:27:45191* Opt in more UI!
192 * Eventually, all of it.
193 * A `DialogBrowserTest` for every descendant of `views::DialogDelegate`.
taptedf38739a2017-02-09 04:34:52194
195* Automatically generate screenshots (for each platform, in various languages)
196 * Build upon [CL 2008283002](https://codereview.chromium.org/2008283002/)
197
198* (maybe) Try removing the subprocess
199 * Probably requires altering the browser_test suite code directly rather
200 than just adding a test case as in the current approach
201
Peter Kastingcf49b7b792017-12-18 23:27:45202* An automated test suite for UI
203 * Test various ways to dismiss or hide UI, especially dialogs
taptedf38739a2017-02-09 04:34:52204 * e.g. native close (via taskbar?)
205 * close parent window (possibly via task bar)
206 * close parent tab
207 * switch tabs
208 * close via `DialogClientView::AcceptWindow` (and `CancelWindow`)
209 * close via `Widget::Close`
210 * close via `Widget::CloseNow`
211 * Drag tab off browser into a new window
212 * Fullscreen that may create a new window/parent
213
Peter Kastingcf49b7b792017-12-18 23:27:45214* Find obscure workflows for invoking UI that has no test coverage and causes
215 crashes (e.g. [http://crrev.com/426302](http://crrev.com/426302))
taptedf38739a2017-02-09 04:34:52216 * Supporting window-modal dialogs with a null parent window.
217
218* Find memory leaks, e.g. [http://crrev.com/432320](http://crrev.com/432320)
219 * "Fix memory leak for extension uninstall dialog".
220
221## Appendix: Sample output
222
Peter Kastingcf49b7b792017-12-18 23:27:45223**$ ./out/gn_Debug/browser_tests --gtest_filter=BrowserUiTest.Invoke**
taptedf38739a2017-02-09 04:34:52224```
Peter Kastingcf49b7b792017-12-18 23:27:45225Note: Google Test filter = BrowserUiTest.Invoke
taptedf38739a2017-02-09 04:34:52226[==========] Running 1 test from 1 test case.
227[----------] Global test environment set-up.
Peter Kastingcf49b7b792017-12-18 23:27:45228[----------] 1 test from BrowserUiTest
229[ RUN ] BrowserUiTest.Invoke
230[26879:775:0207/134949.118352:30434675...:INFO:browser_ui_browsertest.cc(46)
231Pass one of the following after --ui=
232 AppInfoDialogBrowserTest.InvokeUi_default
233 AskGoogleForSuggestionsDialogTest.DISABLED_InvokeUi_default
234 BluetoothChooserBrowserTest.InvokeUi_ConnectedBubble
235 BluetoothChooserBrowserTest.InvokeUi_ConnectedModal
236/* and many more */
237[ OK ] BrowserUiTest.Invoke (0 ms)
238[----------] 1 test from BrowserUiTest (0 ms total)
taptedf38739a2017-02-09 04:34:52239[----------] Global test environment tear-down
240[==========] 1 test from 1 test case ran. (1 ms total)
241[ PASSED ] 1 test.
Peter Kastingcf49b7b792017-12-18 23:27:45242[1/1] BrowserUiTest.Invoke (334 ms)
taptedf38739a2017-02-09 04:34:52243SUCCESS: all tests passed.
244```
245
Peter Kastingcf49b7b792017-12-18 23:27:45246**$ ./out/gn_Debug/browser_tests --gtest_filter=BrowserUiTest.Invoke
247--ui=CardUnmaskPromptViewBrowserTest.InvokeUi_expired**
taptedf38739a2017-02-09 04:34:52248
249```
Peter Kastingcf49b7b792017-12-18 23:27:45250Note: Google Test filter = BrowserUiTest.Invoke
taptedf38739a2017-02-09 04:34:52251[==========] Running 1 test from 1 test case.
252[----------] Global test environment set-up.
Peter Kastingcf49b7b792017-12-18 23:27:45253[----------] 1 test from BrowserUiTest
254[ RUN ] BrowserUiTest.Invoke
taptedf38739a2017-02-09 04:34:52255Note: Google Test filter = CardUnmaskPromptViewBrowserTest.InvokeDefault
256[==========] Running 1 test from 1 test case.
257[----------] Global test environment set-up.
258[----------] 1 test from CardUnmaskPromptViewBrowserTest, where TypeParam =
Peter Kastingcf49b7b792017-12-18 23:27:45259[ RUN ] CardUnmaskPromptViewBrowserTest.InvokeUi_expired
taptedf38739a2017-02-09 04:34:52260/* 7 lines of uninteresting log spam */
Peter Kastingcf49b7b792017-12-18 23:27:45261[ OK ] CardUnmaskPromptViewBrowserTest.InvokeUi_expired (1324 ms)
taptedf38739a2017-02-09 04:34:52262[----------] 1 test from CardUnmaskPromptViewBrowserTest (1324 ms total)
263[----------] Global test environment tear-down
264[==========] 1 test from 1 test case ran. (1325 ms total)
265[ PASSED ] 1 test.
Peter Kastingcf49b7b792017-12-18 23:27:45266[ OK ] BrowserUiTest.Invoke (1642 ms)
267[----------] 1 test from BrowserUiTest (1642 ms total)
taptedf38739a2017-02-09 04:34:52268[----------] Global test environment tear-down
269[==========] 1 test from 1 test case ran. (1642 ms total)
270[ PASSED ] 1 test.
Peter Kastingcf49b7b792017-12-18 23:27:45271[1/1] BrowserUiTest.Invoke (2111 ms)
taptedf38739a2017-02-09 04:34:52272SUCCESS: all tests passed.
273```
274
Peter Kastingcf49b7b792017-12-18 23:27:45275**$ ./out/gn_Debug/browser_tests --gtest_filter=BrowserUiTest.Invoke
Peter Boströme2732ef2018-02-21 21:53:24276--ui=CardUnmaskPromptViewBrowserTest.InvokeUi_expired
277--test-launcher-interactive**
taptedf38739a2017-02-09 04:34:52278```
279/*
280 * Output as above, except the test are not interleaved, and the browser window
Peter Kastingcf49b7b792017-12-18 23:27:45281 * should remain open until the UI is dismissed
taptedf38739a2017-02-09 04:34:52282 */
283```
284
Peter Kastingcf49b7b792017-12-18 23:27:45285[chrome/browser/ui/test/test_browser_ui.h]: https://cs.chromium.org/chromium/src/chrome/browser/ui/test/test_browser_ui.h
taptedf38739a2017-02-09 04:34:52286[chrome/browser/ui/test/test_browser_dialog.h]: https://cs.chromium.org/chromium/src/chrome/browser/ui/test/test_browser_dialog.h
Peter Kastingcf49b7b792017-12-18 23:27:45287[chrome/browser/ui/ask_google_for_suggestions_dialog_browsertest.cc]: https://cs.chromium.org/chromium/src/chrome/browser/ui/ask_google_for_suggestions_dialog_browsertest.cc?l=18&q=ShowUi
288[chrome/browser/infobars/infobars_browsertest.cc]: https://cs.chromium.org/chromium/src/chrome/browser/infobars/infobars_browsertest.cc?l=134&q=UiBrowserTest
taptedf38739a2017-02-09 04:34:52289[ExtensionBrowserTest]: https://cs.chromium.org/chromium/src/chrome/browser/extensions/extension_browsertest.h?q=extensionbrowsertest&l=40