Scenario lab
Selenium Scenario Lab
Every task maps to a quiz topic. Build it yourself first, then open the solution to compare your reasoning step by step.
Lab completion
Mark a task complete once you can write the solution without looking. Completion syncs to your account.
Locate a row by its text and click the action in that row
Given a users table with no ids on the rows, click the Delete button that belongs to the row containing 'ajay@example.com'.
Fixture
A <table> with one <tr> per user. Each row has a <td> with the email and a <td> with Edit / Delete buttons that share the same class.
- 1Inspect the table and confirm no row-level id or data-test attribute exists.
- 2Write an XPath that anchors on the row text, not on a row index.
- 3From that row, walk to the sibling cell that holds the buttons.
- 4Assert the row disappears after the click instead of sleeping.
Anchor with normalize-space(.) so surrounding whitespace does not break the match.
Use ancestor::tr[1] to climb from the matched cell back to its row.
Replace a Thread.sleep with a deterministic wait
A dashboard shows a spinner while loading. The current test sleeps 5 seconds and still fails ~1 in 10 runs. Make it deterministic.
Fixture
div.spinner is present in the DOM while loading and removed afterwards. The KPI value renders into [data-test='revenue'] only when data arrives.
- 1Delete the sleep and reproduce the failure to see what the test actually races against.
- 2Wait for the spinner to disappear, then for the data to be non-empty.
- 3Move the wait into the page object so no test ever waits inline.
- 4Run the test 20 times in a loop to prove it is stable.
Two conditions matter here: loading finished AND content rendered.
ExpectedConditions can be composed with a lambda when the built-ins are not enough.
Drag a card between columns on an HTML5 board
Actions.dragAndDrop does nothing on the Kanban board. Move the card 'Write tests' from Backlog to Done reliably.
Fixture
The board uses HTML5 drag events (dragstart / dragover / drop). Columns are [data-column='backlog'] and [data-column='done'].
- 1Confirm the failure: run dragAndDrop and observe the card never moves.
- 2Retry with a slower composite Actions sequence (click-hold, move in steps, pause, release).
- 3If the app ignores synthetic mouse moves, dispatch the HTML5 events through JavascriptExecutor.
- 4Assert the card is now a child of the Done column.
HTML5 drag and drop is event-based, not mouse-position based.
A single moveToElement often lands before the app registers dragover — add intermediate moves and pauses.
Fill a payment form inside a nested iframe, then a new tab
Checkout embeds the card form in an iframe inside another iframe, and the receipt opens in a new tab. Complete the flow and assert the receipt number.
Fixture
Outer iframe #payment, inner iframe #card-fields, and a Pay button in the parent document. The receipt opens with target=_blank.
- 1Switch into the outer frame, then the inner frame, and type the card details.
- 2Return to the top document before clicking Pay, which lives outside both frames.
- 3Capture the original window handle, then switch to the newly opened one.
- 4Assert the receipt number and switch back so later tests are not stranded.
Frame context is not reset automatically — defaultContent() is required before touching parent elements.
Diff the window handle set instead of assuming the new tab is the last handle.
Make the suite safe to run 10-way parallel on Grid
The suite passes serially and fails randomly at thread-count 10. Remove the shared state and point it at Grid.
Fixture
TestNG suite, a static WebDriver field in BaseTest, and one shared login user across all tests.
- 1Find every static mutable field — driver, test data, report context.
- 2Move the driver into a ThreadLocal created in @BeforeMethod and removed in @AfterMethod.
- 3Generate per-test data so two threads never mutate the same record.
- 4Set parallel='methods' with thread-count and run against RemoteWebDriver.
ThreadLocal.remove() in @AfterMethod prevents leaks on reused thread-pool threads.
Any test that asserts on a global list or count is a shared-state test — isolate it or tag it serial.
Attach a screenshot, page source and logs to every failure
Failures in CI say only 'element not found'. Produce a failure artefact bundle automatically, without touching a single test.
Fixture
TestNG + a reporting library. Driver is available through DriverFactory.get().
- 1Implement an ITestListener so the behaviour is opt-in at suite level, not per test.
- 2On failure, capture a screenshot, the page source and the browser console log.
- 3Name artefacts with test name plus timestamp so parallel runs do not overwrite each other.
- 4Register the listener in testng.xml and confirm the artefacts appear in the CI archive.
Guard the capture in try/catch — a dead driver must not replace the real failure with a listener error.
Console logs need loggingPrefs / the BiDi log handler enabled on the browser options.