From 9e6f12ab225f51298658f4fb2811cab251479e4c Mon Sep 17 00:00:00 2001 From: Mohab Mohie Date: Mon, 27 Jul 2026 07:30:35 +0300 Subject: [PATCH 1/4] [java] Add regression coverage for relative locators on collapsed table borders (#13642) The bug reported in #13642 (relative locators picking the wrong element in a border-collapse table) was already fixed by 960ff05af8 (#14482), released in Selenium 4.28.0, which switched the above/below/left/right proximity comparisons from strict to inclusive <=/>=. However there was no regression test for it: mirroring all 21 existing Java relative-locator scenarios against a deliberately-reverted strict comparison shows every one of them still passes, meaning a silent regression back to strict comparisons would go completely undetected today. This adds a new test with its own inline page (not the shared common/src/web/relative_locators.html fixture, to avoid breaking other tests that use unqualified `td` selectors against it) modeling a w3schools-style customer table with collapsed borders, and asserts that toRightOf(...).below(...) resolves to the cell that shares a collapsed border with the anchor cells. Verified with a real bazel test run (bazelisk, headless chrome): - GREEN on current trunk (all 22 tests, including the new one, pass) - RED when above/below/left/right in javascript/atoms/typescript/find-elements.ts are temporarily reverted to strict (new test fails: expected "maria" but was "mexico") - GREEN again after reverting that temporary change Fixes #13642 --- .../support/locators/RelativeLocatorTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java b/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java index edd383fa04555..693f08f764357 100644 --- a/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java +++ b/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java @@ -367,4 +367,41 @@ void nearLocatorShouldNotFindFarElements() { .isThrownBy(() -> driver.findElement(with(By.id("rect4")).near(rect))) .withMessageContaining("Cannot locate an element using"); } + + @Test + void shouldFindCellThatSharesACollapsedBorderWithTheAnchorCell() { + String url = + appServer.create( + new Page() + .withTitle("Collapsed Borders") + .withStyles( + " table {\n" + + " border-collapse: collapse;\n" + + " table-layout: fixed;\n" + + " width: 450px;\n" + + " }\n" + + " td, th {\n" + + " border: 1px solid black;\n" + + " box-sizing: border-box;\n" + + " width: 150px;\n" + + " height: 40px;\n" + + " padding: 4px;\n" + + " }") + .withBody( + "\n" + + " Contact\n" + + " Maria Anders\n" + + " Francisco ChangMexico\n" + + "
CompanyCountry
Alfreds FutterkisteGermany
Centro comercial Moctezuma
")); + driver.get(url); + + WebElement cell = + driver.findElement(with(tagName("td")).toRightOf(By.id("alfreds")).below(By.id("contact"))); + + assertThat(cell.getAttribute("id")).isEqualTo("maria"); + } } From 356b0ded1cf332970fe5ce1ee1ec0b8b031e24cf Mon Sep 17 00:00:00 2001 From: Mohab Mohie Date: Mon, 27 Jul 2026 09:05:22 +0300 Subject: [PATCH 2/4] [java] Serve the new collapsed-border relative-locator test page in standards mode Addresses the qodo-code-review bot comment on PR #17827: the new shouldFindCellThatSharesACollapsedBorderWithTheAnchorCell test built its page with Page.toString(), which omits a doctype and places ", + "", + "", + body, + String.join("\n", bodyParts), + "", + ""); + } + return String.join( "\n", "", @@ -71,10 +109,7 @@ public String toString() { "", - String.format( - "", - onLoad == null ? "" : String.format("onload='%s'", onLoad), - onBeforeUnload == null ? "" : String.format("onbeforeunload='%s'", onBeforeUnload)), + body, String.join("\n", bodyParts), "", ""); diff --git a/java/test/org/openqa/selenium/environment/webserver/PageTest.java b/java/test/org/openqa/selenium/environment/webserver/PageTest.java new file mode 100644 index 0000000000000..59e031a1ad1c9 --- /dev/null +++ b/java/test/org/openqa/selenium/environment/webserver/PageTest.java @@ -0,0 +1,66 @@ +// 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.environment.webserver; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class PageTest { + + @Test + void defaultToStringHasNoDoctypeAndMatchesLegacyShape() { + String page = + new Page().withTitle("Legacy").withScripts("var a = 1;").withStyles("body { }").toString(); + + assertThat(page).doesNotContain("", + "", + "Legacy", + "", + "", + "", + "", + "", + "", + "")); + } + + @Test + void withDoctypeEmitsStandardsModeShapeWithScriptAndStyleInsideHead() { + String page = + new Page() + .withDoctype() + .withTitle("Standards") + .withScripts("var a = 1;") + .withStyles("body { }") + .toString(); + + assertThat(page).startsWith(""); + assertThat(page.indexOf("")).isLessThan(page.indexOf("")); + assertThat(page.indexOf("")).isLessThan(page.indexOf("")); + } +} diff --git a/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java b/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java index 693f08f764357..2e72bcfdccc8f 100644 --- a/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java +++ b/java/test/org/openqa/selenium/support/locators/RelativeLocatorTest.java @@ -373,6 +373,7 @@ void shouldFindCellThatSharesACollapsedBorderWithTheAnchorCell() { String url = appServer.create( new Page() + .withDoctype() .withTitle("Collapsed Borders") .withStyles( " table {\n" From d9318288230e599b0f3bf4bf456442c67ed119f5 Mon Sep 17 00:00:00 2001 From: Mohab Mohie Date: Mon, 27 Jul 2026 10:34:35 +0300 Subject: [PATCH 3/4] [java] Replace brittle full-string assertion in PageTest with invariant checks defaultToStringHasNoDoctypeAndMatchesLegacyShape previously pinned the exact output of Page.toString() via isEqualTo(), including incidental whitespace (the "" double-space, the blank line for an empty body). That makes harmless formatting refactors of toString() fail the test even when the legacy document shape/semantics are unchanged. Replace it with targeted checks that still prove the same contract: no doctype, ", - "", - "", - "", - "", - "")); + .contains("Legacy") + .contains("var a = 1;") + .contains("body { }") + .contains("") + .contains(""); } @Test From ea01e6286ea3a9a1a24b2a74a99b61e3685c9351 Mon Sep 17 00:00:00 2001 From: Mohab Mohie Date: Mon, 27 Jul 2026 11:13:20 +0300 Subject: [PATCH 4/4] [java] Fix indexOf ordering false-pass in PageTest defaultToStringHasNoDoctypeAndMatchesLegacyShape compared indexOf("") to indexOf(" exists. If were removed, indexOf() would return -1, which is still "less than" a positive script/style index, so the ordering assertion silently passed while the legacy page shape was actually broken. Replace the indexOf comparisons with AssertJ containsSubsequence, which asserts presence and order together, so a missing now correctly fails the test instead of passing by coincidence. Verified via a scratch test (removed before this commit) that the old assertion style raised no exception for a hand-built -removed string, and that the new containsSubsequence style does throw for the same string. --- .../org/openqa/selenium/environment/webserver/PageTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/test/org/openqa/selenium/environment/webserver/PageTest.java b/java/test/org/openqa/selenium/environment/webserver/PageTest.java index c2b54553974b5..0b3977c927df3 100644 --- a/java/test/org/openqa/selenium/environment/webserver/PageTest.java +++ b/java/test/org/openqa/selenium/environment/webserver/PageTest.java @@ -32,8 +32,10 @@ void defaultToStringHasNoDoctypeAndMatchesLegacyShape() { assertThat(page).doesNotContain("/