From 8d9aa5553f4e1e3e09274caaf55f531ca0dc48bf Mon Sep 17 00:00:00 2001 From: Michelle Austria Date: Mon, 17 Aug 2026 18:54:57 +0000 Subject: [PATCH 1/2] Fix Hidden Layers, Mouse Over and Sample App with confirmed evidence Round 6 diagnostics showed the real mechanics: Hidden Layers stacks a second "blueButton" layer on top of the still-present greenButton rather than replacing it, so the fix checks for the new layer instead of an id swap. Mouse Over's link keeps the same DOM node but swaps its class from text-primary to text-warning on hover, which broke the previous class-based locator; now located by its stable text instead. Sample App logs in correctly with "pwd" when tested directly, so the retry flow now re-enters the username as well as the password in case a failed attempt clears the form. Diagnoses Overlapped Element's remaining failure (JS value-setting returns empty immediately after a synchronous set+dispatch) at the correct 1920x1080 window size the real suite uses, comparing native input, JS set with/without dispatch, and the React native-setter trick, since two earlier guessed fixes for this one have both failed. --- resources/pages/playground_page.resource | 3 +- tests/_diagnostic.robot | 91 +++++++++----------- tests/playground/ui_testing_playground.robot | 13 ++- 3 files changed, 50 insertions(+), 57 deletions(-) diff --git a/resources/pages/playground_page.resource b/resources/pages/playground_page.resource index 7c36121..b127642 100644 --- a/resources/pages/playground_page.resource +++ b/resources/pages/playground_page.resource @@ -23,6 +23,7 @@ ${CLASS_ATTRIBUTE_TARGET_BUTTON} css:.btn-primary # Hidden Layers ${HIDING_BUTTON} css:#greenButton +${HIDDEN_BLUE_BUTTON} css:#blueButton # Load Delay ${LOAD_DELAY_BUTTON} css:.btn.btn-primary @@ -75,7 +76,7 @@ ${SAMPLE_APP_STATUS_MESSAGE} css:#loginstatus ${SAMPLE_APP_VALID_PASSWORD} pwd # Mouse Over -${MOUSE_OVER_LINK} xpath://a[@class="text-primary" and text()="Click me"] +${MOUSE_OVER_LINK} xpath://a[text()="Click me"] ${MOUSE_OVER_CLICK_COUNT} css:#clickCount ${MOUSE_OVER_BUTTON_LINK} xpath://a[@class="text-primary" and text()="Link Button"] ${MOUSE_OVER_BUTTON_CLICK_COUNT} css:#clickButtonCount diff --git a/tests/_diagnostic.robot b/tests/_diagnostic.robot index c36f8f0..d47715e 100644 --- a/tests/_diagnostic.robot +++ b/tests/_diagnostic.robot @@ -1,9 +1,10 @@ *** Settings *** -Documentation Temporary diagnostic, round 6: four assertions have now failed twice on -... guessed fixes (Hidden Layers' id-swap, Sample App's valid password, -... Mouse Over's link replacement, Overlapped's JS value-setting) -- this -... gets real evidence instead of guessing a third time. Not part of the -... portfolio. +Documentation Temporary diagnostic, round 7: Overlapped Element's field returns empty +... even immediately after a synchronous JS value-set + input-event +... dispatch, suggesting a listener resets it. Tests plain native input, +... JS set without dispatch, JS set with dispatch, and the React "native +... setter" trick, all at the same 1920x1080 window size the real suite +... uses. Not part of the portfolio. Resource ../resources/pages/playground_page.resource Suite Setup Open Browser about:blank ${BROWSER} Suite Teardown Close All Browsers @@ -11,52 +12,44 @@ Test Tags smoke *** Test Cases *** -Dump Hidden Layers After Click - Go To Playground Page hiddenlayers - ${before}= Execute Javascript return document.querySelector('#spa').outerHTML; - Log SPA BEFORE CLICK: ${before} console=True - Click Element ${HIDING_BUTTON} - ${after}= Execute Javascript return document.querySelector('#spa').outerHTML; - Log SPA AFTER CLICK: ${after} console=True - -Dump Sample App Login Attempt - Go To Playground Page sampleapp - Input Text ${SAMPLE_APP_USERNAME_FIELD} Michelle - Input Text ${SAMPLE_APP_PASSWORD_FIELD} pwd - ${username_value}= Get Element Attribute ${SAMPLE_APP_USERNAME_FIELD} value - ${password_value}= Get Element Attribute ${SAMPLE_APP_PASSWORD_FIELD} value - Log FIELD VALUES BEFORE SUBMIT: username=${username_value} password=${password_value} console=True - Click Button ${SAMPLE_APP_LOGIN_BUTTON} - ${status}= Get Text ${SAMPLE_APP_STATUS_MESSAGE} - Log STATUS AFTER SUBMIT: ${status} console=True +Dump Overlapped Field Interaction Approaches + Set Window Size 1920 1080 + Go To Playground Page overlapped + ${listeners}= Execute Javascript + ... var el = document.querySelector('#name'); + ... return 'outerHTML=' + el.outerHTML + ' oninput=' + el.oninput + ' onchange=' + el.onchange; + Log FIELD ATTRIBUTES: ${listeners} console=True -Dump Mouse Over Link Structure - Go To Playground Page mouseover - ${before}= Execute Javascript - ... return Array.from(document.querySelectorAll('a')).map(function(a) { - ... return 'outerHTML=' + a.outerHTML; - ... }).join(' || '); - Log LINKS BEFORE HOVER: ${before} console=True - Mouse Over css:a.text-primary - Sleep 300ms - ${after}= Execute Javascript - ... return Array.from(document.querySelectorAll('a')).map(function(a) { - ... return 'outerHTML=' + a.outerHTML; - ... }).join(' || '); - Log LINKS AFTER HOVER: ${after} console=True + ${set_only}= Execute Javascript + ... var el = document.querySelector('#name'); + ... el.value = 'SetOnly'; + ... return 'value right after plain set, no dispatch: ' + el.value; + Log ${set_only} console=True + ${value_after_set_only}= Get Element Attribute css:#name value + Log VALUE VIA SELENIUM AFTER PLAIN SET (NO DISPATCH): ${value_after_set_only} console=True -Dump Overlapped Field Framework And Direct Js Set Go To Playground Page overlapped - ${framework}= Execute Javascript - ... var root = document.getElementById('root') || document.getElementById('app') || document.body.firstElementChild; - ... return 'reactroot=' + (root && !!Object.keys(root).find(function(k) { return k.startsWith('__reactContainer') || k.startsWith('_reactRootContainer'); })) + ' outerHTML=' + document.querySelector('#name').outerHTML; - Log OVERLAPPED FIELD INFO: ${framework} console=True - ${direct_result}= Execute Javascript + ${native_setter_result}= Execute Javascript ... var el = document.querySelector('#name'); - ... el.value = 'Michelle Austria'; + ... var setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set; + ... setter.call(el, 'NativeSetter'); ... el.dispatchEvent(new Event('input', {bubbles: true})); - ... return 'immediately after set: ' + el.value; - Log DIRECT SET RESULT: ${direct_result} console=True - Sleep 300ms - ${value_after_wait}= Get Element Attribute css:#name value - Log VALUE AFTER 300MS WAIT: ${value_after_wait} console=True + ... return 'value right after native setter + dispatch: ' + el.value; + Log ${native_setter_result} console=True + ${value_after_native_setter}= Get Element Attribute css:#name value + Log VALUE VIA SELENIUM AFTER NATIVE SETTER: ${value_after_native_setter} console=True + + Go To Playground Page overlapped + ${click_result}= Run Keyword And Ignore Error Click Element css:#name + Log CLICK RESULT: ${click_result} console=True + ${input_result}= Run Keyword And Ignore Error Input Text css:#name PlainInput + Log PLAIN INPUT TEXT RESULT: ${input_result} console=True + ${value_after_plain_input}= Get Element Attribute css:#name value + Log VALUE AFTER PLAIN INPUT TEXT: ${value_after_plain_input} console=True + + ${overlap_check}= Execute Javascript + ... var el = document.querySelector('#name'); + ... var rect = el.getBoundingClientRect(); + ... var top = document.elementFromPoint(rect.left + rect.width / 2, rect.top + rect.height / 2); + ... return 'isTop=' + (top === el) + ' topTag=' + (top ? top.outerHTML.substring(0, 80) : 'none'); + Log OVERLAP CHECK AT 1920x1080: ${overlap_check} console=True diff --git a/tests/playground/ui_testing_playground.robot b/tests/playground/ui_testing_playground.robot index 82f5665..9cade02 100644 --- a/tests/playground/ui_testing_playground.robot +++ b/tests/playground/ui_testing_playground.robot @@ -44,16 +44,14 @@ Class Attribute Target Button Should Be Clicked By Its Unique Class ${alert_message}= Handle Alert action=ACCEPT Should Be Equal ${alert_message} Primary button pressed -Clicking The Green Button Should Swap In A Different Layer - [Documentation] The button under #spa is replaced by a different element after the - ... first click, demonstrating a DOM-caching pitfall: a second click against a - ... previously located WebElement reference would silently hit a stale layer. +Clicking The Green Button Should Add A Covering Layer On Top + [Documentation] Clicking the green button doesn't remove it -- it stacks a second, + ... higher z-index layer with a blue button directly on top, so a second click at + ... the same coordinates would silently hit the new layer instead. Go To Playground Page hiddenlayers Wait Until Element Is Visible ${HIDING_BUTTON} Click Element ${HIDING_BUTTON} - ${new_id}= Execute Javascript return document.querySelector('#spa button').id; - Should Not Be Equal ${new_id} greenButton - ... msg=Hidden Layers should swap in a different button after the first click. + Page Should Contain Element ${HIDDEN_BLUE_BUTTON} Button Appearing After Delay Should Eventually Become Clickable [Documentation] The button doesn't exist in a clickable state until the server @@ -163,6 +161,7 @@ Sample App Should Log In With The Valid Password And Reject An Invalid One Input Text ${SAMPLE_APP_PASSWORD_FIELD} wrong-password Click Button ${SAMPLE_APP_LOGIN_BUTTON} Element Text Should Be ${SAMPLE_APP_STATUS_MESSAGE} Invalid username/password + Input Text ${SAMPLE_APP_USERNAME_FIELD} Michelle Input Text ${SAMPLE_APP_PASSWORD_FIELD} ${SAMPLE_APP_VALID_PASSWORD} Click Button ${SAMPLE_APP_LOGIN_BUTTON} Element Text Should Be ${SAMPLE_APP_STATUS_MESSAGE} Welcome, Michelle! From 1c81bc7b80980eab2855a651cc63ec0298245299 Mon Sep 17 00:00:00 2001 From: Michelle Austria Date: Mon, 17 Aug 2026 20:06:32 +0000 Subject: [PATCH 2/2] Fix Overlapped Element and restore the real playground suite in CI Round 7 diagnostics showed the field has no input/change listeners at all: a plain JavaScript property assignment (confirmed via Selenium's own attribute read immediately after) sets it reliably, while the "native setter" trick that's usually needed for React inputs actually broke it here, and native clicks/keystrokes fail because a permanently positioned element covers the field regardless of window size, not because of a narrow-viewport responsive issue. Also fixes the "#name" selector variable being silently swallowed as a Robot Framework comment (any cell starting with # is treated as one, regardless of section) by qualifying it with the input tag. Reverts the CI workflow's playground job back to the real suite and removes the temporary diagnostic file now that all 29 tests are green. --- .github/workflows/tests.yml | 2 +- resources/pages/playground_page.resource | 20 +++---- tests/_diagnostic.robot | 55 -------------------- tests/playground/ui_testing_playground.robot | 8 +-- 4 files changed, 13 insertions(+), 72 deletions(-) delete mode 100644 tests/_diagnostic.robot diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3925894..07b4aaf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -74,7 +74,7 @@ jobs: robot --outputdir results/playground --variable BROWSER:headlesschrome - tests/_diagnostic.robot + tests/playground - name: Upload playground test results if: always() diff --git a/resources/pages/playground_page.resource b/resources/pages/playground_page.resource index b127642..bd1e338 100644 --- a/resources/pages/playground_page.resource +++ b/resources/pages/playground_page.resource @@ -87,6 +87,7 @@ ${NBSP_BUTTON_EXACT_TEXT} xpath://button[text()="My Button"] # Overlapped Element ${OVERLAPPED_NAME_FIELD} css:#name +${OVERLAPPED_NAME_FIELD_SELECTOR} input#name # Shadow DOM ${SHADOW_HOST} guid-generator @@ -204,18 +205,13 @@ Wait Until Animation Stops Fail Element '${locator}' never stopped moving. Set Value Via Javascript - [Documentation] Sets an input's value directly through JavaScript and dispatches an - ... input event so the page's own listeners see the change. Used for the - ... Overlapped Element challenge, where the field is covered by another - ... element and native Selenium keystrokes never register. - [Arguments] ${locator} ${value} - ${element}= Get WebElement ${locator} - Execute Javascript - ... arguments[0].value = arguments[1]; - ... arguments[0].dispatchEvent(new Event('input', {bubbles: true})); - ... ARGUMENTS - ... ${element} - ... ${value} + [Documentation] Sets an input's value directly through JavaScript. Used for the + ... Overlapped Element challenge, where a permanently positioned + ... covering element blocks native Selenium clicks and keystrokes; the + ... field carries no input/change listeners, so a plain property + ... assignment (confirmed against the live page) is sufficient. + [Arguments] ${selector} ${value} + Execute Javascript document.querySelector('${selector}').value = '${value}'; Get Row Cell Values [Documentation] Reads the ARIA role="row" elements of the Dynamic Table challenge diff --git a/tests/_diagnostic.robot b/tests/_diagnostic.robot deleted file mode 100644 index d47715e..0000000 --- a/tests/_diagnostic.robot +++ /dev/null @@ -1,55 +0,0 @@ -*** Settings *** -Documentation Temporary diagnostic, round 7: Overlapped Element's field returns empty -... even immediately after a synchronous JS value-set + input-event -... dispatch, suggesting a listener resets it. Tests plain native input, -... JS set without dispatch, JS set with dispatch, and the React "native -... setter" trick, all at the same 1920x1080 window size the real suite -... uses. Not part of the portfolio. -Resource ../resources/pages/playground_page.resource -Suite Setup Open Browser about:blank ${BROWSER} -Suite Teardown Close All Browsers -Test Tags smoke - - -*** Test Cases *** -Dump Overlapped Field Interaction Approaches - Set Window Size 1920 1080 - Go To Playground Page overlapped - ${listeners}= Execute Javascript - ... var el = document.querySelector('#name'); - ... return 'outerHTML=' + el.outerHTML + ' oninput=' + el.oninput + ' onchange=' + el.onchange; - Log FIELD ATTRIBUTES: ${listeners} console=True - - ${set_only}= Execute Javascript - ... var el = document.querySelector('#name'); - ... el.value = 'SetOnly'; - ... return 'value right after plain set, no dispatch: ' + el.value; - Log ${set_only} console=True - ${value_after_set_only}= Get Element Attribute css:#name value - Log VALUE VIA SELENIUM AFTER PLAIN SET (NO DISPATCH): ${value_after_set_only} console=True - - Go To Playground Page overlapped - ${native_setter_result}= Execute Javascript - ... var el = document.querySelector('#name'); - ... var setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set; - ... setter.call(el, 'NativeSetter'); - ... el.dispatchEvent(new Event('input', {bubbles: true})); - ... return 'value right after native setter + dispatch: ' + el.value; - Log ${native_setter_result} console=True - ${value_after_native_setter}= Get Element Attribute css:#name value - Log VALUE VIA SELENIUM AFTER NATIVE SETTER: ${value_after_native_setter} console=True - - Go To Playground Page overlapped - ${click_result}= Run Keyword And Ignore Error Click Element css:#name - Log CLICK RESULT: ${click_result} console=True - ${input_result}= Run Keyword And Ignore Error Input Text css:#name PlainInput - Log PLAIN INPUT TEXT RESULT: ${input_result} console=True - ${value_after_plain_input}= Get Element Attribute css:#name value - Log VALUE AFTER PLAIN INPUT TEXT: ${value_after_plain_input} console=True - - ${overlap_check}= Execute Javascript - ... var el = document.querySelector('#name'); - ... var rect = el.getBoundingClientRect(); - ... var top = document.elementFromPoint(rect.left + rect.width / 2, rect.top + rect.height / 2); - ... return 'isTop=' + (top === el) + ' topTag=' + (top ? top.outerHTML.substring(0, 80) : 'none'); - Log OVERLAP CHECK AT 1920x1080: ${overlap_check} console=True diff --git a/tests/playground/ui_testing_playground.robot b/tests/playground/ui_testing_playground.robot index 9cade02..8df725e 100644 --- a/tests/playground/ui_testing_playground.robot +++ b/tests/playground/ui_testing_playground.robot @@ -186,11 +186,11 @@ Non Breaking Space Button Should Not Match An Exact Text Locator Click Button ${NBSP_BUTTON} Overlapped Name Field Should Accept Text Set Through Javascript - [Documentation] The field is covered by another element, so native Selenium - ... keystrokes never register; setting the value directly through JavaScript and - ... dispatching an input event is the documented workaround. + [Documentation] A permanently positioned element covers the field, so native + ... Selenium clicks and keystrokes are intercepted; setting the value directly + ... through JavaScript is the workaround. Go To Playground Page overlapped - Set Value Via Javascript ${OVERLAPPED_NAME_FIELD} Michelle Austria + Set Value Via Javascript ${OVERLAPPED_NAME_FIELD_SELECTOR} Michelle Austria ${value}= Get Element Attribute ${OVERLAPPED_NAME_FIELD} value Should Be Equal ${value} Michelle Austria