| Index: docs/testing/test_browser_dialog.md
|
| diff --git a/docs/testing/test_browser_dialog.md b/docs/testing/test_browser_dialog.md
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c96045556aeaa25c9fae213fcf3526461c6eaad3
|
| --- /dev/null
|
| +++ b/docs/testing/test_browser_dialog.md
|
| @@ -0,0 +1,279 @@
|
| +# Testing Chrome browser dialogs with TestBrowserDialog
|
| +
|
| +\#include "[chrome/browser/ui/test/test_browser_dialog.h]"
|
| +
|
| +`TestBrowserDialog` provides a way to register an `InProcessBrowserTest` testing
|
| +harness with a framework that invokes Chrome browser dialogs in a consistent
|
| +way. It optionally provides a way to invoke dialogs "interactively". This allows
|
| +screenshots to be generated easily, with the same test data, to assist with UI
|
| +review. It also provides a registry of dialogs so they can be systematically
|
| +checked for subtle changes and regressions.
|
| +
|
| +[TOC]
|
| +
|
| +## How to register a dialog
|
| +
|
| +If registering an existing dialog, there's a chance it already has a test
|
| +harness inheriting, using, or with `typedef InProcessBrowserTest` (or a
|
| +descendant of it). If so, using `TestBrowserDialog` is straightforward. Assume
|
| +the existing InProcessBrowserTest is in `foo_dialog_browsertest.cc`:
|
| +
|
| + class FooDialogTest : public InProcessBrowserTest { ...
|
| +
|
| +Change this to inherit from DialogBrowserTest, and override
|
| +`ShowDialog(std::string)`. See [Advanced Usage](#Advanced-Usage) for details.
|
| +
|
| +```cpp
|
| +class FooDialogTest : public DialogBrowserTest {
|
| + public:
|
| + ..
|
| + // DialogBrowserTest:
|
| + void ShowDialog(const std::string& name) override {
|
| + /* Show dialog attached to browser() and leave it open. */
|
| + }
|
| + ..
|
| +};
|
| +```
|
| +
|
| +Then add test invocations using the usual GTest macros, in
|
| +`foo_dialog_browsertest.cc`:
|
| +
|
| +```cpp
|
| +IN_PROC_BROWSER_TEST_F(FooDialogTest, InvokeDialog_default) {
|
| + RunDialog();
|
| +}
|
| +```
|
| +
|
| +Notes:
|
| +
|
| +* The body of the test is always just "`RunDialog();`".
|
| +* "`default`" is the `std::string` passed to `ShowDialog()` and can be
|
| + customized. See
|
| + [Testing additional dialog "styles"](#Testing-additional-dialog-styles_).
|
| +* The text before `default` (in this case) must always be "`InvokeDialog_`".
|
| +
|
| +### Concrete examples
|
| +
|
| +* [chrome/browser/ui/ask_google_for_suggestions_dialog_browsertest.cc]
|
| +* [chrome/browser/ui/autofill/card_unmask_prompt_view_browsertest.cc]
|
| +* [chrome/browser/ui/collected_cookies_browsertest.cc]
|
| +* [chrome/browser/ui/update_chrome_dialog_browsertest.cc]
|
| +
|
| +## Running the tests
|
| +
|
| +List the available dialogs with
|
| +
|
| + $ ./browser_tests --gtest_filter=BrowserDialogTest.Invoke
|
| +
|
| +E.g. `FooDialogTest.InvokeDialog_default` should be listed. To show the dialog
|
| +interactively, run
|
| +
|
| + $ ./browser_tests --gtest_filter=BrowserDialogTest.Invoke --interactive \
|
| + --dialog=FooDialogTest.InvokeDialog_default
|
| +
|
| +### Implementation
|
| +
|
| +`BrowserDialogTest.Invoke` searches for gtests that have "`InvokeDialog_`" in
|
| +their name, so they can be collected in a list. Providing a `--dialog` argument
|
| +will invoke that test case in a subprocess. Including `--interactive` will set
|
| +up an environment for that subprocess that allows interactivity, e.g., to take
|
| +screenshots. The test ends once the dialog is dismissed.
|
| +
|
| +The `FooDialogTest.InvokeDialog_default` test case **will still be run in the
|
| +usual browser_tests test suite**. Ensure it passes, and isn’t flaky. This will
|
| +give your dialog some regression test coverage. `RunDialog()` checks to ensure a
|
| +dialog is actually created when it invokes `ShowDialog("default")`.
|
| +
|
| +### BrowserDialogTest.Invoke
|
| +
|
| +This is also run in browser_tests but, when run that way, the test case just
|
| +lists the registered test harnesses (it does *not* iterate over them). A
|
| +subprocess is never created unless --dialog is passed on the command line.
|
| +
|
| +## Advanced Usage
|
| +
|
| +If your test harness inherits from a descendant of `InProcessBrowserTest` (one
|
| +example: [ExtensionBrowserTest]) then the `SupportsTestDialog<>` template is
|
| +provided. E.g.
|
| +
|
| +```cpp
|
| +class ExtensionInstallDialogViewTestBase : public ExtensionBrowserTest { ...
|
| +```
|
| +
|
| +becomes
|
| +
|
| +```cpp
|
| +class ExtensionInstallDialogViewTestBase :
|
| + public SupportsTestDialog<ExtensionBrowserTest> { ...
|
| +```
|
| +
|
| +### Testing additional dialog "styles"
|
| +
|
| +Add additional test cases, with a different string after "`InvokeDialog_`".
|
| +Example:
|
| +
|
| +```cpp
|
| +IN_PROC_BROWSER_TEST_F(CardUnmaskViewBrowserTest, InvokeDialog_expired) {
|
| + RunDialog();
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(CardUnmaskViewBrowserTest, InvokeDialog_valid) {
|
| + RunDialog();
|
| +}
|
| +```
|
| +
|
| +The strings "`expired`" or “`valid`” will be given as arguments to
|
| +`ShowDialog(std::string)`.
|
| +
|
| +## Rationale
|
| +
|
| +Bug reference: [Issue 654151](http://crbug.com/654151).
|
| +
|
| +Chrome has a lot of browser dialogs; often for obscure use-cases and often hard
|
| +to invoke. It has traditionally been difficult to be systematic while checking
|
| +dialogs for possible regressions. For example, to investigate changes to shared
|
| +layout parameters which are testable only with visual inspection.
|
| +
|
| +For Chrome UI review, screenshots need to be taken. Iterating over all the
|
| +"styles" that a dialog may appear with is fiddly. E.g. a login or particular web
|
| +server setup may be required. It’s important to provide a consistent “look” for
|
| +UI review (e.g. same test data, same browser size, anchoring position, etc.).
|
| +
|
| +Some dialogs lack tests. Some dialogs have zero coverage on the bots. Dialogs
|
| +can have tricky lifetimes and common mistakes are repeated. TestBrowserDialog
|
| +runs simple "Show dialog" regression tests and can be extended to do more.
|
| +
|
| +Even discovering the full set of dialogs present for each platform in Chrome is
|
| +[difficult](http://crbug.com/686239).
|
| +
|
| +### Why browser_tests?
|
| +
|
| +* `browser_tests` already provides a `browser()->window()` of a consistent
|
| + size that can be used as a dialog anchor and to take screenshots for UI
|
| + review.
|
| + * UI review have requested that screenshots be provided with the entire
|
| + browser window so that the relative size of the dialog/change under
|
| + review can be assessed.
|
| +
|
| +* Some dialogs already have a test harness with appropriate setup (e.g. test
|
| + data) running in browser_tests.
|
| + * Supporting `BrowserDialogTest` should require minimal setup and minimal
|
| + ongoing maintenance.
|
| +
|
| +* An alternative is to maintain a working end-to-end build target executable
|
| + to do this, but this has additional costs (and is hard).
|
| + * E.g. setup/teardown of low-level functions (
|
| + `InitializeGLOneOffPlatform()`,
|
| + `MaterialDesignController::Initialize()`, etc.).
|
| +
|
| +* Why not chrome.exe?
|
| + * E.g. a scrappy chrome:// page with links to invoke dialogs would be
|
| + great!
|
| + * But...
|
| + * A dialog may have test data (e.g. credit card info) which shouldn’t
|
| + be in the release build.
|
| + * A dialog may use EmbeddedTestServer.
|
| + * Higher maintenance cost - can’t leverage existing test harnesses.
|
| +
|
| +## Future Work
|
| +
|
| +* Opt in more dialogs!
|
| + * Eventually, all of them.
|
| + * A `BrowserDialogTest` for every descendant of `views::DialogDelegate`.
|
| +
|
| +* Automatically generate screenshots (for each platform, in various languages)
|
| + * Build upon [CL 2008283002](https://codereview.chromium.org/2008283002/)
|
| +
|
| +* (maybe) Try removing the subprocess
|
| + * Probably requires altering the browser_test suite code directly rather
|
| + than just adding a test case as in the current approach
|
| +
|
| +* An automated test suite for dialogs
|
| + * Test various ways to dismiss or hide a dialog
|
| + * e.g. native close (via taskbar?)
|
| + * close parent window (possibly via task bar)
|
| + * close parent tab
|
| + * switch tabs
|
| + * close via `DialogClientView::AcceptWindow` (and `CancelWindow`)
|
| + * close via `Widget::Close`
|
| + * close via `Widget::CloseNow`
|
| + * Drag tab off browser into a new window
|
| + * Fullscreen that may create a new window/parent
|
| +
|
| +* Find obscure workflows for invoking dialogs that have no test coverage and
|
| + cause crashes (e.g. [http://crrev.com/426302](http://crrev.com/426302))
|
| + * Supporting window-modal dialogs with a null parent window.
|
| +
|
| +* Find memory leaks, e.g. [http://crrev.com/432320](http://crrev.com/432320)
|
| + * "Fix memory leak for extension uninstall dialog".
|
| +
|
| +## Appendix: Sample output
|
| +
|
| +**$ ./out/gn_Debug/browser_tests --gtest_filter=BrowserDialogTest.Invoke**
|
| +```
|
| +Note: Google Test filter = BrowserDialogTest.Invoke
|
| +[==========] Running 1 test from 1 test case.
|
| +[----------] Global test environment set-up.
|
| +[----------] 1 test from BrowserDialogTest
|
| +[ RUN ] BrowserDialogTest.Invoke
|
| +[26879:775:0207/134949.118352:30434675...:INFO:browser_dialog_browsertest.cc(46)
|
| +Pass one of the following after --dialog=
|
| + AskGoogleForSuggestionsDialogTest.InvokeDialog_default
|
| + CardUnmaskPromptViewBrowserTest.InvokeDialog_expired
|
| + CardUnmaskPromptViewBrowserTest.InvokeDialog_valid
|
| + CollectedCookiesTestMd.InvokeDialog_default
|
| + UpdateRecommendedDialogTest.InvokeDialog_default
|
| +/* lots more will eventually be listed here */
|
| +[ OK ] BrowserDialogTest.Invoke (0 ms)
|
| +[----------] 1 test from BrowserDialogTest (0 ms total)
|
| +[----------] Global test environment tear-down
|
| +[==========] 1 test from 1 test case ran. (1 ms total)
|
| +[ PASSED ] 1 test.
|
| +[1/1] BrowserDialogTest.Invoke (334 ms)
|
| +SUCCESS: all tests passed.
|
| +```
|
| +
|
| +**$ ./out/gn_Debug/browser_tests --gtest_filter=BrowserDialogTest.Invoke
|
| +--dialog=CardUnmaskPromptViewBrowserTest.InvokeDialog_expired**
|
| +
|
| +```
|
| +Note: Google Test filter = BrowserDialogTest.Invoke
|
| +[==========] Running 1 test from 1 test case.
|
| +[----------] Global test environment set-up.
|
| +[----------] 1 test from BrowserDialogTest
|
| +[ RUN ] BrowserDialogTest.Invoke
|
| +Note: Google Test filter = CardUnmaskPromptViewBrowserTest.InvokeDefault
|
| +[==========] Running 1 test from 1 test case.
|
| +[----------] Global test environment set-up.
|
| +[----------] 1 test from CardUnmaskPromptViewBrowserTest, where TypeParam =
|
| +[ RUN ] CardUnmaskPromptViewBrowserTest.InvokeDialog_expired
|
| +/* 7 lines of uninteresting log spam */
|
| +[ OK ] CardUnmaskPromptViewBrowserTest.InvokeDialog_expired (1324 ms)
|
| +[----------] 1 test from CardUnmaskPromptViewBrowserTest (1324 ms total)
|
| +[----------] Global test environment tear-down
|
| +[==========] 1 test from 1 test case ran. (1325 ms total)
|
| +[ PASSED ] 1 test.
|
| +[ OK ] BrowserDialogTest.Invoke (1642 ms)
|
| +[----------] 1 test from BrowserDialogTest (1642 ms total)
|
| +[----------] Global test environment tear-down
|
| +[==========] 1 test from 1 test case ran. (1642 ms total)
|
| +[ PASSED ] 1 test.
|
| +[1/1] BrowserDialogTest.Invoke (2111 ms)
|
| +SUCCESS: all tests passed.
|
| +```
|
| +
|
| +**$ ./out/gn_Debug/browser_tests --gtest_filter=BrowserDialogTest.Invoke
|
| +--dialog=CardUnmaskPromptViewBrowserTest.InvokeDialog_expired --interactive**
|
| +```
|
| +/*
|
| + * Output as above, except the test are not interleaved, and the browser window
|
| + * should remain open until the dialog is dismissed
|
| + */
|
| +```
|
| +
|
| +[chrome/browser/ui/test/test_browser_dialog.h]: https://cs.chromium.org/chromium/src/chrome/browser/ui/test/test_browser_dialog.h
|
| +[chrome/browser/ui/autofill/card_unmask_prompt_view_browsertest.cc]: https://cs.chromium.org/chromium/src/chrome/browser/ui/autofill/card_unmask_prompt_view_browsertest.cc?l=104&q=ShowDialog
|
| +[chrome/browser/ui/collected_cookies_browsertest.cc]: https://cs.chromium.org/chromium/src/chrome/browser/ui/collected_cookies_browsertest.cc?l=26&q=ShowDialog
|
| +[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=ShowDialog
|
| +[chrome/browser/ui/update_chrome_dialog_browsertest.cc]: https://cs.chromium.org/chromium/src/chrome/browser/ui/update_chrome_dialog_browsertest.cc?l=15&q=ShowDialog
|
| +[ExtensionBrowserTest]: https://cs.chromium.org/chromium/src/chrome/browser/extensions/extension_browsertest.h?q=extensionbrowsertest&l=40
|
|
|