commit 75ac0fc100a323d11461ecdb09ff7c06cadd846e
parent 73fb1081cd3c3cc70ea382ed36930e58260fba1a
Author: Julian Descottes <jdescottes@mozilla.com>
Date: Thu, 13 Nov 2025 14:52:00 +0000
Bug 1855045 - [bidi] Dismiss file picker prompts automatically r=Sasha
Differential Revision: https://phabricator.services.mozilla.com/D271792
Diffstat:
7 files changed, 135 insertions(+), 27 deletions(-)
diff --git a/remote/jar.mn b/remote/jar.mn
@@ -91,6 +91,7 @@ remote.jar:
content/shared/webdriver/Certificates.sys.mjs (shared/webdriver/Certificates.sys.mjs)
content/shared/webdriver/Errors.sys.mjs (shared/webdriver/Errors.sys.mjs)
content/shared/webdriver/Event.sys.mjs (shared/webdriver/Event.sys.mjs)
+ content/shared/webdriver/FilePickerHandler.sys.mjs (shared/webdriver/FilePickerHandler.sys.mjs)
content/shared/webdriver/KeyData.sys.mjs (shared/webdriver/KeyData.sys.mjs)
content/shared/webdriver/NodeCache.sys.mjs (shared/webdriver/NodeCache.sys.mjs)
content/shared/webdriver/Session.sys.mjs (shared/webdriver/Session.sys.mjs)
diff --git a/remote/shared/webdriver/FilePickerHandler.sys.mjs b/remote/shared/webdriver/FilePickerHandler.sys.mjs
@@ -0,0 +1,105 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const FILE_PICKER_HANDLER_CID = Services.uuid.generateUUID();
+const FILE_PICKER_CONTRACT_ID = "@mozilla.org/filepicker;1";
+
+/**
+ * The FilePickerHandler can override the default component factory for the file
+ * picker to prevent showing file pickers if needed.
+ */
+class FilePickerHandlerClass {
+ #callers;
+ #originalFilePickerCID;
+ #registrar;
+ #registeredFactory;
+
+ constructor() {
+ this.#registeredFactory = null;
+
+ this.#registrar = Components.manager.QueryInterface(
+ Ci.nsIComponentRegistrar
+ );
+ this.#originalFilePickerCID = this.#registrar.contractIDToCID(
+ FILE_PICKER_CONTRACT_ID
+ );
+
+ // Set to keep track of all callers which requested to handle file pickers.
+ this.#callers = new Set();
+ }
+
+ /**
+ * Stop requesting to dismiss all file pickers on behalf of the provided
+ * caller.
+ * Note that file pickers will only be displayed again once all callers
+ * called allowFilePickers.
+ *
+ * @param {object} caller
+ * A reference to identify the caller which requested to dismiss pickers.
+ */
+ allowFilePickers(caller) {
+ this.#callers.delete(caller);
+
+ if (this.#callers.size || !this.#registeredFactory) {
+ return;
+ }
+
+ // Unregister our proxy factory.
+ this.#registrar.unregisterFactory(
+ FILE_PICKER_HANDLER_CID,
+ this.#registeredFactory
+ );
+ this.#registeredFactory = null;
+
+ // Restore the original factory.
+ this.#registrar.registerFactory(
+ this.#originalFilePickerCID,
+ "",
+ FILE_PICKER_CONTRACT_ID,
+ null
+ );
+ }
+
+ /**
+ * Request to dismiss all file picker dialogs by registering a custom file
+ * picker factory instead of the default one.
+ *
+ * @param {object} caller
+ * A reference to identify the caller which requested to dismiss pickers.
+ */
+ dismissFilePickers(caller) {
+ this.#callers.add(caller);
+
+ if (this.#registeredFactory) {
+ return;
+ }
+
+ this.#registeredFactory = {
+ createInstance(iid) {
+ const filePickerProxy = {
+ init() {},
+ open: openCallback => {
+ openCallback.done(Ci.nsIFilePicker.returnCancel);
+ },
+ displayDirectory: null,
+ file: null,
+ QueryInterface: ChromeUtils.generateQI(["nsIFilePicker"]),
+ };
+ return filePickerProxy.QueryInterface(iid);
+ },
+ QueryInterface: ChromeUtils.generateQI(["nsIFactory"]),
+ };
+
+ this.#registrar.registerFactory(
+ FILE_PICKER_HANDLER_CID,
+ "WebDriver FilePicker handler",
+ FILE_PICKER_CONTRACT_ID,
+ this.#registeredFactory
+ );
+ }
+}
+
+// Expose a singleton shared by all WebDriver sessions.
+// The FilePickerHandler factory should only be registered once at most.
+export const FilePickerHandler = new FilePickerHandlerClass();
diff --git a/remote/shared/webdriver/Session.sys.mjs b/remote/shared/webdriver/Session.sys.mjs
@@ -14,6 +14,8 @@ ChromeUtils.defineESModuleGetters(lazy, {
Capabilities: "chrome://remote/content/shared/webdriver/Capabilities.sys.mjs",
Certificates: "chrome://remote/content/shared/webdriver/Certificates.sys.mjs",
error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
+ FilePickerHandler:
+ "chrome://remote/content/shared/webdriver/FilePickerHandler.sys.mjs",
generateUUID: "chrome://remote/content/shared/UUID.sys.mjs",
Log: "chrome://remote/content/shared/Log.sys.mjs",
NavigableManager: "chrome://remote/content/shared/NavigableManager.sys.mjs",
@@ -284,6 +286,11 @@ export class WebDriverSession {
// Start the tracking of browsing contexts to create Navigable ids.
lazy.NavigableManager.startTracking();
+ // Temporarily dismiss all file pickers.
+ // Bug 1999693: File pickers should only be dismissed when the unhandled
+ // prompt behaviour for type "file" is not set to "ignore".
+ lazy.FilePickerHandler.dismissFilePickers(this);
+
webDriverSessions.set(this.#id, this);
}
@@ -294,6 +301,8 @@ export class WebDriverSession {
// session exists anymore.
lazy.NavigableManager.stopTracking();
+ lazy.FilePickerHandler.allowFilePickers(this);
+
lazy.unregisterProcessDataActor();
this.#navigableSeenNodes = null;
diff --git a/testing/web-platform/meta/webdriver/tests/bidi/input/file_dialog_opened/file_dialog_opened.py.ini b/testing/web-platform/meta/webdriver/tests/bidi/input/file_dialog_opened/file_dialog_opened.py.ini
@@ -1,20 +0,0 @@
-[file_dialog_opened.py]
- [test_unsubscribe]
- bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1855045
- expected: FAIL
-
- [test_subscribe]
- bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1855045
- expected: FAIL
-
- [test_multiple[True\]]
- bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1855045
- expected: FAIL
-
- [test_multiple[False\]]
- bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1855045
- expected: FAIL
-
- [test_element]
- bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1855045
- expected: FAIL
diff --git a/testing/web-platform/meta/webdriver/tests/bidi/session/capabilities/unhandled_prompt_behavior/file/accept.py.ini b/testing/web-platform/meta/webdriver/tests/bidi/session/capabilities/unhandled_prompt_behavior/file/accept.py.ini
@@ -1,4 +1,4 @@
[accept.py]
- disabled:
- bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1855045
-
+ [test_file_accept]
+ bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1999693
+ expected: ERROR
diff --git a/testing/web-platform/meta/webdriver/tests/bidi/session/capabilities/unhandled_prompt_behavior/file/dismiss.py.ini b/testing/web-platform/meta/webdriver/tests/bidi/session/capabilities/unhandled_prompt_behavior/file/dismiss.py.ini
@@ -1,3 +1,4 @@
[dismiss.py]
- disabled:
- bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1855045
+ [test_file_dismiss]
+ bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1999693
+ expected: ERROR
diff --git a/testing/web-platform/meta/webdriver/tests/bidi/session/capabilities/unhandled_prompt_behavior/file/ignore.py.ini b/testing/web-platform/meta/webdriver/tests/bidi/session/capabilities/unhandled_prompt_behavior/file/ignore.py.ini
@@ -1,4 +1,16 @@
[ignore.py]
- disabled:
- bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1855045
+ [test_no_capabilities]
+ bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1999693
+ expected: FAIL
+ [test_string_ignore]
+ bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1999693
+ expected: FAIL
+
+ [test_default_ignore]
+ bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1999693
+ expected: FAIL
+
+ [test_file_ignore]
+ bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1999693
+ expected: ERROR