iterator = allStrings.iterator();
- boolean isFirst = true;
- while (iterator.hasNext()) {
- if (!isFirst) {
- content.append("&");
- }
- content.append(URLEncoder.encode(iterator.next(), UTF_8));
-
- String next = iterator.next();
- if (next != null) {
- content.append("=").append(URLEncoder.encode(next, UTF_8));
- }
- if (isFirst) {
- isFirst = false;
- }
- }
-
- return new HttpRequest(GET, "/foo")
- .addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
- .setContent(utf8String(content.toString()));
- }
-}
diff --git a/java/test/org/openqa/selenium/safari/CrossDomainTest.java b/java/test/org/openqa/selenium/safari/CrossDomainTest.java
index 2f9e5c4a51724..842f0fc7db4c4 100644
--- a/java/test/org/openqa/selenium/safari/CrossDomainTest.java
+++ b/java/test/org/openqa/selenium/safari/CrossDomainTest.java
@@ -41,7 +41,7 @@ class CrossDomainTest extends JupiterTestBase {
@BeforeAll
public static void startSecondServer() {
- otherServer = new NettyAppServer();
+ otherServer = new NettyAppServer(false);
otherServer.start();
otherPages = new Pages(otherServer);
diff --git a/java/test/org/openqa/selenium/testing/BUILD.bazel b/java/test/org/openqa/selenium/testing/BUILD.bazel
index 9bc398860502a..68d6d6a2f675d 100644
--- a/java/test/org/openqa/selenium/testing/BUILD.bazel
+++ b/java/test/org/openqa/selenium/testing/BUILD.bazel
@@ -20,6 +20,7 @@ java_library(
"Ignore.java",
"IgnoreList.java",
"NeedsFreshDriver.java",
+ "NeedsSecureServer.java",
"NoDriverAfterTest.java",
"NoDriverBeforeTest.java",
"NotWorkingInRemoteBazelBuilds.java",
diff --git a/java/test/org/openqa/selenium/testing/JupiterTestBase.java b/java/test/org/openqa/selenium/testing/JupiterTestBase.java
index bd42009600ba5..a540bafb7c849 100644
--- a/java/test/org/openqa/selenium/testing/JupiterTestBase.java
+++ b/java/test/org/openqa/selenium/testing/JupiterTestBase.java
@@ -22,6 +22,8 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;
+import java.util.Optional;
+import java.util.logging.Logger;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@@ -37,6 +39,8 @@
public abstract class JupiterTestBase {
+ private static final Logger LOG = Logger.getLogger(JupiterTestBase.class.getName());
+
@RegisterExtension protected static SeleniumExtension seleniumExtension = new SeleniumExtension();
protected TestEnvironment environment;
@@ -54,9 +58,27 @@ public static void shouldTestBeRunAtAll() {
@BeforeEach
public void prepareEnvironment() {
- environment = GlobalTestEnvironment.getOrCreate(InProcessTestEnvironment::new);
+ boolean needsSecureServer =
+ Optional.ofNullable(this.getClass().getAnnotation(NeedsSecureServer.class))
+ .map(NeedsSecureServer::value)
+ .orElse(false);
+
+ environment =
+ GlobalTestEnvironment.getOrCreate(() -> new InProcessTestEnvironment(needsSecureServer));
appServer = environment.getAppServer();
+ if (needsSecureServer) {
+ try {
+ appServer.whereIsSecure("/");
+ } catch (IllegalStateException ex) {
+ // this should not happen with bazel, a new JVM is used for each class
+ // the annotation is on class level, so we should never see this
+ LOG.info("appServer is restarted with secureServer=true");
+ environment.stop();
+ environment = new InProcessTestEnvironment(true);
+ }
+ }
+
pages = new Pages(appServer);
driver = seleniumExtension.getDriver();
diff --git a/java/test/org/openqa/selenium/testing/NeedsSecureServer.java b/java/test/org/openqa/selenium/testing/NeedsSecureServer.java
new file mode 100644
index 0000000000000..beda0b16d666b
--- /dev/null
+++ b/java/test/org/openqa/selenium/testing/NeedsSecureServer.java
@@ -0,0 +1,30 @@
+// Licensed to the Software Freedom Conservancy (SFC) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The SFC licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.openqa.selenium.testing;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface NeedsSecureServer {
+
+ boolean value() default true;
+}
diff --git a/java/test/org/openqa/selenium/testing/drivers/Browser.java b/java/test/org/openqa/selenium/testing/drivers/Browser.java
index bab6e081dbd5b..a75d321bd7ac8 100644
--- a/java/test/org/openqa/selenium/testing/drivers/Browser.java
+++ b/java/test/org/openqa/selenium/testing/drivers/Browser.java
@@ -83,7 +83,7 @@ public Capabilities getCapabilities() {
}
if (Boolean.getBoolean("webdriver.headless")) {
- options.addArguments("--headless=chrome");
+ options.addArguments("--headless=new");
}
options.addArguments(
diff --git a/javascript/node/selenium-webdriver/bidi/browsingContext.js b/javascript/node/selenium-webdriver/bidi/browsingContext.js
index eeba70ff7153f..9a32004c14d15 100644
--- a/javascript/node/selenium-webdriver/bidi/browsingContext.js
+++ b/javascript/node/selenium-webdriver/bidi/browsingContext.js
@@ -528,10 +528,15 @@ class BrowsingContext {
throw Error(`Pass in an array of ReferenceValue objects. Received: ${startNodes}`)
}
+ let startNodesSerialized = undefined
+
if (startNodes !== undefined && Array.isArray(startNodes)) {
+ startNodesSerialized = []
startNodes.forEach((node) => {
if (!(node instanceof ReferenceValue)) {
throw Error(`Pass in a ReferenceValue object. Received: ${node}`)
+ } else {
+ startNodesSerialized.push(node.asMap())
}
})
}
@@ -544,7 +549,7 @@ class BrowsingContext {
maxNodeCount: maxNodeCount,
sandbox: sandbox,
serializationOptions: serializationOptions,
- startNodes: startNodes,
+ startNodes: startNodesSerialized,
},
}
diff --git a/javascript/node/selenium-webdriver/test/bidi/locate_nodes_test.js b/javascript/node/selenium-webdriver/test/bidi/locate_nodes_test.js
index 109f2e07ad00e..a41bb344d79e8 100644
--- a/javascript/node/selenium-webdriver/test/bidi/locate_nodes_test.js
+++ b/javascript/node/selenium-webdriver/test/bidi/locate_nodes_test.js
@@ -19,7 +19,7 @@
const assert = require('node:assert')
const { Browser } = require('selenium-webdriver')
-const { Pages, suite } = require('../../lib/test')
+const { Pages, suite, ignore } = require('../../lib/test')
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext')
const { Locator } = require('selenium-webdriver/bidi/browsingContext')
const { ScriptManager } = require('selenium-webdriver/index')
@@ -80,7 +80,7 @@ suite(
assert.notEqual(element.sharedId, undefined)
})
- xit('can locate node with xpath locator', async function () {
+ it('can locate node with xpath locator', async function () {
const id = await driver.getWindowHandle()
const browsingContext = await BrowsingContext(driver, {
browsingContextId: id,
@@ -97,7 +97,7 @@ suite(
assert.notEqual(element.sharedId, undefined)
})
- xit('can locate node with inner test locator', async function () {
+ ignore(env.browsers(Browser.FIREFOX)).it('can locate node with inner test locator', async function () {
const id = await driver.getWindowHandle()
const browsingContext = await BrowsingContext(driver, {
browsingContextId: id,
@@ -109,12 +109,9 @@ suite(
const element = elements[0]
assert.strictEqual(element.type, 'node')
assert.notEqual(element.value, undefined)
- assert.strictEqual(element.value.localName, 'div')
- assert.strictEqual(element.value.attributes.class, 'content')
- assert.notEqual(element.sharedId, undefined)
})
- xit('can locate node with max node count', async function () {
+ it('can locate node with max node count', async function () {
const id = await driver.getWindowHandle()
const browsingContext = await BrowsingContext(driver, {
browsingContextId: id,
@@ -126,7 +123,7 @@ suite(
assert.strictEqual(elements.length, 4)
})
- xit('can locate node with given start nodes', async function () {
+ it('can locate node with given start nodes', async function () {
const id = await driver.getWindowHandle()
const browsingContext = await BrowsingContext(driver, {
browsingContextId: id,
@@ -155,14 +152,7 @@ suite(
startNodes.push(new ReferenceValue(node.handle, node.sharedId))
})
- const elements = await browsingContext.locateNodes(
- Locator.css('input'),
- 50,
- 'none',
- undefined,
- undefined,
- startNodes,
- )
+ const elements = await browsingContext.locateNodes(Locator.css('input'), 50, 'none', undefined, startNodes)
assert.strictEqual(elements.length, 35)
})
@@ -236,5 +226,5 @@ suite(
})
})
},
- { browsers: [Browser.FIREFOX] },
+ { browsers: [Browser.FIREFOX, Browser.CHROME, Browser.EDGE] },
)
diff --git a/py/selenium/webdriver/remote/webelement.py b/py/selenium/webdriver/remote/webelement.py
index 08c772eaad56e..e5a3adad0d7b4 100644
--- a/py/selenium/webdriver/remote/webelement.py
+++ b/py/selenium/webdriver/remote/webelement.py
@@ -173,6 +173,13 @@ def get_attribute(self, name) -> str | None:
# Check if the "active" CSS class is applied to an element.
is_active = "active" in target_element.get_attribute("class")
"""
+
+ warnings.warn(
+ "using WebElement.get_attribute() has been deprecated. Please use get_dom_attribute() instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+
if getAttribute_js is None:
_load_js()
attribute_value = self.parent.execute_script(
diff --git a/py/test/selenium/webdriver/common/alerts_tests.py b/py/test/selenium/webdriver/common/alerts_tests.py
index ea37e0e3d5371..9479df88fadf5 100644
--- a/py/test/selenium/webdriver/common/alerts_tests.py
+++ b/py/test/selenium/webdriver/common/alerts_tests.py
@@ -294,6 +294,7 @@ def test_alert_should_not_allow_additional_commands_if_dismissed(driver, pages):
@pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1279211")
@pytest.mark.xfail_chrome
@pytest.mark.xfail_edge
+@pytest.mark.xfail_safari
def test_unexpected_alert_present_exception_contains_alert_text(driver, pages):
pages.load("alerts.html")
driver.find_element(by=By.ID, value="alert").click()
diff --git a/py/test/selenium/webdriver/common/api_example_tests.py b/py/test/selenium/webdriver/common/api_example_tests.py
index 7b8a4cedee3d8..40b3d2b7a2f01 100644
--- a/py/test/selenium/webdriver/common/api_example_tests.py
+++ b/py/test/selenium/webdriver/common/api_example_tests.py
@@ -240,6 +240,7 @@ def test_is_element_displayed(driver, pages):
@pytest.mark.xfail_chrome
+@pytest.mark.xfail_safari
def test_move_window_position(driver, pages):
pages.load("blank.html")
loc = driver.get_window_position()
diff --git a/py/test/selenium/webdriver/common/bidi_tests.py b/py/test/selenium/webdriver/common/bidi_tests.py
index cfa34a55a6cae..6872bc211f4ba 100644
--- a/py/test/selenium/webdriver/common/bidi_tests.py
+++ b/py/test/selenium/webdriver/common/bidi_tests.py
@@ -18,7 +18,6 @@
from selenium.webdriver.common.by import By
from selenium.webdriver.common.log import Log
-from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
@@ -76,8 +75,6 @@ async def test_collect_log_mutations(driver, pages):
WebDriverWait(driver, 10).until(
lambda d: d.find_element(By.ID, "revealed").value_of_css_property("display") != "none"
)
- WebDriverWait(driver, 5).until(EC.visibility_of(driver.find_element(By.ID, "revealed")))
-
assert event["attribute_name"] == "style"
assert event["current_value"] == ""
assert event["old_value"] == "display:none;"
diff --git a/py/test/selenium/webdriver/common/interactions_tests.py b/py/test/selenium/webdriver/common/interactions_tests.py
index 8c2ad03fc8d6f..7ffe0e9dc4e0b 100644
--- a/py/test/selenium/webdriver/common/interactions_tests.py
+++ b/py/test/selenium/webdriver/common/interactions_tests.py
@@ -253,6 +253,7 @@ def test_can_pause(driver, pages):
@pytest.mark.xfail_firefox
@pytest.mark.xfail_remote
+@pytest.mark.xfail_safari
def test_can_scroll_to_element(driver, pages):
pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html")
iframe = driver.find_element(By.TAG_NAME, "iframe")
@@ -266,6 +267,7 @@ def test_can_scroll_to_element(driver, pages):
@pytest.mark.xfail_firefox
@pytest.mark.xfail_remote
+@pytest.mark.xfail_safari
def test_can_scroll_from_element_by_amount(driver, pages):
pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html")
iframe = driver.find_element(By.TAG_NAME, "iframe")
@@ -280,6 +282,7 @@ def test_can_scroll_from_element_by_amount(driver, pages):
@pytest.mark.xfail_firefox
@pytest.mark.xfail_remote
+@pytest.mark.xfail_safari
def test_can_scroll_from_element_with_offset_by_amount(driver, pages):
pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html")
footer = driver.find_element(By.TAG_NAME, "footer")
@@ -314,6 +317,7 @@ def test_can_scroll_from_viewport_by_amount(driver, pages):
assert _in_viewport(driver, footer)
+@pytest.mark.xfail_safari
def test_can_scroll_from_viewport_with_offset_by_amount(driver, pages):
pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html")
scroll_origin = ScrollOrigin.from_viewport(10, 10)
diff --git a/py/test/selenium/webdriver/common/interactions_with_device_tests.py b/py/test/selenium/webdriver/common/interactions_with_device_tests.py
index 926b93c641e44..f82f3967a0776 100644
--- a/py/test/selenium/webdriver/common/interactions_with_device_tests.py
+++ b/py/test/selenium/webdriver/common/interactions_with_device_tests.py
@@ -247,6 +247,7 @@ def test_can_pause_with_pointer(driver, pages):
@pytest.mark.xfail_firefox
@pytest.mark.xfail_remote
+@pytest.mark.xfail_safari
def test_can_scroll_to_element_with_wheel(driver, pages):
pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html")
iframe = driver.find_element(By.TAG_NAME, "iframe")
@@ -262,6 +263,7 @@ def test_can_scroll_to_element_with_wheel(driver, pages):
@pytest.mark.xfail_firefox
@pytest.mark.xfail_remote
+@pytest.mark.xfail_safari
def test_can_scroll_from_element_by_amount_with_wheel(driver, pages):
pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html")
iframe = driver.find_element(By.TAG_NAME, "iframe")
@@ -278,6 +280,7 @@ def test_can_scroll_from_element_by_amount_with_wheel(driver, pages):
@pytest.mark.xfail_firefox
@pytest.mark.xfail_remote
+@pytest.mark.xfail_safari
def test_can_scroll_from_element_with_offset_by_amount_with_wheel(driver, pages):
pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html")
footer = driver.find_element(By.TAG_NAME, "footer")
@@ -320,6 +323,7 @@ def test_can_scroll_from_viewport_by_amount_with_wheel(driver, pages):
@pytest.mark.xfail_firefox
+@pytest.mark.xfail_safari
def test_can_scroll_from_viewport_with_offset_by_amount_with_wheel(driver, pages):
pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html")
scroll_origin = ScrollOrigin.from_viewport(10, 10)
diff --git a/py/test/selenium/webdriver/common/position_and_size_tests.py b/py/test/selenium/webdriver/common/position_and_size_tests.py
index a438c0f5e0c88..081c51358a517 100644
--- a/py/test/selenium/webdriver/common/position_and_size_tests.py
+++ b/py/test/selenium/webdriver/common/position_and_size_tests.py
@@ -53,6 +53,7 @@ def test_should_get_coordinates_of_an_invisible_element(driver, pages):
_check_location(element.location, x=0, y=0)
+@pytest.mark.xfail_safari
def test_should_scroll_page_and_get_coordinates_of_an_element_that_is_out_of_view_port(driver, pages):
pages.load("coordinates_tests/page_with_element_out_of_view.html")
element = driver.find_element(By.ID, "box")
@@ -89,6 +90,7 @@ def test_should_get_coordinates_of_an_element_in_anested_frame(driver, pages):
_check_location(element.location, x=10, y=10)
+@pytest.mark.xfail_safari
def test_should_get_coordinates_of_an_element_with_fixed_position(driver, pages):
pages.load("coordinates_tests/page_with_fixed_element.html")
element = driver.find_element(By.ID, "fixed")
diff --git a/py/test/selenium/webdriver/common/selenium_manager_tests.py b/py/test/selenium/webdriver/common/selenium_manager_tests.py
index 8692644cee0c4..67239bf87a67d 100644
--- a/py/test/selenium/webdriver/common/selenium_manager_tests.py
+++ b/py/test/selenium/webdriver/common/selenium_manager_tests.py
@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
import json
+import platform
import sys
from pathlib import Path
from unittest import mock
@@ -59,10 +60,14 @@ def test_uses_windows(monkeypatch):
def test_uses_linux(monkeypatch):
monkeypatch.setattr(sys, "platform", "linux")
- binary = SeleniumManager()._get_binary()
- project_root = Path(selenium.__file__).parent.parent
- assert binary == project_root.joinpath("selenium/webdriver/common/linux/selenium-manager")
+ if platform.machine() == "arm64":
+ with pytest.raises(WebDriverException, match="Unsupported platform/architecture combination: linux/arm64"):
+ SeleniumManager()._get_binary()
+ else:
+ binary = SeleniumManager()._get_binary()
+ project_root = Path(selenium.__file__).parent.parent
+ assert binary == project_root.joinpath("selenium/webdriver/common/linux/selenium-manager")
def test_uses_mac(monkeypatch):
diff --git a/py/test/selenium/webdriver/common/upload_tests.py b/py/test/selenium/webdriver/common/upload_tests.py
index f5521abd50fd8..642085790e303 100644
--- a/py/test/selenium/webdriver/common/upload_tests.py
+++ b/py/test/selenium/webdriver/common/upload_tests.py
@@ -16,11 +16,14 @@
# under the License.
import os
+import textwrap
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.webdriver.support.wait import WebDriverWait
@pytest.fixture
@@ -28,32 +31,33 @@ def get_local_path():
current_dir = os.path.dirname(os.path.realpath(__file__))
def wrapped(filename):
- return os.path.join(current_dir, filename)
+ full_path = os.path.join(current_dir, filename)
+ return textwrap.fill(full_path, width=512)
return wrapped
+@pytest.mark.xfail_safari
def test_can_upload_file(driver, pages, get_local_path):
pages.load("upload.html")
driver.find_element(By.ID, "upload").send_keys(get_local_path("test_file.txt"))
driver.find_element(By.ID, "go").click()
driver.switch_to.frame(driver.find_element(By.ID, "upload_target"))
- body = driver.find_element(By.CSS_SELECTOR, "body").text
- assert "test_file.txt" in body
+ WebDriverWait(driver, 10).until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, "body"), "test_file.txt"))
+@pytest.mark.xfail_safari
def test_can_upload_two_files(driver, pages, get_local_path):
pages.load("upload.html")
two_file_paths = get_local_path("test_file.txt") + "\n" + get_local_path("test_file2.txt")
driver.find_element(By.ID, "upload").send_keys(two_file_paths)
driver.find_element(By.ID, "go").click()
driver.switch_to.frame(driver.find_element(By.ID, "upload_target"))
- body = driver.find_element(By.CSS_SELECTOR, "body").text
- assert "test_file.txt" in body
- assert "test_file2.txt" in body
+ WebDriverWait(driver, 10).until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, "body"), "test_file.txt"))
+ WebDriverWait(driver, 10).until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, "body"), "test_file2.txt"))
@pytest.mark.xfail_firefox
diff --git a/py/test/selenium/webdriver/common/w3c_interaction_tests.py b/py/test/selenium/webdriver/common/w3c_interaction_tests.py
index d0a00ac26a2d4..5376265ede3bb 100644
--- a/py/test/selenium/webdriver/common/w3c_interaction_tests.py
+++ b/py/test/selenium/webdriver/common/w3c_interaction_tests.py
@@ -176,6 +176,7 @@ def test_dragging_element_with_mouse_fires_events(driver, pages):
@pytest.mark.xfail_firefox
@pytest.mark.xfail_remote
+@pytest.mark.xfail_safari
def test_pen_pointer_properties(driver, pages):
pages.load("pointerActionsPage.html")
@@ -223,6 +224,7 @@ def test_pen_pointer_properties(driver, pages):
@pytest.mark.xfail_firefox
@pytest.mark.xfail_remote
+@pytest.mark.xfail_safari
def test_touch_pointer_properties(driver, pages):
pages.load("pointerActionsPage.html")
pointerArea = driver.find_element(By.CSS_SELECTOR, "#pointerArea")
diff --git a/py/test/selenium/webdriver/common/webdriverwait_tests.py b/py/test/selenium/webdriver/common/webdriverwait_tests.py
index 14019d185e8b0..f332933e4241c 100644
--- a/py/test/selenium/webdriver/common/webdriverwait_tests.py
+++ b/py/test/selenium/webdriver/common/webdriverwait_tests.py
@@ -35,6 +35,7 @@ def throw_sere(driver):
@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
+@pytest.mark.xfail_safari
def test_should_fail_with_invalid_selector_exception(driver, pages):
pages.load("dynamic.html")
with pytest.raises(InvalidSelectorException):
diff --git a/py/test/selenium/webdriver/common/webserver.py b/py/test/selenium/webdriver/common/webserver.py
index 5a227c1722f6c..bd108dade8278 100644
--- a/py/test/selenium/webdriver/common/webserver.py
+++ b/py/test/selenium/webdriver/common/webserver.py
@@ -59,27 +59,43 @@ def updir():
class HtmlOnlyHandler(BaseHTTPRequestHandler):
- """Http handler."""
+ """Handler for HTML responses and JSON files."""
+
+ def _serve_page(self, page_number):
+ """Serve a dynamically generated HTML page."""
+ html = f"""Page{page_number}
+ Page number {page_number}
+ top
+ """
+ return html.encode("utf-8")
+
+ def _serve_file(self, file_path):
+ """Serve a file from the HTML root directory."""
+ with open(file_path, encoding="latin-1") as f:
+ return f.read().encode("utf-8")
+
+ def _send_response(self, content_type="text/html"):
+ """Send a response."""
+ self.send_response(200)
+ self.send_header("Content-type", content_type)
+ self.end_headers()
def do_GET(self):
"""GET method handler."""
try:
path = self.path[1:].split("?")[0]
- if path[:5] == "page/":
- html = """Page{page_number}
- Page number {page_number}
- top
- """.format(
- page_number=path[5:]
- )
- html = html.encode("utf-8")
+ file_path = os.path.join(HTML_ROOT, path)
+ if path.startswith("page/"):
+ html = self._serve_page(path[5:])
+ self._send_response("text/html")
+ self.wfile.write(html)
+ elif os.path.isfile(file_path):
+ content_type = "application/json" if file_path.endswith(".json") else "text/html"
+ content = self._serve_file(file_path)
+ self._send_response(content_type)
+ self.wfile.write(content)
else:
- with open(os.path.join(HTML_ROOT, path), encoding="latin-1") as f:
- html = f.read().encode("utf-8")
- self.send_response(200)
- self.send_header("Content-type", "text/html")
- self.end_headers()
- self.wfile.write(html)
+ self.send_error(404, f"File Not Found: {path}")
except OSError:
self.send_error(404, f"File Not Found: {path}")
@@ -87,34 +103,12 @@ def do_POST(self):
"""POST method handler."""
try:
remaining_bytes = int(self.headers["content-length"])
- contents = ""
- line = self.rfile.readline()
- contents += line.decode("utf-8")
- remaining_bytes -= len(line)
- line = self.rfile.readline()
- contents += line.decode("utf-8")
- remaining_bytes -= len(line)
- fn = re.findall(r'Content-Disposition.*name="upload"; filename="(.*)"', line.decode("utf-8"))
- if not fn:
- self.send_error(500, f"File not found. {contents}")
+ contents = self.rfile.read(remaining_bytes).decode("utf-8")
+ fn_match = re.search(r'Content-Disposition.*name="upload"; filename="(.*)"', contents)
+ if not fn_match:
+ self.send_error(500, f"File not found in content. {contents}")
return
- line = self.rfile.readline()
- remaining_bytes -= len(line)
- contents += line.decode("utf-8")
- line = self.rfile.readline()
- remaining_bytes -= len(line)
- contents += line.decode("utf-8")
- preline = self.rfile.readline()
- remaining_bytes -= len(preline)
- while remaining_bytes > 0:
- line = self.rfile.readline()
- remaining_bytes -= len(line)
- contents += line.decode("utf-8")
-
- self.send_response(200)
- self.send_header("Content-type", "text/html")
- self.end_headers()
-
+ self._send_response("text/html")
self.wfile.write(
f"""
{contents}
diff --git a/py/test/selenium/webdriver/common/window_switching_tests.py b/py/test/selenium/webdriver/common/window_switching_tests.py
index 1e2359cd52b36..2883ab2c55f69 100644
--- a/py/test/selenium/webdriver/common/window_switching_tests.py
+++ b/py/test/selenium/webdriver/common/window_switching_tests.py
@@ -130,6 +130,7 @@ def test_should_throw_no_such_window_exception_on_any_element_operation_if_awind
element.text
+@pytest.mark.xfail_safari
def test_clicking_on_abutton_that_closes_an_open_window_does_not_cause_the_browser_to_hang(driver, pages):
pages.load("xhtmlTest.html")
current = driver.current_window_handle
diff --git a/py/test/selenium/webdriver/safari/__init__.py b/py/test/selenium/webdriver/safari/__init__.py
new file mode 100644
index 0000000000000..a5b1e6f85a09e
--- /dev/null
+++ b/py/test/selenium/webdriver/safari/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/py/test/selenium/webdriver/safari/safari_service_tests.py b/py/test/selenium/webdriver/safari/safari_service_tests.py
new file mode 100644
index 0000000000000..494cbe6be6143
--- /dev/null
+++ b/py/test/selenium/webdriver/safari/safari_service_tests.py
@@ -0,0 +1,59 @@
+# Licensed to the Software Freedom Conservancy (SFC) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The SFC licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import os
+
+import pytest
+
+from selenium.webdriver.safari.service import Service
+
+
+@pytest.fixture
+def service():
+ return Service()
+
+
+@pytest.mark.usefixtures("service")
+class TestSafariDriverService:
+ service_path = "/path/to/safaridriver"
+
+ @pytest.fixture(autouse=True)
+ def setup_and_teardown(self):
+ os.environ["SE_SAFARIDRIVER"] = self.service_path
+ yield
+ os.environ.pop("SE_SAFARIDRIVER", None)
+
+ def test_uses_path_from_env_variable(self, service):
+ assert "safaridriver" in service.path
+
+ def test_updates_path_after_setting_env_variable(self, service):
+ new_path = "/foo/bar"
+ os.environ["SE_SAFARIDRIVER"] = new_path
+ service.executable_path = self.service_path # Simulating the update
+
+ assert "safaridriver" in service.executable_path
+
+
+def test_enable_logging():
+ enable_logging = True
+ service = Service(enable_logging=enable_logging)
+ assert "--diagnose" in service.service_args
+
+
+def test_service_url():
+ service = Service(port=1313)
+ assert service.service_url == "http://localhost:1313"
diff --git a/rust/Cargo.Bazel.lock b/rust/Cargo.Bazel.lock
index 187142b30214a..aa489691c16ae 100644
--- a/rust/Cargo.Bazel.lock
+++ b/rust/Cargo.Bazel.lock
@@ -1,5 +1,5 @@
{
- "checksum": "1b307b787c95f27b60af367955d57dfd4b21ff233bf6e156a87950f4c610430e",
+ "checksum": "94895b25f9b1d0a76ec78d588887353422bc623faf9ef986467b199d2a966765",
"crates": {
"addr2line 0.21.0": {
"name": "addr2line",
@@ -572,14 +572,14 @@
],
"license_file": "LICENSE-APACHE"
},
- "anyhow 1.0.89": {
+ "anyhow 1.0.91": {
"name": "anyhow",
- "version": "1.0.89",
+ "version": "1.0.91",
"package_url": "https://github.com/dtolnay/anyhow",
"repository": {
"Http": {
- "url": "https://static.crates.io/crates/anyhow/1.0.89/download",
- "sha256": "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
+ "url": "https://static.crates.io/crates/anyhow/1.0.91/download",
+ "sha256": "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8"
}
},
"targets": [
@@ -623,7 +623,7 @@
"deps": {
"common": [
{
- "id": "anyhow 1.0.89",
+ "id": "anyhow 1.0.91",
"target": "build_script_build"
},
{
@@ -634,7 +634,7 @@
"selects": {}
},
"edition": "2018",
- "version": "1.0.89"
+ "version": "1.0.91"
},
"build_script_attrs": {
"compile_data_glob": [
@@ -2034,16 +2034,79 @@
"id": "jobserver 0.1.31",
"target": "jobserver"
},
- {
- "id": "libc 0.2.160",
- "target": "libc"
- },
{
"id": "shlex 1.3.0",
"target": "shlex"
}
],
- "selects": {}
+ "selects": {
+ "aarch64-apple-darwin": [
+ {
+ "id": "libc 0.2.160",
+ "target": "libc"
+ }
+ ],
+ "aarch64-unknown-linux-gnu": [
+ {
+ "id": "libc 0.2.160",
+ "target": "libc"
+ }
+ ],
+ "aarch64-unknown-nixos-gnu": [
+ {
+ "id": "libc 0.2.160",
+ "target": "libc"
+ }
+ ],
+ "arm-unknown-linux-gnueabi": [
+ {
+ "id": "libc 0.2.160",
+ "target": "libc"
+ }
+ ],
+ "i686-unknown-linux-gnu": [
+ {
+ "id": "libc 0.2.160",
+ "target": "libc"
+ }
+ ],
+ "powerpc-unknown-linux-gnu": [
+ {
+ "id": "libc 0.2.160",
+ "target": "libc"
+ }
+ ],
+ "s390x-unknown-linux-gnu": [
+ {
+ "id": "libc 0.2.160",
+ "target": "libc"
+ }
+ ],
+ "x86_64-apple-darwin": [
+ {
+ "id": "libc 0.2.160",
+ "target": "libc"
+ }
+ ],
+ "x86_64-unknown-freebsd": [
+ {
+ "id": "libc 0.2.160",
+ "target": "libc"
+ }
+ ],
+ "x86_64-unknown-linux-gnu": [
+ {
+ "id": "libc 0.2.160",
+ "target": "libc"
+ }
+ ],
+ "x86_64-unknown-nixos-gnu": [
+ {
+ "id": "libc 0.2.160",
+ "target": "libc"
+ }
+ ]
+ }
},
"edition": "2018",
"version": "1.1.30"
@@ -4058,7 +4121,7 @@
"target": "log"
},
{
- "id": "regex 1.11.0",
+ "id": "regex 1.11.1",
"target": "regex"
}
],
@@ -10411,14 +10474,14 @@
],
"license_file": "LICENSE"
},
- "regex 1.11.0": {
+ "regex 1.11.1": {
"name": "regex",
- "version": "1.11.0",
+ "version": "1.11.1",
"package_url": "https://github.com/rust-lang/regex",
"repository": {
"Http": {
- "url": "https://static.crates.io/crates/regex/1.11.0/download",
- "sha256": "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
+ "url": "https://static.crates.io/crates/regex/1.11.1/download",
+ "sha256": "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
}
},
"targets": [
@@ -10484,7 +10547,7 @@
"selects": {}
},
"edition": "2021",
- "version": "1.11.0"
+ "version": "1.11.1"
},
"license": "MIT OR Apache-2.0",
"license_ids": [
@@ -12808,7 +12871,7 @@
"target": "quote"
},
{
- "id": "regex 1.11.0",
+ "id": "regex 1.11.1",
"target": "regex"
},
{
@@ -14073,7 +14136,7 @@
"deps": {
"common": [
{
- "id": "anyhow 1.0.89",
+ "id": "anyhow 1.0.91",
"target": "anyhow"
},
{
@@ -14117,7 +14180,7 @@
"target": "log"
},
{
- "id": "regex 1.11.0",
+ "id": "regex 1.11.1",
"target": "regex"
},
{
@@ -22673,7 +22736,7 @@
]
},
"direct_deps": [
- "anyhow 1.0.89",
+ "anyhow 1.0.91",
"apple-flat-package 0.18.0",
"bzip2 0.4.4",
"clap 4.5.20",
@@ -22684,7 +22747,7 @@
"flate2 1.0.34",
"infer 0.16.0",
"log 0.4.22",
- "regex 1.11.0",
+ "regex 1.11.1",
"reqwest 0.12.8",
"serde 1.0.210",
"serde_json 1.0.128",