summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/fenced-frame/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/fenced-frame/README.md')
-rw-r--r--testing/web-platform/tests/fenced-frame/README.md217
1 files changed, 217 insertions, 0 deletions
diff --git a/testing/web-platform/tests/fenced-frame/README.md b/testing/web-platform/tests/fenced-frame/README.md
new file mode 100644
index 0000000000..6055d17e97
--- /dev/null
+++ b/testing/web-platform/tests/fenced-frame/README.md
@@ -0,0 +1,217 @@
+# Fenced Frames
+
+This directory contains [Web Platform
+Tests](third_party/blink/web_tests/external/wpt) for the [Fenced
+Frames](https://github.com/shivanigithub/fenced-frame) feature.
+
+These tests are generally intended to be upstreamed to the Web Platform Tests
+repository (i.e., moved from `wpt_internal/fenced_frame/` to `external/wpt/`).
+There are a few reasons why we're holding off doing that right now, see [Fenced
+Frames Testing Plan > Web Platform Tests](https://docs.google.com/document/d/1A4Dkw8PesXSqmRLy2Xa-KxpXgIZUT4rPocbxMBuP_3E/edit#heading=h.3plnzof3mgvv).
+
+In general, these tests should follow Chromium's [web tests
+guidelines](docs/testing/web_tests_tips.md) and [web-platform-tests
+guidelines](/docs/testing/web_platform_tests.md). This document describes
+how to use the specific fenced frame testing infrastructure.
+
+## How to run tests
+Fenced frames feature needs to be enabled to run tests. A convenient way to
+do this is to define the following variables for fenced frames [virtual test
+suites](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/web_tests.md#virtual-test-suites)
+directories.
+```bash
+# Fenced frame MPArch implementation
+export MPTEST=virtual/fenced-frame-mparch/wpt_internal/fenced_frame
+# Fenced frame ShadowDOM implementation
+export SDTEST=virtual/fenced-frame-shadow-dom/wpt_internal/fenced_frame
+```
+
+Then run tests under the virtual test suite. This will include necessary
+fenced frame flags.
+```bash
+third_party/blink/tools/run_web_tests.py -t Default $MPTEST/test-name.https.html
+```
+
+## How to write tests
+
+The `<fencedframe>` element has a strict requirement that it cannot directly
+communicate with or reach its embedder document. The fenced frame does have
+network access however, so we can use a server as a middleman to communicate
+with the outer page. There are two main test patterns we use: remote execution
+(recommended) and message passing (deprecated).
+
+### Remote execution
+
+Remote execution uses the helper `attachFencedFrameContext()` defined in
+[resources/utils.js](resources/utils.js), which requires
+[/common/dispatcher/dispatcher.js](/common/dispatcher/dispatcher.js) and
+[/common/utils.js](/common/utils.js). This returns a fenced frame that is
+wrapped with additional functionality from RemoteContext, which allows you to
+perform a remote procedure call into the frame using the function
+`execute(function, [arguments]=[])`.
+
+This interface allows us to write an entire test in only one file, with minimal
+boilerplate and an obvious control flow between all the frames on the page
+(including nested fenced frames, which can be achieved with nested `execute`
+calls).
+
+Let's see an example of communication between the top-level frame and the fenced
+frame.
+
+```js
+promise_test(async () => {
+ const important_value = "Hello";
+
+ // First, create an empty fenced frame.
+ const frame = attachFencedFrameContext();
+
+ // Next, make a function call into the frame, passing a particular string
+ // "Hello" as an argument. Make sure to `await` the call.
+ const response = await frame.execute((message_from_embedder) => {
+
+ // This code runs inside the fenced frame.
+ if (message_from_embedder == "Hello") {
+ // Message that we received was expected.
+ return "Hello to you too");
+ } else {
+ // Message that we received was *not* expected, let's report an error to
+ // the outer page so it fails the test.
+ return "Unexpected message";
+ }
+
+ }, [important_value]);
+
+ // Assert that the returned value was what we expected.
+ // Keep in mind that in a less contrived example, you can perform this assert
+ // inside the fenced frame.
+ assert_equals(response, "Hello to you too",
+ "The fenced frame received the message, and said hello back to us".)
+}, "Fenced frame and receive and send a greeting");
+```
+
+For test examples, see
+[document-referrer.https.html](document-referrer.https.html),
+[hid.https.html](hid.https.html),
+or [web-usb.https.html](web-usb.https.html).
+
+Some tips to keep in mind while writing tests using remote execution:
+* The functions `attachFencedFrameContext()` and `attachIFrameContext()`
+ optionally take a dictionary of configs as an argument. You can use it to
+ pass:
+ * The API you want to use to generate the fenced frame urn. Either `'fledge'`,
+ `'sharedstorage'`, or default (case-insensitive). When you use this option,
+ the return value becomes a promise so you **must** await it.For example:
+ ```
+ await attachFencedFrameContext({generator_api: 'fledge'});
+ ```
+ * HTML source code to inject into the frame's DOM tree. For example:
+ ```
+ attachFencedFrameContext({html: '<button id="Button">Click me!</button>'});
+ ```
+ * Response headers. For example:
+ ```
+ attachFencedFrameContext({headers: [["Content-Security-Policy", "frame-src 'self'"]]});
+ ```
+ * Attributes to set on the frame. For example:
+ ```
+ attachIFrameContext({attributes: [["csp", "frame-src 'self'"]]})
+ ```
+ * Origin of the url to allow cross-origin test. For example:
+ ```
+ attachIFrameContext({origin:get_host_info().HTTPS_REMOTE_ORIGIN})
+ ```
+* There is also a helper `attachIFrameContext()`, which does the same thing
+ but for iframes instead of fencedframes.
+* There is also a helper `replaceFrameContext(frame, {options})` which will
+ replace an existing frame context using the same underlying element (i.e., you
+ can use it to test when happens when you navigate an existing frame).
+* Make sure to `await` the result of an `execute` call, even if it doesn't
+ return anything.
+* In order to save a global variable, you need to explicitly assign to
+ `window.variable_name`. Assigning to `variable_name` without declaring it
+ will not persist across `execute` calls. This is especially important for
+ tests with nested frames, if you want to keep a handle to the nested frame
+ across multiple calls.
+* Remember to declare the function passed to `execute` as async if it itself
+ needs to invoke any async functions, including to create nested frames.
+
+### Message passing (deprecated)
+
+Message passing is done by using the helpers
+defined in
+[resources/utils.js](third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js)
+to send a message to the server, and poll the server for a response. All
+messages have a unique key associated with them so that documents that want to
+receive messages can poll the server for a given message that can be identified
+by a unique key.
+
+Let's see an example of sending a message to the server that a fenced frame will
+receive and respond to.
+
+**outer-page.js:**
+```js
+promise_test(async () => {
+ const important_message_key = token();
+ const fenced_frame_ack_key = token();
+ const important_value = "Hello";
+
+ // First, let's embed a new fenced frame in our test, and pass the key we
+ // just created into it as a parameter.
+ const frame_url = generateURL("resources/page-inner.html",
+ [important_message_key, fenced_frame_ack_key]);
+ attachFencedFrame(frame_url);
+
+ // Then, let's send the message over to the fenced frame.
+ writeValueToServer(important_message_key, important_value);
+
+ // Now that the message has been sent to the fenced frame, let's wait for its
+ // ACK, so that we don't exit the test before the fenced frame gets the
+ // message.
+ const response_from_fenced_frame = await
+ nextValueFromServer(fenced_frame_ack_key);
+ assert_equals(response_from_fenced_frame, "Hello to you too",
+ "The fenced frame received the message, and said hello back to us");
+}, "Fenced frame and receive and send a greeting");
+```
+
+**inner-fenced-frame.js:**
+
+```js
+async function init() { // Needed in order to use top-level await.
+ const [important_message_key, fenced_frame_ack_key] = parseKeylist();
+ const greeting_from_embedder = await nextValueFromServer(important_message_key);
+
+ if (greeting_from_embedder == "Hello") {
+ // Message that we received was expected.
+ writeValueToServer(fenced_frame_ack_key, "Hello to you too");
+ } else {
+ // Message that we received was *not* expected, let's report an error to the
+ // outer page so it fails the test.
+ writeValueToServer(fenced_frame_ack_key, "Unexpected message");
+ }
+}
+
+init();
+```
+
+When you write a new web platform test, it will likely involve passing a _new_
+message like the messages above, to and from the fenced frame. Keep in mind
+that you may have to use a _pair_ of keys, so that when one document writes a
+message associated with one unique key, it can listen for an ACK from the
+receiving document, so that it doesn't write over the message again before the
+receiving document actually reads it. **No two tests should ever use the same
+key to communicate information to and from a fenced frame**, as this will cause
+server-side race conditions.
+
+For a good test example, see
+[window-parent.html](window-parent.html).
+
+## Underlying implementations
+
+This directory contains <fencedframe> tests that exercise the
+`blink::features::kFencedFrames` feature.
+
+## Wrap lines at 80 columns
+
+This is the convention for most Chromium/WPT style tests. Note that
+`git cl format [--js]` does not reformat js code in .html files.