Bug 2000801 - [wdspec] Add Mozilla-specific tests for chrome window handles. r=frontend-codestyle-reviewers,jdescottes,mossop
Differential Revision: https://phabricator.services.mozilla.com/D273541
This commit is contained in:
committed by
hskupin@mozilla.com
parent
bac2666086
commit
6e586279cd
+3
-1
@@ -102,5 +102,7 @@ toolkit/components/pdfjs/content/web/viewer.css
|
||||
toolkit/components/pdfjs/content/web/viewer-geckoview.css
|
||||
build/pgo/blueprint/**/*.css
|
||||
|
||||
# Ignore web-platform tests as they are not necessarily under our control.
|
||||
# Ignore web-platform tests as they are not necessarily
|
||||
# under our control or we don't want to modify at this point:
|
||||
testing/web-platform/mozilla/
|
||||
testing/web-platform/tests/
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[chrome.py]
|
||||
disabled:
|
||||
if os == "android": https://bugzilla.mozilla.org/show_bug.cgi?id=1762066
|
||||
@@ -0,0 +1,3 @@
|
||||
[chrome.py]
|
||||
disabled:
|
||||
if os == "android": https://bugzilla.mozilla.org/show_bug.cgi?id=1762066
|
||||
@@ -0,0 +1,35 @@
|
||||
import pytest
|
||||
from support.context import using_context
|
||||
from tests.classic.execute_async_script import execute_async_script
|
||||
from tests.support.asserts import assert_success
|
||||
from webdriver.client import WebFrame, WebWindow
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expression, expected_type",
|
||||
[
|
||||
("window.frames[0]", WebFrame),
|
||||
("window", WebWindow),
|
||||
],
|
||||
ids=["frame", "window"],
|
||||
)
|
||||
@pytest.mark.allow_system_access
|
||||
def test_web_reference(
|
||||
session, expression, default_chrome_handler, new_chrome_window, expected_type
|
||||
):
|
||||
chrome_url = f"{default_chrome_handler}test.xhtml"
|
||||
new_window = new_chrome_window(chrome_url)
|
||||
|
||||
with using_context(session, "chrome"):
|
||||
session.window_handle = new_window.id
|
||||
assert session.url == chrome_url
|
||||
|
||||
result = execute_async_script(session, f"arguments[0]({expression})")
|
||||
reference = assert_success(result)
|
||||
|
||||
assert isinstance(reference, expected_type)
|
||||
|
||||
if isinstance(reference, WebWindow):
|
||||
assert reference.id in session.handles
|
||||
else:
|
||||
assert reference.id not in session.handles
|
||||
+1
-10
@@ -1,19 +1,10 @@
|
||||
import pytest
|
||||
from tests.classic.execute_async_script import execute_async_script
|
||||
from tests.support.asserts import assert_success
|
||||
from tests.support.sync import Poll
|
||||
from webdriver.error import NoSuchAlertException
|
||||
|
||||
|
||||
def execute_async_script(session, script, args=None):
|
||||
if args is None:
|
||||
args = []
|
||||
body = {"script": script, "args": args}
|
||||
|
||||
return session.transport.send(
|
||||
"POST", "/session/{session_id}/execute/async".format(**vars(session)), body
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
|
||||
def test_no_abort_by_user_prompt_in_other_tab(session, inline, dialog_type):
|
||||
original_handle = session.window_handle
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import pytest
|
||||
from support.context import using_context
|
||||
from tests.classic.execute_script import execute_script
|
||||
from tests.support.asserts import assert_success
|
||||
from webdriver.client import WebFrame, WebWindow
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expression, expected_type",
|
||||
[
|
||||
("window.frames[0]", WebFrame),
|
||||
("window", WebWindow),
|
||||
],
|
||||
ids=["frame", "window"],
|
||||
)
|
||||
@pytest.mark.allow_system_access
|
||||
def test_web_reference(
|
||||
session, expression, default_chrome_handler, new_chrome_window, expected_type
|
||||
):
|
||||
chrome_url = f"{default_chrome_handler}test.xhtml"
|
||||
new_window = new_chrome_window(chrome_url)
|
||||
|
||||
with using_context(session, "chrome"):
|
||||
session.window_handle = new_window.id
|
||||
assert session.url == chrome_url
|
||||
|
||||
result = execute_script(session, f"return {expression}")
|
||||
reference = assert_success(result)
|
||||
|
||||
assert isinstance(reference, expected_type)
|
||||
|
||||
if isinstance(reference, WebWindow):
|
||||
assert reference.id in session.handles
|
||||
else:
|
||||
assert reference.id not in session.handles
|
||||
@@ -0,0 +1,6 @@
|
||||
def switch_to_window(session, handle):
|
||||
return session.transport.send(
|
||||
"POST",
|
||||
"session/{session_id}/window".format(**vars(session)),
|
||||
{"handle": handle},
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
import pytest
|
||||
from support.context import using_context
|
||||
from tests.support.asserts import assert_error, assert_success
|
||||
|
||||
from . import switch_to_window
|
||||
|
||||
|
||||
@pytest.mark.allow_system_access
|
||||
def test_no_such_window(session):
|
||||
with using_context(session, "chrome"):
|
||||
response = switch_to_window(session, "foo")
|
||||
assert_error(response, "no such window")
|
||||
|
||||
|
||||
@pytest.mark.allow_system_access
|
||||
def test_chrome_window(session):
|
||||
session.new_window(type_hint="window")
|
||||
|
||||
with using_context(session, "chrome"):
|
||||
current_handle = session.window_handle
|
||||
chrome_handles = session.handles
|
||||
|
||||
chrome_handles.remove(current_handle)
|
||||
|
||||
assert len(chrome_handles)
|
||||
|
||||
response = switch_to_window(session, chrome_handles[0])
|
||||
assert_success(response)
|
||||
|
||||
assert session.window_handle == chrome_handles[0]
|
||||
assert session.window_handle != current_handle
|
||||
@@ -0,0 +1,13 @@
|
||||
.flex-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.dialog-box {
|
||||
min-height: 500px;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.input-moz-box-flex {
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?csp default-src chrome:; ?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<!-- Test file for a XUL window by using a XHTML document instead. -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="remote-window"
|
||||
windowtype="remote:xhtml"
|
||||
>
|
||||
<head>
|
||||
<title>Test Window</title>
|
||||
<link rel="stylesheet" href="chrome://global/skin/global.css" />
|
||||
<link rel="stylesheet" href="chrome://marionette-chrome/content/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="types" class="flex-column">
|
||||
<input id="textInput" size="6" value="test" label="input" />
|
||||
<input type="checkbox" id="testBox" label="box" />
|
||||
<button id="button" class="foo" label="button" />
|
||||
<button id="options-button" label="options" />
|
||||
</div>
|
||||
|
||||
<div id="frames" class="flex-column">
|
||||
<iframe
|
||||
id="iframe"
|
||||
src="chrome://marionette-chrome/content/test_iframe.xhtml"
|
||||
/>
|
||||
<iframe
|
||||
id="iframe-nested"
|
||||
src="chrome://marionette-chrome/content/test_nested_iframe.xhtml"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<!-- 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/. -->
|
||||
|
||||
<!ENTITY testDialog.title "Test Dialog">
|
||||
|
||||
<!ENTITY settings.label "Settings">
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
# 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/.
|
||||
|
||||
testDialog.title=Test Dialog
|
||||
|
||||
settings.label=Settings
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0"?>
|
||||
<?csp default-src chrome:; ?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<!-- Test file for a XUL dialog. -->
|
||||
|
||||
<!DOCTYPE testdialog [ <!ENTITY % dialogDTD SYSTEM "chrome://marionette-chrome/content/test_dialog.dtd">
|
||||
%dialogDTD; ]>
|
||||
|
||||
<window
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
title="&testDialog.title;"
|
||||
>
|
||||
<html:link rel="stylesheet" href="chrome://global/skin/global.css" />
|
||||
<html:link rel="stylesheet" href="chrome://marionette-chrome/content/style.css" />
|
||||
|
||||
<dialog id="testDialog" buttons="accept,cancel">
|
||||
<vbox flex="1" class="dialog-box">
|
||||
<label>&settings.label;</label>
|
||||
<separator class="thin" />
|
||||
<richlistbox id="test-list" flex="1">
|
||||
<richlistitem id="item-choose" orient="horizontal" selected="true">
|
||||
<label id="choose-label" value="First Entry" flex="1" />
|
||||
<button id="choose-button" label="Choose..." />
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
<separator class="thin" />
|
||||
<checkbox id="check-box" label="Test Mode 2" />
|
||||
<hbox align="center">
|
||||
<label id="text-box-label" control="text-box">Name:</label>
|
||||
<input
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="text-box"
|
||||
class="input-moz-box-flex"
|
||||
/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</dialog>
|
||||
</window>
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?csp default-src 'none' ?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="remote-test-iframe"
|
||||
windowtype="remote:test-xhtml"
|
||||
>
|
||||
<head>
|
||||
<title>iframe</title>
|
||||
<link rel="stylesheet" href="chrome://global/skin/global.css" />
|
||||
<link rel="stylesheet" href="chrome://marionette-chrome/content/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="types" class="flex-column">
|
||||
<input id="textInput" size="6" value="test" label="input" />
|
||||
<input type="checkbox" id="testBox" label="box" />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?csp default-src chrome:; ?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="remote-test-nested-iframe"
|
||||
windowtype="remote:test-xhtml"
|
||||
>
|
||||
<head>
|
||||
<title>nested iframe</title>
|
||||
<link rel="stylesheet" href="chrome://global/skin/global.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<iframe
|
||||
id="iframe"
|
||||
src="chrome://marionette-chrome/content/test_iframe.xhtml"
|
||||
/>
|
||||
</body>
|
||||
</html>
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0"?>
|
||||
<?csp default-src chrome:; ?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<!-- Test file for a XUL window. -->
|
||||
|
||||
<window
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
id="remote-window"
|
||||
title="Test Window"
|
||||
windowtype="remote:xul"
|
||||
>
|
||||
<linkset>
|
||||
<html:link rel="stylesheet" href="chrome://global/skin/global.css" />
|
||||
</linkset>
|
||||
|
||||
<popupset id="options-popupset">
|
||||
<menupopup id="options-menupopup" position="before_end">
|
||||
<menuitem id="option-enabled" type="checkbox" label="enabled" />
|
||||
<menuitem
|
||||
id="option-hidden"
|
||||
type="checkbox"
|
||||
label="hidden"
|
||||
hidden="true"
|
||||
/>
|
||||
<menuitem
|
||||
id="option-disabled"
|
||||
type="checkbox"
|
||||
label="disabled"
|
||||
disabled="true"
|
||||
/>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
<vbox id="types">
|
||||
<html:input id="textInput" size="6" value="test" label="input" />
|
||||
<checkbox id="testBox" label="box" />
|
||||
<button id="button" class="foo" label="button" />
|
||||
<button id="options-button" popup="options-menupopup" label="options" />
|
||||
</vbox>
|
||||
|
||||
<vbox id="frames">
|
||||
<html:iframe
|
||||
id="iframe"
|
||||
src="chrome://marionette-chrome/content/test_iframe.xhtml"
|
||||
/>
|
||||
<html:iframe
|
||||
id="iframe-nested"
|
||||
src="chrome://marionette-chrome/content/test_nested_iframe.xhtml"
|
||||
/>
|
||||
</vbox>
|
||||
</window>
|
||||
@@ -0,0 +1,65 @@
|
||||
import contextlib
|
||||
|
||||
from support.context import using_context
|
||||
|
||||
|
||||
def register_chrome_handler(session, manifest_path, entries):
|
||||
with using_context(session, "chrome"):
|
||||
return session.execute_script(
|
||||
"""
|
||||
const { FileUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/FileUtils.sys.mjs"
|
||||
);
|
||||
|
||||
const [manifestPath, entries] = arguments;
|
||||
|
||||
const manifest = new FileUtils.File(manifestPath);
|
||||
const rootURI = Services.io.newFileURI(manifest.parent);
|
||||
const manifestURI = Services.io.newURI(manifest.leafName, null, rootURI);
|
||||
|
||||
const handle = Cc["@mozilla.org/addons/addon-manager-startup;1"]
|
||||
.getService(Ci.amIAddonManagerStartup)
|
||||
.registerChrome(manifestURI, entries);
|
||||
const id = Services.uuid.generateUUID().toString().slice(1, -1);
|
||||
|
||||
if (globalThis.chromeProtocolHandles) {
|
||||
globalThis.chromeProtocolHandles.set(id, handle);
|
||||
}
|
||||
|
||||
return id;
|
||||
|
||||
""",
|
||||
args=[manifest_path, entries],
|
||||
)
|
||||
|
||||
|
||||
def unregister_chrome_handler(session, id):
|
||||
with using_context(session, "chrome"):
|
||||
return session.execute_script(
|
||||
"""
|
||||
const [id] = arguments;
|
||||
|
||||
if (globalThis.chromeProtocolHandles) {
|
||||
if (!globalThis.chromeProtocolHandles.has(id)) {
|
||||
throw new Error(
|
||||
`Id ${id} is not a known chrome protocol handler`
|
||||
);
|
||||
}
|
||||
|
||||
const handle = globalThis.chromeProtocolHandles.get(id);
|
||||
globalThis.chromeProtocolHandles.delete(id);
|
||||
handle.destruct();
|
||||
}
|
||||
""",
|
||||
args=[id],
|
||||
)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def using_chrome_handler(session, manifest_path, entries):
|
||||
id = register_chrome_handler(session, manifest_path, entries)
|
||||
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
unregister_chrome_handler(session, id)
|
||||
@@ -1,7 +1,11 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from tests.support.helpers import deep_update
|
||||
|
||||
from .chrome_handler import using_chrome_handler
|
||||
from .context import using_context
|
||||
from .helpers import (
|
||||
Browser,
|
||||
Geckodriver,
|
||||
@@ -137,11 +141,94 @@ def default_capabilities(request):
|
||||
return capabilities
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def default_chrome_handler(current_session):
|
||||
manifest_path = os.path.join(
|
||||
os.path.abspath(os.path.dirname(__file__)), "chrome-assets", "chrome.manifest"
|
||||
)
|
||||
entries = [["content", "marionette-chrome", "chrome/"]]
|
||||
|
||||
with using_chrome_handler(current_session, manifest_path, entries):
|
||||
yield "chrome://marionette-chrome/content/"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def default_preferences(profile_folder):
|
||||
return read_user_preferences(profile_folder)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def new_chrome_window(current_session):
|
||||
opened_chrome_windows = []
|
||||
|
||||
def _new_chrome_window(url, focus=True):
|
||||
# Bug 1944570: Replace with BiDi once scripts can be evaluated
|
||||
# in the parent process.
|
||||
with using_context(current_session, "chrome"):
|
||||
new_window = current_session.execute_async_script(
|
||||
"""
|
||||
const { NavigableManager } = ChromeUtils.importESModule(
|
||||
"chrome://remote/content/shared/NavigableManager.sys.mjs"
|
||||
);
|
||||
|
||||
let [url, focus, resolve] = arguments;
|
||||
|
||||
function waitForEvent(target, type, args) {
|
||||
return new Promise(resolve => {
|
||||
let params = Object.assign({once: true}, args);
|
||||
target.addEventListener(type, event => {
|
||||
dump(`** Received DOM event ${event.type} for ${event.target}\n`);
|
||||
resolve();
|
||||
}, params);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForFocus(win) {
|
||||
return Promise.all([
|
||||
waitForEvent(win, "activate"),
|
||||
waitForEvent(win, "focus", {capture: true}),
|
||||
]);
|
||||
}
|
||||
|
||||
(async function() {
|
||||
// Open a window, wait for it to receive focus
|
||||
let win = window.openDialog(url, null, "chrome,centerscreen");
|
||||
let focused = waitForFocus(win);
|
||||
|
||||
win.focus();
|
||||
await focused;
|
||||
|
||||
// The new window shouldn't get focused. As such set the
|
||||
// focus back to the opening window.
|
||||
if (!focus && Services.focus.activeWindow != window) {
|
||||
let focused = waitForFocus(window);
|
||||
window.focus();
|
||||
await focused;
|
||||
}
|
||||
|
||||
resolve(win);
|
||||
})();
|
||||
""",
|
||||
args=[url, focus],
|
||||
)
|
||||
|
||||
# Append opened chrome window to automatic closing on teardown
|
||||
opened_chrome_windows.append(new_window)
|
||||
return new_window
|
||||
|
||||
yield _new_chrome_window
|
||||
|
||||
with using_context(current_session, "chrome"):
|
||||
for win in opened_chrome_windows:
|
||||
try:
|
||||
current_session.window_handle = win.id
|
||||
current_session.execute_script("arguments[0].close()", args=[win])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
current_session.window_handle = current_session.handles[0]
|
||||
|
||||
|
||||
@pytest.fixture(name="create_custom_profile")
|
||||
def fixture_create_custom_profile(default_preferences, profile_folder):
|
||||
profile = None
|
||||
|
||||
Reference in New Issue
Block a user