blob: 37b22b9ecde15e49e94bdd1e8ce242641757c61a [file] [log] [blame] [view]
Daniel Murphy27a6bd02021-11-03 18:58:461# Desktop Web App Integration Testing Framework
2
3[TOC]
4
5## Background
6
7The WebAppProvider system has very wide action space and testing state interactions between all of the subsystems is very difficult. The integration testing framework is intended to help testing critical user journeys for installable web apps in a scalable fashion.
8
9The framework and process is broken down into the following pieces:
101. A list of [critical user journeys][cuj-spreadsheet] and the [actions][cuj-actions-sheet] used to make those journeys.
112. A [script][generate-script] that can process these (along with information about which action is supported by which platform).
123. [Tests][default-tests] generated by the script that use the [`WebAppIntegrationTestDriver`][test-driver] to execute actions.
134. [Coverage][coverage-win] information about what percentage of the critical user journeys are covered.
14
Daniel Murphy0ffd42c82022-07-22 22:12:2515How-tos / guides:
Daniel Murphy27a6bd02021-11-03 18:58:4616* [How to create WebApp Integration Tests][how-to-create]
17* [Disabling a test](#disabling-a-test)
Daniel Murphy0ffd42c82022-07-22 22:12:2518* [Why is this test failing?][why-is-this-test-failing]
Daniel Murphy27a6bd02021-11-03 18:58:4619
20Related:
21 * [WebAppProvider README.md](/chrome/browser/web_applications/README.md)
22
Phillis Tang55bb5e702022-02-11 21:59:5823## When to add integration tests?
Daniel Murphyfd7822a2022-04-11 18:39:2924Any web app feature (or any code in general) should have a combination of unit tests and browser tests that focus on testing the specific feature itself. Unit tests are the least likely to become flaky, and allow fine-grained testing of a system. Browser tests are more likely to be flaky but enable testing with most of the system running. Regular unit tests or browser tests should be used for testing system parts in isolation and for testing minute details like handling of error cases.
25
26Integration tests are required for all critical user journeys for the dPWA (or installable web app) product. If a feature is to be considered "supported" on the dPWA platform, then it MUST have it's critical user journeys described and integration tests generated for these journeys.
Phillis Tang55bb5e702022-02-11 21:59:5827
Daniel Murphy27a6bd02021-11-03 18:58:4628## Future Work
29
Daniel Murphyd8a8ce92022-03-30 14:51:3630* Change arguments from string values (e.g. `"SiteA"`) to enumeration values (e.g. `Site::kSiteA`).
Daniel Murphy27a6bd02021-11-03 18:58:4631* Making test generation friendlier for the developer.
32 * Detecting incorrect tests.
33 * Modifying tests automatically in common scenarios.
34
35## Terminology
36
37### Action
38A primitive test operation, or test building block, that can be used to create coverage tests. The integration test framework may or may not support an action on a given platform. Actions can fall into one of three types:
39* State-change action
40* State-check action
41* parameterized action
42
43Actions also can be fully, partially, or not supported on a given platform. This information is used when generating the tests to run & coverage report for a given platform. To make parsing easier, actions are always snake_case.
44
45#### State-change Action
46A state-changing action is expected to change the state chrome or the web app provider system.
47
48Examples: `navigate_browser(SiteA)`, `switch_incognito_profile`, `sync_turn_off`, `set_app_badge`
49
50#### State-check Action
51Some actions are classified as "state check" actions, which means they do not change any state and only inspect the state of the system. In graph representations, state check actions are not given nodes, and instead live under the last non-state-check action.
52
53All actions that start with `check_` are considered state-check actions.
54
55Examples: `check_app_list_empty`, `check_install_icon_shown`, `check_platform_shortcut_exists(SiteA)`, `check_tab_created`
56
Daniel Murphyd8a8ce92022-03-30 14:51:3657#### Action Arguments
Daniel Murphy27a6bd02021-11-03 18:58:4658When creating tests, there emerged a common scenario where a given action could be applied to multiple different sites. For example, the “navigate the browser to an installable site” action was useful if “site” could be customized.
59
Daniel Murphyfd7822a2022-04-11 18:39:2960To accept arguments, list the argument [types][cuj-enums-sheet] you wish to accept in the "Argument Types" column in the actions [file][cuj-actions-sheet]. If an required argument type does not exist, please add it to that [file][cuj-enums-sheet].
Daniel Murphy27a6bd02021-11-03 18:58:4661
Daniel Murphy6ad32d62022-08-15 20:40:2762When a test specified as action with arguments, it can also specify `ArgType::All`, which will create a separate test for every possible value of that argument.
63
Daniel Murphyd8a8ce92022-03-30 14:51:3664To allow for future de-parsing of modes (when generating C++ tests), modes will always be PascalCase.
65
66##### Default argument values
67Each [enumeration][cuj-enums-sheet] can specify a "default" enumeration value that is used if the test does not specify an argument value. This is done by a `*` character.
Daniel Murphy27a6bd02021-11-03 18:58:4668
69#### Parameterized Action
70To help with testing scenarios like outlined above, an action can be defined that references or 'turns into' a set of non-parameterized actions. For example, an action `install_windowed` can be created and reference the set of actions `install_omnibox_icon`, `install_menu_option`, `install_create_shortcut_windowed`, `add_policy_app_windowed_shortcuts`, and `add_policy_app_windowed_no_shortcuts`. When a test case includes this action, it will generate multiple tests in which the parameterized action is replaced with the non-parameterized action.
71
Daniel Murphyd8a8ce92022-03-30 14:51:3672##### Arguments & Argument Forwarding
73**All output actions must have their arguments fully specified, no defaults are respected**. This avoids implementation complexity and mistakes.
74
75To "forward" arguments from the parent parameterized action to the output actions, you can use the bash-style argument syntax.
76
77Example output actions for `install_windowed`, which has a single `Site` argument:
78* `install_omnibox_icon($1)`,
79* `install_create_shortcut_windowed($1)`,
80* `add_policy_app_windowed_shortcuts($1)`,
81* etc
82
83These actions use the first argument of the parent action as their argument.
84
Daniel Murphy27a6bd02021-11-03 18:58:4685### Tests
86A sequence of actions used to test the WebAppProvider system. A test that can be run by the test framework must not have any "parameterized" actions, as these are supposed to be used to generate multiple tests.
87
88#### Unprocessed Required-coverage tests
Daniel Murphyfd7822a2022-04-11 18:39:2989This is the set of tests that, if all executed, should provide full test coverage for the WebAppProvider system. They currently live in this file as "unprocessed".
Daniel Murphy27a6bd02021-11-03 18:58:4690
91#### Required-coverage tests (processed)
Daniel Murphyfd7822a2022-04-11 18:39:2992Processed tests go through the following steps from the unprocessed version in the file:
Daniel Murphy27a6bd02021-11-03 18:58:4693* Tests with one or more "parameterized" actions have been processed to produce the resulting tests without parameterized actions.
Daniel Murphyd8a8ce92022-03-30 14:51:3694* Actions in tests that have arguments but do not specify them have the default argument added to them. Default arguments are known only if all argument types have a default value specified.
Daniel Murphy27a6bd02021-11-03 18:58:4695
96#### Platform-specific tests
Daniel Murphyfd7822a2022-04-11 18:39:2997The first column of the test specifies which platforms the test should be created for:
98- `W` = Windows
99- `M` = Mac
100- `L` = Linux
101- `C` = ChromeOS
102
103This is because some tests need to be platform-specific. For example, all tests that involve "locally installing" an app are only applicable on Windows/Mac/Linux, as ChromeOS automatically locally installs all apps from sync. Because of this, tests must be able to specify which platforms they should be run on.
Daniel Murphy27a6bd02021-11-03 18:58:46104
105### Sync Partition and Default Partition
106Due to some browsertest support limitations, certain actions are only supported in the sync testing framework. Because of this, the script supports a separate "partition" of tests for any test that uses sync actions. This means that at test output time, a test will either go in the "sync" partition or the "default" partition.
107
108See the [sync tests design doc][sync-tests-dd] for more information.
109
110## Script Design & Usage
111The [script][generate-script] takes the following information:
112* A list of [action][cuj-actions-sheet]-based [tests][cuj-spreadsheet] which fully test the WebAppProvider system (a.k.a. required-coverage tests).
113* A list of actions [supported][framework-supported-actions] by the integration test framework (per-platform).
114
115The results of running the script is:
116* Console output (to stdout) of the minimal number of tests (per-platform) to run to achieve the maximum coverage of the critical user journeys.
117 * If tests already exist, then these are taken into account and not printed.
118 * If any existing tests are unnecessary, then the script will inform the developer that they can be removed.
119* The resulting [coverage][coverage-win] of the system (with required-coverage tests as 100%).
120
121See the [design doc][design-doc] for more information and links.
122
123### Downloading test data
124
125The test data is hosted in this [spreadsheet][cuj-spreadsheet]. To download the latest copy of the data, run the included script:
126```sh
127./chrome/test/webapps/download_data_from_sheet.py
128```
129
130This will download the data from the sheet into csv files in the [data/][script-data-dir] directory:
131
132* `actions.csv` This describes all actions that can be used in the required coverage tests (processed or unprocessed).
Daniel Murphyfd7822a2022-04-11 18:39:29133* `coverage_required.csv` This is the full list of all tests needed to fully cover the Web App system. The first column specifies the platforms for testing, and the test starts on the second column.
Daniel Murphy27a6bd02021-11-03 18:58:46134
135### Generating test descriptions & coverage
136
137Required test changes are printed and coverage files are written by running:
138```sh
139chrome/test/webapps/generate_framework_tests_and_coverage.py
140```
141This uses the files in `chrome/test/webapps/data` and existing browsertests on the system (see `custom_partitions` and `default_partitions` in [`generate_framework_tests_and_coverage.py`][generate-script]) to:
142
Clifford Cheng0626c86e2023-05-02 07:29:35143#### 1) Print all detected browsertests' changes to `stdout` or to existing test files.
144The script can remove tests (--delete-in-place) or add tests (--add-to-file) to existing test files.
145It is not smart enough to automatically create new test files and add tests to them because it usually involves modifying the BUILD file. If the test file does not exist, the file name and the tests will be printed out to `stdout` instead.
146If none of these flags are used, the script prints out the tests that need to be added or removed to `stdout` and have the tests match what it expects. It assumes:
Daniel Murphy27a6bd02021-11-03 18:58:46147 * Browsertests are correctly described by the `TestPartitionDescription`s in [`generate_framework_tests_and_coverage.py`][generate-script].
148 * Browsertests with the per-platform suffixes (e.g. `_mac`, `_win`, etc) are only run on those platforms
149
Clifford Cheng0626c86e2023-05-02 07:29:35150This process doesn't modify the browsertests that are disabled by sheriffs. The script runner is thus expected to make the requested changes manually. In the rare case that a test is moving between files (if we are enabling a test on a new platform, for example), then the script runner should be careful to copy any sheriff changes to the browsertest as well.
Daniel Murphy27a6bd02021-11-03 18:58:46151
152#### 2) Generate per-platform processed required coverage `tsv` files in `chrome/test/webapps/coverage`
153These are the processed required coverage tests with markers per action to allow a conditional formatter (like the one [here][cuj-coverage-sheet]) to highlight what was and was not covered by the testing framework.
154 * These files also contain a coverage % at the top of the file. Full coverage is the percent of the actions of the processed required coverage test that were executed and fully covered by the framework. Partial coverage also includes actions that are partially covered by the framework.
155 * This includes loss of coverage from any disabled tests. Cool!
156
157### Exploring the tested and coverage graphs
158
159To view the directed graphs that are generated to process the test and coverage data, the `--graphs` switch can be specified:
160```sh
161chrome/test/webapps/generate_framework_tests_and_coverage.py --graphs
162```
163
164This will generate:
165* `coverage_required_graph.dot` - The graph of all of the required test coverage. Green nodes are actions explicitly listed in the coverage list, and orange nodes specify partial coverage paths.
166* `framework_test_graph_<platform>.dot` - The graph that is now tested by the generated framework tests for the given platform, including partial coverage.
167
168The [graphviz](https://graphviz.org/) library can be used to view these graphs. An install-free online version is [here](https://dreampuf.github.io/GraphvizOnline/).
169
Clifford Cheng81e46cb2023-03-20 17:02:57170### Running new tests locally
171
172gtest_filter for all for any new or modified tests in `browser_tests` and `sync_integration_tests` can be generated by running:
173```sh
174chrome/test/webapps/generate_gtest_filter_for_added_tests.py
175```
176
177The output format will be
178```sh
179browser_tests --gtest_filter=<test_name>
180
181sync_integration_tests --gtest_filter=<test_name>
182```
183The new tests can be triggered by adding the path to `browser_tests` or `sync_integration_tests` binaries.
184
Daniel Murphy27a6bd02021-11-03 18:58:46185### Debugging Further
186
187To help debug or explore further, please see the [`graph_cli_tool.py`](graph_cli_tool.py) script which includes a number of command line utilities to process the various files.
188
Dibyajyoti Pal3c797c22024-11-23 00:43:48189Both this file and the [`generate_framework_tests_and_coverage.py`][generate-script] file support the `-v` option to print out informational logging.
190
191### Uploading test CLs
192
193Once the tests have been generated from the CUJs, always run [`generate_framework_tests_and_coverage.py`][generate-script] as a sanity check to ensure that this outputs nothing in the terminal. This means that the [critical user journeys][cuj-spreadsheet] and the generated tests across all files are in sync and no new tests need to be generated. If this outputs something on the terminal, perform the debugging steps outlined above to understand why the two converge.
Daniel Murphy27a6bd02021-11-03 18:58:46194
195## [`WebAppIntegrationTestDriver`][test-driver] and Browsertest Implementation
196
197After the script has output the tests that are needed, they still need to be compiled and run by something. The [`WebAppIntegrationTestDriver`][test-driver] is what runs the actions, and the browsertests themselves are put into specific files based on which partition they will be run in (default or sync), and which platforms will be running them.
198
199These are all of the files that make up the browsertest and browsertest support of the dPWA integration test framework:
200
201* [`WebAppIntegrationTestDriver`][test-driver] - This class implements most actions that are used by the generated tests.
202* [`web_app_integration_browsertest.cc`][default-tests] - These are the cross-platform tests in the default partition.
203 * [`web_app_integration_browsertest_mac_win_linux.cc`][default-tests-mwl] - These are the default partition tests that only run on mac, windows, and linux.
204 * [`web_app_integration_browsertest_cros.cc`][default-tests-cros].
205* `two_client_web_apps_integration_test_*` - These are the tests in the sync partition.
206 * [`two_client_web_apps_integration_test_mac_win_linux.cc`][sync-tests-mwl]
207 * [`two_client_web_apps_integration_test_cros.cc`][sync-tests-cros]
208
209### Creating Action Implementations
210
211The driver implements all actions for the generated tests. For tests in the sync partition (which require the functionality of the [`SyncTest`][sync-test-base] base class), some actions are delegated to the [`two_client_web_apps_integration_test_base.h`][sync-tests-base]).
212
213Testing actions must:
214* Call the appropriate `BeforeState*Action()` and `AfterState*Action()` functions inside of their function body.
215* Wait until the action is fully completed before returning.
216* Try to exercise code as close to the user-level action as reasonably possible.
217* Accommodate multiple browsertests running at the same time on the trybot (be careful modifying global information on an operating system).
218* Ensure that, at the end of the test, all side effects are cleaned up in `TearDownOnMainThread()`.
219
220To help with state-check actions, the state of the system is recorded before and after every state-change action. This allows for actions to detect any changes that happened in the last state-change action. This is stored in `before_state_change_action_state_` and `after_state_change_action_state_`, and generated by calling `ConstructStateSnapshot()`.
221
222When adding actions, it may be useful to add information into this state snapshot in order to verify the results of state-change actions within state-check actions. To do this:
223* Add a field onto the relevant state object.
224* Update the `==` and `<<` operators.
225* Populate the field in the `ConstructStateSnapshot()` method.
226
227Then, this field can be accessed in the `before_state_change_action_state_` and `after_state_change_action_state_` members appropriately.
228
Daniel Murphyfd7822a2022-04-11 18:39:29229### Running the tests on Mac
230
231There is a [history](https://crbug.com/1042757) of browser_tests being disabled on Mac trybots & CQ (but they run on the waterfall). To ensure there are no mac failures for changes to integration tests:
232- Click on the "Choose Trybots" button in Gerrit.
233- Filter for "mac"
234- Choose applicable builders from the "luci.chromium.try" section. Examples (from 2022.04.08):
235 - mac11-arm64-rel
Zhaoyang Li5d3713d2022-06-13 18:01:17236 - mac12-arm64-rel
Daniel Murphyfd7822a2022-04-11 18:39:29237 - mac_chromium_10.11_rel_ng
238 - mac_chromium_10.12_rel_ng
239 - mac_chromium_10.13_rel_ng
240 - mac_chromium_10.14_rel_ng
241 - mac_chromium_10.15_rel_ng
242 - mac_chromium_11.0_rel_ng
243 - mac_chromium_asan_rel_ng
244
245Running tests on these bots MAY have other random failures happening. That is normal.
246
Daniel Murphy27a6bd02021-11-03 18:58:46247### Disabling a Test
248
249Tests can be disabled in the same manner that other integration/browser tests are disabled, using macros. See [on disabling tests](/docs/testing/on_disabling_tests.md) for more information.
250
Dibyajyoti Pal3c797c22024-11-23 00:43:48251### Modifying a test
252
253If you need to modify a test, that means you are changing a critical user journey on the platform. If that is intentional, then modifications must be done to the [critical-user-journey markdown file][cuj-spreadsheet], and not the tests - they are generated from this markdown and should always stay in-sync.
254
Daniel Murphy27a6bd02021-11-03 18:58:46255## Understanding and Implementing Test Cases
256
257Actions are the basic building blocks of integration tests. A test is a sequence of actions. Each action has a name that must be a valid C++ identifier.
258
259Actions are defined (and can be modified) in [this][cuj-actions-sheet] sheet. Tests are defined (and can be modified) in [this][cuj-spreadsheet] sheet.
260
261### Action Creation & Specification
262
263[Actions][cuj-actions-sheet] are the building blocks of tests.
264
Daniel Murphyd8a8ce92022-03-30 14:51:36265This section is meant to help describe how the testing script works internally, but may not be helpful for those just looking to simply run the script.
266
Daniel Murphy27a6bd02021-11-03 18:58:46267#### Templates
Daniel Murphyd8a8ce92022-03-30 14:51:36268To help making test writing less repetitive, actions are described as templates in the [actions][cuj-actions-sheet] spreadsheet. Action templates specify actions while avoiding rote repetition. Each action template has a name (the **action base name**). Each action template supports arguments, which must be defined in the [enumeration sheet][cuj-enums-sheet]. Parameter values must also be valid C++ identifiers.
Daniel Murphy27a6bd02021-11-03 18:58:46269
Daniel Murphyd8a8ce92022-03-30 14:51:36270An action template without arguments specifies one action whose name matches the template. For example, the `check_tab_created` template generates the `check_tab_created` action.
Daniel Murphy27a6bd02021-11-03 18:58:46271
Daniel Murphyd8a8ce92022-03-30 14:51:36272An action template with arguments that can take N * M * (...etc) values for all combinations of each argument type specified. The action names are the concatenations of the template name and the corresponding value name, separated by an underscore (`_`). For example, the `clear_app_badge` template generates the `clear_app_badge_SiteA` and `clear_app_badge_SiteB` actions. A three-argument action like `install_policy_app` may generate many actions, for example: `install_policy_app_SiteA_Windowed_NoShortcut`, `install_policy_app_SiteA_Windowed_Shortcut`, `install_policy_app_SiteA_Browser_NoShortcut`, etc
Daniel Murphy27a6bd02021-11-03 18:58:46273
Daniel Murphyd8a8ce92022-03-30 14:51:36274The templates also support [parameterizing](#parameterized-action) an action, which causes any test that uses the action to be expanded into multiple tests, one per specified output action. Arguments carry over into the output action by using bash-style string replacement of argument values. If an output action doesn't support a given argument value then that parameterization is simply excluded during test generation.
275
Daniel Murphy6ad32d62022-08-15 20:40:27276Similarly, the templates support specifying `ArgType::All` as an argument, signifying that the test can be expanded into multiple tests, one for each argument value. This is also supported in the parameterized actions field.
277
Daniel Murphyd8a8ce92022-03-30 14:51:36278To see any "skipped" parameterized output functions, please run the script with the `-v` option to see the log.
Daniel Murphy27a6bd02021-11-03 18:58:46279
280#### Default Values
281
Daniel Murphyd8a8ce92022-03-30 14:51:36282All argument types can mark one of their values as the default value by using a `*` character. This value is used if the test author does not specify one.
Daniel Murphy27a6bd02021-11-03 18:58:46283
Daniel Murphyd8a8ce92022-03-30 14:51:36284Note: Default values are not considered when resolving the output actions of parameterized actions.
285
286#### Specifying an Argument
Daniel Murphy27a6bd02021-11-03 18:58:46287Human-friendly action names are a slight variation of the canonical names above.
288
Daniel Murphyd8a8ce92022-03-30 14:51:36289Actions generated by argument-less templates have the same human-friendly name as their canonical name.
Daniel Murphy27a6bd02021-11-03 18:58:46290
Daniel Murphyd8a8ce92022-03-30 14:51:36291Actions generated by templates use parenthesis to separate the template name from the value name. For example, the actions generated by the `clear_app_badge` template have the human-friendly names `clear_app_badge(SiteA)` and `clear_app_badge(SiteB)`.
Daniel Murphy27a6bd02021-11-03 18:58:46292
293The template name can be used as the human-friendly name of the action generated by the template with the default value. For example, `clear_app_badge` is a shorter human-friendly name equivalent to `clear_app_badge(SiteA)`.
294
295### Test Creation & Specification
296
297[Tests][cuj-spreadsheet] are created specifying actions.
298
299For a step-by-step guide for creating a new integration test, see [this guide][how-to-create].
300
301#### Mindset
302The mindset for test creation and organization is to really exhaustively check every possible string of user actions. The framework will automatically combine tests that are the same except for state check actions. They are currently organized by:
3031. **Setup actions** - The state change actions needed to enter the system state that is being tested.
3042. **Primary state-change action/s** - Generally one action that will change the system state after the setup.
3053. **State check action** - One state check action, checking the state of the system after the previous actions have executed.
306
307Each test can have at most one [state check](#state-check-action) action as the last action.
308
309One way to enumerate tests is to think about **affected-by** action edges. These are a pair of two actions, where the first action affects the second. For example, the action `set_app_badge` will affect the action `check_app_badge_has_value`. Or, `uninstall_from_app_list` will affect `check_platform_shortcut_exists`. There is often then different setup states that would effect these actions. Once these edges are identified, tests can be created around them.
310
311#### Creating a test
312
313A test should be created that does the bare minimum necessary to set up the test before testing the primary state change action and then checking the state.
314
315The framework is designed to be able to collapse tests that contain common non-'state-check' actions, so adding a new test does not always mean that a whole new test will be run by the framework. Sometimes it only adds a few extra state-check actions in an existing test.
316
317If new actions are required for a test, see [How to create WebApp Integration Tests][how-to-create] for more information about how to add a new action.
318
319[design-doc]: https://docs.google.com/document/d/e/2PACX-1vTFI0sXhZMvvg1B3sctYVUe64WbLVNzuXFUa6f3XyYTzKs2JnuFR8qKNyXYZsxE-rPPvsq__4ZCyrcS/pub
Daniel Murphyfd7822a2022-04-11 18:39:29320[cuj-spreadsheet]: /chrome/test/webapps/data/critical_user_journeys.md
321[cuj-actions-sheet]: /chrome/test/webapps/data/actions.md
322[cuj-enums-sheet]: /chrome/test/webapps/data/enums.md
Daniel Murphy27a6bd02021-11-03 18:58:46323[cuj-coverage-sheet]: https://docs.google.com/spreadsheets/u/1/d/e/2PACX-1vSbO6VsnWsq_9MN6JEXlL8asMqATHc2-pz9ed_Jlf5zHJGg2KAtegsorHqkQ5kydU6VCqebv_1gUCD5/pubhtml?gid=884228058
324[how-to-create]: how-to-create-webapp-integration-tests.md
325[script-data-dir]: /chrome/test/webapps/data/
326[script-output-dir]: /chrome/test/webapps/output/
327[test-driver]: /chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h
328[default-tests]: /chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
329[default-tests-mwl]: /chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
330[default-tests-cros]: /chrome/browser/ui/views/web_apps/web_app_integration_browsertest_cros.cc
331[sync-tests-mwl]: /chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc
332[sync-tests-cros]: /chrome/browser/sync/test/integration/two_client_web_apps_integration_test_cros.cc
333[sync-tests-base]: /chrome/browser/sync/test/integration/two_client_web_apps_integration_test_base.h
334[sync-tests-dd]: https://docs.google.com/document/d/139ktCajbmbFKh4T-vEhipTxilyYrXf_rlCBHIvrdeSg/edit
335[generate-script]: /chrome/test/webapps/generate_framework_tests_and_coverage.py
336[coverage-win]: /chrome/test/webapps/coverage/coverage_win.tsv
337[framework-supported-actions]: /chrome/test/webapps/data/framework_supported_actions.csv
338[sync-test-base]: chrome/browser/sync/test/integration/sync_test.h
Daniel Murphy0ffd42c82022-07-22 22:12:25339[why-is-this-test-failing]: why-is-this-test-failing.md