[java] Add regression coverage for relative locators on collapsed table borders (#13642) - #17827
Conversation
…le borders (SeleniumHQ#13642) The bug reported in SeleniumHQ#13642 (relative locators picking the wrong element in a border-collapse table) was already fixed by 960ff05 (SeleniumHQ#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 SeleniumHQ#13642
|
Thank you, @MohabMohie for this code suggestion. The support packages contain example code that many users find helpful, but they do not necessarily represent After reviewing the change, unless it is a critical fix or a feature that is needed for Selenium We actively encourage people to add the wrapper and helper code that makes sense for them to their own frameworks. |
PR Summary by QodoAdd Java regression test for relative locators with collapsed table borders
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
18 rules 1.
|
…tandards mode Addresses the qodo-code-review bot comment on PR SeleniumHQ#17827: the new shouldFindCellThatSharesACollapsedBorderWithTheAnchorCell test built its page with Page.toString(), which omits a doctype and places <script>/<style> outside <head>, making parsing/quirks-mode less deterministic for a layout-sensitive assertion. Add an opt-in Page.withDoctype() flag instead of changing the global Page.toString() default (Page is a shared fixture used across the whole suite). When unset, output is byte-identical to before (see PageTest, asserted against the exact legacy string). When set, it emits "<!DOCTYPE html>" and moves <script>/<style> inside <head>, mirroring the existing standards-mode shape already used by GeneratedJsTestHandler. Only the one new test opts in.
|
Code review by qodo was updated up to the latest commit 356b0de |
|
Can you please use the PR template we have? |
…nt checks defaultToStringHasNoDoctypeAndMatchesLegacyShape previously pinned the exact output of Page.toString() via isEqualTo(), including incidental whitespace (the "<body >" 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, <script>/<style> come after </head> closes (the legacy ordering, as opposed to the withDoctype() standards-mode shape), and the expected tags/content are present. Verified these assertions still catch the regressions they guard against (reintroduced doctype, script/style moved back inside <head>) before applying them. Addresses qodo-code-review feedback on PR SeleniumHQ#17827.
|
Reply to #17827 (comment): Fixed in d931828. Replaced the full-string
It no longer pins the exact Before applying these, I verified they're still meaningfully strict (not vacuous) by running them against two deliberately regressed shapes as a scratch check: a string with |
|
@diemol thanks for the nudge — updated the PR description to actually follow |
|
Code review by qodo was updated up to the latest commit d931828 |
defaultToStringHasNoDoctypeAndMatchesLegacyShape compared
indexOf("</head>") to indexOf("<script")/indexOf("<style") without
asserting </head> exists. If </head> 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 </head>
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 </head>-removed
string, and that the new containsSubsequence style does throw for the
same string.
|
Reply to #17827 (comment): Fixed in ea01e62: |
|
Code review by qodo was updated up to the latest commit ea01e62 |
🔗 Related Issues
Fixes #13642
💥 What does this PR do?
Adds the regression test that #13642 was missing. The underlying bug
(relative locators picking the wrong element in a
border-collapsetable) was already fixed by 960ff05 (#14482), released in Selenium
4.28.0, which changed the
above/below/left/rightproximitycomparisons in the find-elements atom from strict
</>to inclusive<=/>=— but nothing guarded that fix, so a silent regression back tostrict comparisons would go completely undetected today. This PR closes
that coverage gap with one new
RelativeLocatorTestscenario, plus twosmall follow-ups made in response to review:
Page.withDoctype(): an opt-in flag on the shared test-page builder sothe new test's page can request a standards-mode document (doctype,
<script>/<style>inside<head>) for deterministic parsing,without changing
Page's default output for every other caller.PageTestassertion fix: replaced a brittle full-string equalitycheck with targeted invariant checks (no doctype by default;
<script>/<style>stay after</head>closes; expected contentpresent) so future harmless whitespace-only refactors of
Page.toString()won't break the test.No production/runtime code changes are included — the locator fix
already exists on trunk; this PR only adds the missing regression
coverage plus the test-infrastructure changes needed to write it
cleanly.
🔧 Implementation Notes
Pagebuilder (same pattern as
ensureNoRepeatedElements), rather thanadding a table to the shared
common/src/web/relative_locators.htmlfixture. A previous attempt at this ([java][js] Fixed bug #13642 related to relative locators #14336) added such a table to the
shared fixture, which breaks other tests relying on unqualified
tdselectors against it (e.g.
shouldFindElementsBelowAnother); this PRavoids that regression by keeping the page test-local.
Page.withDoctype()is opt-in rather than a change toPage's defaultshape, because
Pageis a shared fixture used across the whole testsuite; making it opt-in keeps every existing caller's output
byte-identical while giving the new, layout-sensitive test a
deterministic (non-quirks-mode) document to assert against.
PageTestfix targets only the one brittle assertion flagged byreview — it still fails if a doctype is reintroduced or
<script>/<style>move back inside<head>(verified against both regressionshapes before applying it), it just no longer pins incidental
whitespace.
🤖 AI assistance
RelativeLocatorTestscenario and itsinline test page, the
Page.withDoctype()follow-up, thePageTestassertion fix, and this PR description. All of it wasreviewed and verified by me (real
bazelisk testruns, includingdeliberate RED/GREEN checks against reverted code, are described
below); I can explain every change without referring back to the
tool.
💡 Additional Considerations
None outstanding. All review feedback received so far has been addressed
in the follow-up commits described above.
🔄 Types of changes
Verification
Ran the real JUnit tests via Bazel (bazelisk):
RelativeLocatorTestsuite (22tests, including the new one) passes with 0 failures, headless Chrome.
above/below/left/rightcomparisons injavascript/atoms/typescript/find-elements.tsback to strict</>and reran — the new test fails as expected
(
expected: "maria" but was: "mexico"), while reverting back to thecurrent inclusive comparisons restores the passing state. This
confirms the new test actually exercises the fixed code path and would
catch a regression.
PageTest(2 tests): GREEN with the new invariant-style assertions;before applying them, confirmed via scratch checks that the same
assertion style throws on both a reintroduced doctype and on
<script>/<style>moved back inside<head>— i.e. it stillcatches the regressions the original test guarded against.
scripts/format.sh(no further changes beyondgoogle-java-formatline-wrapping already included in this diff).
Test plan
bazelisk test //java/test/org/openqa/selenium/support/locators:RelativeLocatorTest --//common:headless— 22/22 pass on trunkfind-elements.tsto strict comparisons, reran — new test fails with the wrong element, confirming it detects the regressionbazelisk test //java/test/org/openqa/selenium/environment:webserver/PageTest --test_output=all— 2/2 passscripts/format.sh— no additional formatting changes