blob: 8d2f239ee974026858b6d84460765ef74edff66c [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
Keren Zhu1f7b99da2023-10-04 23:47:3276 $ ./interactive_ui_tests --gtest_filter=BrowserInteractiveUiTest.Invoke
taptedf38739a2017-02-09 04:34:5277
Peter Kastingcf49b7b792017-12-18 23:27:4578E.g. `FooUiTest.InvokeUi_default` should be listed. To show the UI
taptedf38739a2017-02-09 04:34:5279interactively, run
80
Keren Zhu1f7b99da2023-10-04 23:47:3281 # If FooUiTest is a browser test.
Peter Boströme2732ef2018-02-21 21:53:2482 $ ./browser_tests --gtest_filter=BrowserUiTest.Invoke \
83 --test-launcher-interactive --ui=FooUiTest.InvokeUi_default
taptedf38739a2017-02-09 04:34:5284
Keren Zhu1f7b99da2023-10-04 23:47:3285 # If FooUiTest is an interactive UI test.
86 $ ./interactive_ui_tests --gtest_filter=BrowserInteractiveUiTest.Invoke \
87 --test-launcher-interactive --ui=FooUiTest.InvokeUi_default
88
taptedf38739a2017-02-09 04:34:5289### Implementation
90
Peter Kastingcf49b7b792017-12-18 23:27:4591`BrowserUiTest.Invoke` searches for gtests that have "`InvokeUi_`" in their
92names, so they can be collected in a list. Providing a `--ui` argument will
Peter Boströme2732ef2018-02-21 21:53:2493invoke that test case in a subprocess. Including `--test-launcher-interactive`
94will set up an environment for that subprocess that allows interactivity, e.g.,
95to take screenshots. The test ends once the UI is dismissed.
taptedf38739a2017-02-09 04:34:5296
Peter Kastingcf49b7b792017-12-18 23:27:4597The `FooUiTest.InvokeUi_default` test case **will still be run in the usual
98browser_tests test suite**. Ensure it passes, and isn’t flaky. This will
99give your UI some regression test coverage. `ShowAndVerifyUi()` checks to ensure
100UI is actually created when it invokes `ShowUi("default")`.
taptedf38739a2017-02-09 04:34:52101
Keren Zhu1f7b99da2023-10-04 23:47:32102`BrowserInteractiveUiTest` is the equivalent of `BrowserUiTest` for
103interactive_ui_tests.
104
Peter Kastingcf49b7b792017-12-18 23:27:45105### BrowserUiTest.Invoke
taptedf38739a2017-02-09 04:34:52106
107This is also run in browser_tests but, when run that way, the test case just
108lists the registered test harnesses (it does *not* iterate over them). A
Peter Kastingcf49b7b792017-12-18 23:27:45109subprocess is never created unless --ui is passed on the command line.
taptedf38739a2017-02-09 04:34:52110
111## Advanced Usage
112
113If your test harness inherits from a descendant of `InProcessBrowserTest` (one
Peter Kastingcf49b7b792017-12-18 23:27:45114example: [ExtensionBrowserTest]) then the `SupportsTestUi<>` and
115`SupportsTestDialog` templates are provided. E.g.
taptedf38739a2017-02-09 04:34:52116
117```cpp
118class ExtensionInstallDialogViewTestBase : public ExtensionBrowserTest { ...
119```
120
121becomes
122
123```cpp
124class ExtensionInstallDialogViewTestBase :
125 public SupportsTestDialog<ExtensionBrowserTest> { ...
126```
127
Peter Kastingcf49b7b792017-12-18 23:27:45128If you need to do any setup before `ShowUi()` is called, or any teardown in the
129non-interactive case, you can override the `PreShow()` and `DismissUi()
130methods.
taptedf38739a2017-02-09 04:34:52131
Peter Kastingcf49b7b792017-12-18 23:27:45132### Testing additional UI "styles"
133
134Add additional test cases, with a different string after "`InvokeUi_`".
taptedf38739a2017-02-09 04:34:52135Example:
136
137```cpp
Peter Kastingcf49b7b792017-12-18 23:27:45138IN_PROC_BROWSER_TEST_F(CardUnmaskViewBrowserTest, InvokeUi_expired) {
139 ShowAndVerifyUi();
taptedf38739a2017-02-09 04:34:52140}
141
Peter Kastingcf49b7b792017-12-18 23:27:45142IN_PROC_BROWSER_TEST_F(CardUnmaskViewBrowserTest, InvokeUi_valid) {
143 ShowAndVerifyUi();
taptedf38739a2017-02-09 04:34:52144}
145```
146
147The strings "`expired`" or “`valid`” will be given as arguments to
Peter Kastingcf49b7b792017-12-18 23:27:45148`ShowUi(std::string)`.
taptedf38739a2017-02-09 04:34:52149
150## Rationale
151
152Bug reference: [Issue 654151](http://crbug.com/654151).
153
Peter Kastingcf49b7b792017-12-18 23:27:45154Chrome has a lot of browser UI; often for obscure use-cases and often hard to
155invoke. It has traditionally been difficult to be systematic while checking UI
156for possible regressions. For example, to investigate changes to shared layout
157parameters which are testable only with visual inspection.
taptedf38739a2017-02-09 04:34:52158
159For Chrome UI review, screenshots need to be taken. Iterating over all the
Peter Kastingcf49b7b792017-12-18 23:27:45160"styles" that UI may appear with is fiddly. E.g. a login or particular web
taptedf38739a2017-02-09 04:34:52161server setup may be required. It’s important to provide a consistent “look” for
162UI review (e.g. same test data, same browser size, anchoring position, etc.).
163
Peter Kastingcf49b7b792017-12-18 23:27:45164Some UI lacks tests. Some UI has zero coverage on the bots. UI elements can have
165tricky lifetimes and common mistakes are repeated. TestBrowserUi runs simple
166"Show UI" regression tests and can be extended to do more.
taptedf38739a2017-02-09 04:34:52167
Peter Kastingcf49b7b792017-12-18 23:27:45168Even discovering the full set of UI present for each platform in Chrome is
taptedf38739a2017-02-09 04:34:52169[difficult](http://crbug.com/686239).
170
171### Why browser_tests?
172
173* `browser_tests` already provides a `browser()->window()` of a consistent
174 size that can be used as a dialog anchor and to take screenshots for UI
175 review.
176 * UI review have requested that screenshots be provided with the entire
Peter Kastingcf49b7b792017-12-18 23:27:45177 browser window so that the relative size of the UI element/change under
taptedf38739a2017-02-09 04:34:52178 review can be assessed.
179
Peter Kastingcf49b7b792017-12-18 23:27:45180* Some UI already has a test harness with appropriate setup (e.g. test data)
181 running in browser_tests.
182 * Supporting `BrowserUiTest` should require minimal setup and minimal
taptedf38739a2017-02-09 04:34:52183 ongoing maintenance.
184
185* An alternative is to maintain a working end-to-end build target executable
186 to do this, but this has additional costs (and is hard).
Peter Kastingc6fd7f2d2020-03-10 21:21:08187 * E.g. setup/teardown of low-level functions
188 (`InitializeGLOneOffPlatform()`, etc.).
taptedf38739a2017-02-09 04:34:52189
190* Why not chrome.exe?
Peter Kastingcf49b7b792017-12-18 23:27:45191 * E.g. a scrappy chrome:// page with links to invoke UI would be great!
taptedf38739a2017-02-09 04:34:52192 * But...
Peter Kastingcf49b7b792017-12-18 23:27:45193 * UI may have test data (e.g. credit card info) which shouldn’t be in
194 the release build.
195 * UI may use EmbeddedTestServer.
taptedf38739a2017-02-09 04:34:52196 * Higher maintenance cost - can’t leverage existing test harnesses.
197
198## Future Work
199
Peter Kastingcf49b7b792017-12-18 23:27:45200* Opt in more UI!
201 * Eventually, all of it.
202 * A `DialogBrowserTest` for every descendant of `views::DialogDelegate`.
taptedf38739a2017-02-09 04:34:52203
204* Automatically generate screenshots (for each platform, in various languages)
205 * Build upon [CL 2008283002](https://codereview.chromium.org/2008283002/)
206
207* (maybe) Try removing the subprocess
208 * Probably requires altering the browser_test suite code directly rather
209 than just adding a test case as in the current approach
210
Peter Kastingcf49b7b792017-12-18 23:27:45211* An automated test suite for UI
212 * Test various ways to dismiss or hide UI, especially dialogs
taptedf38739a2017-02-09 04:34:52213 * e.g. native close (via taskbar?)
214 * close parent window (possibly via task bar)
215 * close parent tab
216 * switch tabs
217 * close via `DialogClientView::AcceptWindow` (and `CancelWindow`)
218 * close via `Widget::Close`
219 * close via `Widget::CloseNow`
220 * Drag tab off browser into a new window
221 * Fullscreen that may create a new window/parent
222
Peter Kastingcf49b7b792017-12-18 23:27:45223* Find obscure workflows for invoking UI that has no test coverage and causes
224 crashes (e.g. [http://crrev.com/426302](http://crrev.com/426302))
taptedf38739a2017-02-09 04:34:52225 * Supporting window-modal dialogs with a null parent window.
226
227* Find memory leaks, e.g. [http://crrev.com/432320](http://crrev.com/432320)
228 * "Fix memory leak for extension uninstall dialog".
229
230## Appendix: Sample output
231
Peter Kastingcf49b7b792017-12-18 23:27:45232**$ ./out/gn_Debug/browser_tests --gtest_filter=BrowserUiTest.Invoke**
taptedf38739a2017-02-09 04:34:52233```
Peter Kastingcf49b7b792017-12-18 23:27:45234Note: Google Test filter = BrowserUiTest.Invoke
taptedf38739a2017-02-09 04:34:52235[==========] Running 1 test from 1 test case.
236[----------] Global test environment set-up.
Peter Kastingcf49b7b792017-12-18 23:27:45237[----------] 1 test from BrowserUiTest
238[ RUN ] BrowserUiTest.Invoke
239[26879:775:0207/134949.118352:30434675...:INFO:browser_ui_browsertest.cc(46)
240Pass one of the following after --ui=
241 AppInfoDialogBrowserTest.InvokeUi_default
242 AskGoogleForSuggestionsDialogTest.DISABLED_InvokeUi_default
243 BluetoothChooserBrowserTest.InvokeUi_ConnectedBubble
244 BluetoothChooserBrowserTest.InvokeUi_ConnectedModal
245/* and many more */
246[ OK ] BrowserUiTest.Invoke (0 ms)
247[----------] 1 test from BrowserUiTest (0 ms total)
taptedf38739a2017-02-09 04:34:52248[----------] Global test environment tear-down
249[==========] 1 test from 1 test case ran. (1 ms total)
250[ PASSED ] 1 test.
Peter Kastingcf49b7b792017-12-18 23:27:45251[1/1] BrowserUiTest.Invoke (334 ms)
taptedf38739a2017-02-09 04:34:52252SUCCESS: all tests passed.
253```
254
Peter Kastingcf49b7b792017-12-18 23:27:45255**$ ./out/gn_Debug/browser_tests --gtest_filter=BrowserUiTest.Invoke
256--ui=CardUnmaskPromptViewBrowserTest.InvokeUi_expired**
taptedf38739a2017-02-09 04:34:52257
258```
Peter Kastingcf49b7b792017-12-18 23:27:45259Note: Google Test filter = BrowserUiTest.Invoke
taptedf38739a2017-02-09 04:34:52260[==========] Running 1 test from 1 test case.
261[----------] Global test environment set-up.
Peter Kastingcf49b7b792017-12-18 23:27:45262[----------] 1 test from BrowserUiTest
263[ RUN ] BrowserUiTest.Invoke
taptedf38739a2017-02-09 04:34:52264Note: Google Test filter = CardUnmaskPromptViewBrowserTest.InvokeDefault
265[==========] Running 1 test from 1 test case.
266[----------] Global test environment set-up.
267[----------] 1 test from CardUnmaskPromptViewBrowserTest, where TypeParam =
Peter Kastingcf49b7b792017-12-18 23:27:45268[ RUN ] CardUnmaskPromptViewBrowserTest.InvokeUi_expired
taptedf38739a2017-02-09 04:34:52269/* 7 lines of uninteresting log spam */
Peter Kastingcf49b7b792017-12-18 23:27:45270[ OK ] CardUnmaskPromptViewBrowserTest.InvokeUi_expired (1324 ms)
taptedf38739a2017-02-09 04:34:52271[----------] 1 test from CardUnmaskPromptViewBrowserTest (1324 ms total)
272[----------] Global test environment tear-down
273[==========] 1 test from 1 test case ran. (1325 ms total)
274[ PASSED ] 1 test.
Peter Kastingcf49b7b792017-12-18 23:27:45275[ OK ] BrowserUiTest.Invoke (1642 ms)
276[----------] 1 test from BrowserUiTest (1642 ms total)
taptedf38739a2017-02-09 04:34:52277[----------] Global test environment tear-down
278[==========] 1 test from 1 test case ran. (1642 ms total)
279[ PASSED ] 1 test.
Peter Kastingcf49b7b792017-12-18 23:27:45280[1/1] BrowserUiTest.Invoke (2111 ms)
taptedf38739a2017-02-09 04:34:52281SUCCESS: all tests passed.
282```
283
Peter Kastingcf49b7b792017-12-18 23:27:45284**$ ./out/gn_Debug/browser_tests --gtest_filter=BrowserUiTest.Invoke
Peter Boströme2732ef2018-02-21 21:53:24285--ui=CardUnmaskPromptViewBrowserTest.InvokeUi_expired
286--test-launcher-interactive**
taptedf38739a2017-02-09 04:34:52287```
288/*
289 * Output as above, except the test are not interleaved, and the browser window
Peter Kastingcf49b7b792017-12-18 23:27:45290 * should remain open until the UI is dismissed
taptedf38739a2017-02-09 04:34:52291 */
292```
293
Peter Kastingcf49b7b792017-12-18 23:27:45294[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:52295[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:45296[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
297[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:52298[ExtensionBrowserTest]: https://cs.chromium.org/chromium/src/chrome/browser/extensions/extension_browsertest.h?q=extensionbrowsertest&l=40