summaryrefslogtreecommitdiffstats
path: root/remote/cdp/test/browser/input/browser_dispatchKeyEvent_race.js
diff options
context:
space:
mode:
Diffstat (limited to 'remote/cdp/test/browser/input/browser_dispatchKeyEvent_race.js')
-rw-r--r--remote/cdp/test/browser/input/browser_dispatchKeyEvent_race.js92
1 files changed, 92 insertions, 0 deletions
diff --git a/remote/cdp/test/browser/input/browser_dispatchKeyEvent_race.js b/remote/cdp/test/browser/input/browser_dispatchKeyEvent_race.js
new file mode 100644
index 0000000000..ee1cd5be39
--- /dev/null
+++ b/remote/cdp/test/browser/input/browser_dispatchKeyEvent_race.js
@@ -0,0 +1,92 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Here we test that the `dispatchKeyEvent` API resolves after all the synchronous event
+// handlers from the content page have been flushed.
+//
+// Say the content page has an event handler such as:
+//
+// el.addEventListener("keyup", () => {
+// doSomeVeryLongProcessing(); // <- takes a long time but is synchronous!
+// window.myVariable = "newValue";
+// });
+//
+// And imagine this is tested via:
+//
+// await Input.dispatchKeyEvent(...);
+// const myVariable = await Runtime.evaluate({ expression: "window.myVariable" });
+// equals(myVariable, "newValue");
+//
+// In order for this to work, we need to be sure that `await Input.dispatchKeyEvent`
+// resolves only after the content page flushed the event handlers (and
+// `window.myVariable = "newValue"` was executed).
+//
+// This can be racy because Input.dispatchKeyEvent and window.myVariable = "newValue" run
+// in different processes.
+
+const PAGE_URL =
+ "https://example.com/browser/remote/cdp/test/browser/input/doc_dispatchKeyEvent_race.html";
+
+add_task(async function ({ client }) {
+ await loadURL(PAGE_URL);
+
+ const { Input, Runtime } = client;
+
+ // Need an enabled Runtime domain to run evaluate.
+ info("Enable the Runtime domain");
+ await Runtime.enable();
+ const { context } = await Runtime.executionContextCreated();
+
+ info("Focus the input on the page");
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
+ const input = content.document.querySelector("input");
+ input.focus();
+ is(input, content.document.activeElement, "Input should be focused");
+ });
+
+ // See doc_input_dispatchKeyEvent_race.html
+ // The page listens to `input` events to update a property on window.
+ // We will check that the value is updated as soon dispatchKeyEvent has resolved.
+ await checkWindowTestValue("initial-value", context.id, Runtime);
+
+ info("Write 'hhhhhh' ('h' times 6)");
+ for (let i = 0; i < 6; i++) {
+ await dispatchKeyEvent(Input, "h", 72, "keyDown");
+ await dispatchKeyEvent(Input, "h", 72, "keyUp");
+ }
+ await checkWindowTestValue("hhhhhh", context.id, Runtime);
+
+ info("Write 'aaaaaa' with 6 consecutive keydown and one keyup");
+ await Promise.all([
+ dispatchKeyEvent(Input, "a", 65, "keyDown"),
+ dispatchKeyEvent(Input, "a", 65, "keyDown"),
+ dispatchKeyEvent(Input, "a", 65, "keyDown"),
+ dispatchKeyEvent(Input, "a", 65, "keyDown"),
+ dispatchKeyEvent(Input, "a", 65, "keyDown"),
+ dispatchKeyEvent(Input, "a", 65, "keyDown"),
+ ]);
+ await dispatchKeyEvent(Input, "a", 65, "keyUp");
+ await checkWindowTestValue("hhhhhhaaaaaa", context.id, Runtime);
+});
+
+function dispatchKeyEvent(Input, key, keyCode, type, modifiers = 0) {
+ info(`Send ${type} for key ${key}`);
+ return Input.dispatchKeyEvent({
+ type,
+ modifiers,
+ windowsVirtualKeyCode: keyCode,
+ key,
+ });
+}
+
+async function checkWindowTestValue(expected, contextId, Runtime) {
+ info("Retrieve the value of `window.testValue` in the test page");
+ const { result } = await Runtime.evaluate({
+ contextId,
+ expression: "window.testValue",
+ });
+
+ is(result.value, expected, "Content window test value is correct");
+}