|
| 1 | +# RFC 86: Add `fetch_tests_from_prefixed_local_storage` method |
| 2 | + |
| 3 | +## Summary |
| 4 | + |
| 5 | +Add `fetch_tests_from_prefixed_local_storage` method that fetches test results from another page via local storage and `/common/PrefixedLocalStorage.js`. |
| 6 | +This is similar to `fetch_tests_from_window`, but is designed for cases where direct communication channels including `postMessage` are not available, like a `Window` opened by `window.open(url, "noopener")`. |
| 7 | + |
| 8 | +This is primarily for the use in [Back-foward cache WPTs](https://github.com/web-platform-tests/wpt/pull/28950), but can be also used for other tests involving isolated Windows or top-level navigations. |
| 9 | + |
| 10 | +## Details |
| 11 | + |
| 12 | +Testing things requiring isolated windows is not well supported by the WPT frameworks. |
| 13 | +For example, when `A.html` calls `window.open('B.html', 'noopener')` and tests something on `B.html`, `B.html` sends data to `A.html` and `A.html` calls `testharness.js` APIs like `assert_equals()` on the data, like: |
| 14 | + |
| 15 | +A.html: |
| 16 | +``` |
| 17 | +async_test(t => { |
| 18 | + window.open(prefixedLocalStorage.url('B.html'), '_blank', 'noopener'); |
| 19 | + wait_for_result(); |
| 20 | + assert_equals(localStorage.getItem('result'), 'expected'); |
| 21 | +}); |
| 22 | +``` |
| 23 | + |
| 24 | +B.html: |
| 25 | +``` |
| 26 | +localStorage.setItem('result', doSomethingAndGetResult()); |
| 27 | +``` |
| 28 | + |
| 29 | +The problems here are: |
| 30 | + |
| 31 | +- Test logic often spreads across multiple HTMLs, which can make the logic and its failure mode unclear. |
| 32 | +- we need non-`postMessage` communication mechanisms (which tend to be one-off; see below for existing examples). |
| 33 | + |
| 34 | +Instead, this RFC proposes |
| 35 | + |
| 36 | +- Writing tests using `testharness.js` APIs on isolated Windows (`B.html` in the example above), and |
| 37 | +- Communicating test results within a new API `fetch_tests_from_prefixed_local_storage` in `testharness.js` from the isolated Windows to the main test Window (`A.html` in the example). |
| 38 | + |
| 39 | +A.html: |
| 40 | +``` |
| 41 | +const prefixedLocalStorage = new PrefixedLocalStorageTest(); |
| 42 | +fetch_tests_from_prefixed_local_storage(prefixedLocalStorage); |
| 43 | +window.open(prefixedLocalStorage.url('B.html'), '_blank', 'noopener'); |
| 44 | +``` |
| 45 | + |
| 46 | +B.html: |
| 47 | +``` |
| 48 | +async_test(t => { |
| 49 | + assert_equals(doSomethingAndGetResult(), 'expected'); |
| 50 | +}); |
| 51 | +``` |
| 52 | + |
| 53 | +By doing so, |
| 54 | + |
| 55 | +- More test logic can be centralized to `B.html`, especially when the most of the test logic can be done in `B.html` and `window.open() + noopener` is needed just to create a separate browsing context (this is the case for most of the BFCache tests). |
| 56 | +- Communication implementation is encapsulated within `testharness.js`, instead of within individual tests. |
| 57 | + |
| 58 | +## Risks |
| 59 | + |
| 60 | +We might want to change the implementations within `fetch_tests_from_prefixed_local_storage`, when |
| 61 | + |
| 62 | +* More use cases are to be supported (like cross-origin Windows) |
| 63 | +* `localStorage` spec or implementation is changed |
| 64 | + |
| 65 | +This kind of risks is somehow inherent regardless of communication methods we use, because we anyway want communications between isolated Windows, which might be blocked by security/privacy efforts. |
| 66 | + |
| 67 | +Changes needed will be anyway small, because I expect |
| 68 | + |
| 69 | +* We only have to change the implementation within `fetch_tests_from_prefixed_local_storage` and boilerplate-like code on its caller side, (hopefully) not the test contents, given that the APIs supported in the test contents are stable `testharness.js` APIs. |
| 70 | +* The number of tests using `fetch_tests_from_prefixed_local_storage` will be limited. |
| 71 | + |
| 72 | +## Existing communication helpers |
| 73 | + |
| 74 | +Existing tests (WPT or Chromium, mainly those with `window.open()` + `noopener`) uses several communication mechanisms/helpers for this purpose. |
| 75 | + |
| 76 | +- localStorage |
| 77 | + - [/wpt/common/PrefixedLocalStorage.js](https://github.com/web-platform-tests/wpt/blob/master/common/PrefixedLocalStorage.js) |
| 78 | + - e.g. used by [/wpt/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener.html](https://github.com/web-platform-tests/wpt/blob/master/html/browsers/windows/auxiliary-browsing-contexts/opener-noopener.html) |
| 79 | +- sessionStorage |
| 80 | + - [http/tests/navigation/resources/back-to-get-after-post-helper.html](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/web_tests/http/tests/navigation/resources/back-to-get-after-post-helper.html) |
| 81 | +- Fetch API + server-side stash |
| 82 | + - [/wpt/scroll-to-text-fragment/stash.js](https://github.com/web-platform-tests/wpt/blob/master/scroll-to-text-fragment/stash.js) |
| 83 | + - [/wpt/html/browsers/windows/resources/window-name-stash.py](https://github.com/web-platform-tests/wpt/blob/master/html/browsers/windows/resources/window-name-stash.py) |
| 84 | + - [/wpt_internal/prerender/resources/key-value-store.py](third_party/blink/web_tests/wpt_internal/prerender/resources/key-value-store.py) |
| 85 | + |
| 86 | +## Alternatives Considered |
| 87 | + |
| 88 | +### Fetch API + server-side stash instead of `localStorage` |
| 89 | + |
| 90 | +- pros: More robust than `localStorage`: Fetch API will be less affected by efforts to block communications between windows, and works even in cross-origin cases. |
| 91 | +- cons: Fetch API is async, and pages with open fetch requests are not BFCache-eligible in Chromium. Therefore, a little more coordination is needed to ensure the fetch requests for accessing stash are closed before navigation. |
| 92 | + |
| 93 | +### BroadcastChannel instead of `localStorage` |
| 94 | + |
| 95 | +- cons: Pages with open BroadcastChannels is not BFCache-eligible in Chromium. |
| 96 | +- cons: BroadcastChannel is not supported in Safari. |
| 97 | + |
| 98 | +### Introduce a new class of tests that drive the browser from the outside |
| 99 | + |
| 100 | +Instead of writing tests and passing data within JavaScript, introduce a new class of tests and its infrastructure controling the browser "from the outside", much more like WebDriver tests. |
| 101 | + |
| 102 | +- cons: Design and implementation costs are much higher. |
| 103 | +- It would be preferable to create a design that covers a broader use cases like navigation, BFCache, prerendering, etc., but right now I don't have clear ideas (both on design/implementation and use cases). |
0 commit comments