blob: 99f57524496174a0d72f528619820c67d440cde5 [file] [log] [blame] [view]
Daniel Murphy11adede82021-06-03 15:05:061# [Web Apps](../README.md) - Testing
2
3
Daniel Murphyb3a8760a2023-03-03 20:09:574Please read [Testing In Chromium][13] for general guidance on writing tests in chromium.
Daniel Murphy11adede82021-06-03 15:05:065
Daniel Murphyb3a8760a2023-03-03 20:09:576The following tests are expected for writing code in this system:
Daniel Murphy11adede82021-06-03 15:05:067
Daniel Murphyb3a8760a2023-03-03 20:09:578* Unit tests
9* Browser tests
10* Integration tests
Daniel Murphy11adede82021-06-03 15:05:0611
Daniel Murphyb3a8760a2023-03-03 20:09:5712### Known Issues
Daniel Murphy11adede82021-06-03 15:05:0613
Daniel Murphyb3a8760a2023-03-03 20:09:5714- Unit tests currently cannot rely on `WebContents` functionality, as that is not built as part of unit test frameworks. Instead, they must use the `FakeWebAppUrlLoader` or `FakeWebAppDataRetriever` classes.
15 - Note: This should be fixed in early 2023. See [bug][1] to make it easier to install apps in unit tests that require a web contents and [bug][2] to improve the `WebContents` dependency and current helper classes to allow the WebAppProvider system to not directly depend on `WebContents`.
16- Installing web apps before the WebAppProvider system starts can be cumbersome.
17 - Browser tests can use the `PRE_` test functionality to set up any state.
18 - Unit tests must either load a static profile directory saved in the test data, or create a test-only way to explicitly delay the desired subsystem from starting.
Daniel Murphy11adede82021-06-03 15:05:0619
20## Unit tests
Daniel Murphy11adede82021-06-03 15:05:0621
Daniel Murphyb3a8760a2023-03-03 20:09:5722Unit tests have the following benefits:
Daniel Murphy11adede82021-06-03 15:05:0623
Daniel Murphyb3a8760a2023-03-03 20:09:5724* They are very efficient.
25* They run on all relevant CQ trybots.
26* They will always be supported by the [code coverage][8] framework.
Daniel Murphy11adede82021-06-03 15:05:0627
Daniel Murphyb3a8760a2023-03-03 20:09:5728Unit tests are the fastest tests to execute and are expected to be used to test most cases, especially error cases. They are usually built on the `WebAppTest` base class, and use the `FakeWebAppProvider` to customize (or not) the [dependencies][3] of the `WebAppProvider` system.
Daniel Murphy11adede82021-06-03 15:05:0629
Daniel Murphyb3a8760a2023-03-03 20:09:5730Notes
Daniel Murphy11adede82021-06-03 15:05:0631
Daniel Murphyb3a8760a2023-03-03 20:09:5732- UI elements do not work in unit tests, and the appropriate fakes must be used (see [External Dependencies][3]).
33- If one of the external dependencies of the system cannot be faked out yet or the feature is tightly coupled to this, then it might make sense to use a browser test instead (or make that dependency fake-able).
34- Please use the [`WebAppTest`][4] base class if possible.
Zelin Liufc9a90d2023-08-16 17:47:0135- Unit tests based on `WebAppTest` print a snapshot of chrome://web-app-internals to console on test failures. This can be a powerful debugging tool. The command line flag `--disable-web-app-internals-log` can be used to disable this feature.
Daniel Murphy11adede82021-06-03 15:05:0636
37## Browser tests
Daniel Murphy11adede82021-06-03 15:05:0638
Daniel Murphyb3a8760a2023-03-03 20:09:5739With improved web app test support, most of the components should using unittests to cover the detailed test cases.
Daniel Murphy11adede82021-06-03 15:05:0640
Daniel Murphyb3a8760a2023-03-03 20:09:5741Creating an integration test (using the integration framework) should satisfy the need for end-to-end tests for major use-cases of your feature. However, you may need to create one due to:
Daniel Murphy11adede82021-06-03 15:05:0642
Daniel Murphyb3a8760a2023-03-03 20:09:5743- The unittest framework doesnt support certain needs.
44- You need end-to-end test, but using integration test framework has too much overhead.
Daniel Murphy11adede82021-06-03 15:05:0645
Daniel Murphyb3a8760a2023-03-03 20:09:5746Browser tests are much more expensive to run, as they run a fully functional browser. These tests are usually only created to test functionality that requires multiple parts of the system to be running or dependencies like the Sync service to be fully running and functional. It is good practice to have browsertests be as true-to-user-action as possible, to make sure that as much of our stack is exercised.
Daniel Murphy11adede82021-06-03 15:05:0647
Glen Robertsonb8d47732024-04-16 10:29:3848An example set of browser tests are in [`web_app_browsertest.cc`][6]. Please use the [`WebAppBrowserTestBase`][5] base class.
Daniel Murphy11adede82021-06-03 15:05:0649
Zelin Liufc9a90d2023-08-16 17:47:0150Notes
51
Glen Robertsonb8d47732024-04-16 10:29:3852- Browser tests based on `WebAppBrowserTestBase` print a snapshot of chrome://web-app-internals to console on test failures. This can be a powerful debugging tool. The command line flag `--disable-web-app-internals-log` can be used to disable this feature.
Zelin Liufc9a90d2023-08-16 17:47:0153
Daniel Murphy11adede82021-06-03 15:05:0654## Integration tests
Daniel Murphyb3a8760a2023-03-03 20:09:5755
56We have a custom integration testing framework that we use due to the complexity of our use-cases. See [integration-testing-framework.md][7] for more information.
57
58**It is a good idea to think about your integration tests early & figure out your CUJs with the team. Having your CUJs and integration tests working early greatly speeds up development & launch time.**
59
Zelin Liufc9a90d2023-08-16 17:47:0160Notes
61
62- Integration tests using `WebAppIntegrationTestDriver` print a snapshot of chrome://web-app-internals to console on test failures. This can be a powerful debugging tool. The command line flag `--disable-web-app-internals-log` can be used to disable this feature.
63
Daniel Murphyb3a8760a2023-03-03 20:09:5764## Testing OS integration
65
Glen Robertsonb8d47732024-04-16 10:29:3866It is very common to test OS integration. By default, OS integration is suppressed if the test extends [`WebAppTest`][4] or [`WebAppBrowserTestBase`][5].
Daniel Murphyb3a8760a2023-03-03 20:09:5767
68End-to-end OS integration testing is facilitated using the [`OsIntegrationTestOverride`][9]. If OS integration CAN be tested in an automated way, this class will do so. If not, the existence of this override will stub-out the OS integration at the lowest level to test as much of our code as possible.
69
70## `Fake*` classes
71
72A class that starts with `Fake` is meant to completely replace a component of the system. They inherit from a base class with virtual methods, and allow a test to specify custom behavior or checks. The component should seem to be working correctly to other system components, but with behavior that is defined by a test.
73
74The most common pattern here is that the Fake will by default appear to work correctly, and a test can either specify it to return custom results, fail in specific ways, or simply check that it was used in the correct way.
75
76An example is [fake_os_integration_manager.h][14], which pretends to successfully perform install, update, and uninstall operations on OS integration, but instead pretends to work and does simple bookkeeping for tests to check that it was called correctly.
77
78## `Mock*` classes
79
80A class that start with `Mock` is a [gmock][12] version of the class. This allows the user to have complete control of exactly what that class does, verify it is called exactly as expected, etc. These tend to be much more powerful to use than a `Fake`, as you can easily specify every possible case you might want to check, like which arguments are called and the exact calling order of multiple functions, even across multiple mocks. The downsides are:
81* Mocks end up being very verbose to use, often at the expense of test readiability.
82* Mocks require creating a mock class & learning how to use gmock.
83
84These are generally not preferred to a "Fake".
85
86## Tool: `FakeWebAppProvider`
87
88The [`FakeWebAppProvider`][11] is basically a fake version of the WebAppProvider system, that uses the [`WebAppProvider`][10] root class to set up subsystems and can be used to selectively set fake subsystems or shut them
89down on a per-demand basis to test system shutdown use-cases.
90
91By default, the `FakeWebAppProvider` will NOT start the `WebAppProvider` system, and it must be manually done so. This is usually done by calling [`AwaitStartWebAppProviderAndSubsystems`][15].
92
93## Common issue: Waiting
94
95Many operations that happen at higher levels that the commands / scheduling system in the WebAppProvider require that tests wait for async operations to complete.
96
97### Tabs & Browsers
98
99* `AllBrowserTabAddedWaiter` - Waits for a tab to be added anywhere (works for both app browser and regular browser).
100* `BrowserChangeObserver` - Waits for a browser to add or remove.
101
102### Navigation & Loading
103
104* `UrlLoadObserver` - Waits for given url to load anywhere.
105* `content::TestNavigationObserver` - Waits for a navigation anywhere or in given WebContents. See StartWatchingNewWebContents to watch all web contents.
106* `content::WebContentsObserver` - Can generally be used to wait for events on a given `content::WebContents`
107 * To wait for `onload` to complete in a page, the `::DocumentOnLoadCompletedInPrimaryMainFrame` can be used if `WebContents::IsDocumentOnLoadCompletedInPrimaryMainFrame()` returns false.
108
109### `WebAppProvider` commands
110
111[`WebAppCommandManager::AwaitAllCommandsCompleteForTesting`][16] will wait for all commands to complete. This will mostly handle all tasks in the `WebAppProvider`.
112
113## Common issue: External Dependency that isn't faked
114
115Sometimes classes use a dependency that either doesn't work or isn't fake-able in our system.
116
1171. Can you just not depend on that? The best way is to remove the dependency entirely if possible.
1181. If there is a way to easily fake the dependency that is already supported, then do that next.
119 - e.g. if it's a `KeyedService`, and the authors have a fake version you can use, then use that. See how it is used elsewhere.
1201. Create a new interface for this new external dependency, put it on the `WebAppProvider`, and create a fake for it so that you can test with it faked.
1211. If all else fails, use a browser test.
122
123[1]: https://b/269618710
124[2]: http://b/271124885
125[3]: README.md#external-dependencies
126[4]: https://source.chromium.org/search?q=web_app_test.h
Glen Robertsonb8d47732024-04-16 10:29:38127[5]: https://source.chromium.org/search?q=WebAppBrowserTestBase
Daniel Murphyb3a8760a2023-03-03 20:09:57128[6]: https://source.chromium.org/search?q=web_app_browsertest.cc
129[7]: integration-testing-framework.md
130[8]: ../testing/code_coverage.md
131[9]: https://source.chromium.org/search?q=OsIntegrationTestOverride
132[10]: https://source.chromium.org/search?q=WebAppProvider
133[11]: https://source.chromium.org/search?q=FakeWebAppProvider
134[12]: https://github.com/google/googletest/tree/HEAD/googlemock
135[13]: ../testing/testing_in_chromium.md
136[14]: https://source.chromium.org/search?q=FakeOsIntegrationManager
137[15]: https://source.chromium.org/search?q=AwaitStartWebAppProviderAndSubsystems
138[16]: https://source.chromium.org/search?q=AwaitAllCommandsCompleteForTesting