CoreHRx Jobs

Apply in one click, save jobs and take free mock tests.

Register free Log in
Hiring? Post jobs with CoreHRx
My account
user

View & update profile
Interview guide

Selenium Interview Questions and Answers: 60 Questions from Easy to Hard

This guide is for freshers and experienced test engineers in India preparing for a Selenium automation interview, whether it is a campus drive, a QA role at an IT services company or an SDET round at a product startup. It has 60 questions in three levels, all for Selenium 4. Easy covers WebDriver basics, locators, waits, alerts, frames and dropdowns. Medium covers what people with one to four years of experience are asked: flaky waits, stale elements, windows, Actions, the Page Object Model, TestNG and pytest. Hard covers WebDriver internals, Selenium Grid, parallel runs, CI, framework design and when not to automate. Code examples are in Java or Python, and each question says which. Answer each question aloud before reading ours, then take the mock test.

  • 60 questions, 3 levels
  • Updated
  • CoreHRx Jobs

What Selenium interviews cover

  • WebDriver basics: how a script talks to the browser through a driver, opening pages, finding elements and the difference between close and quit. Almost every fresher round starts here.
  • Locators and waits: id, CSS and XPath, and implicit, explicit and fluent waits. Interviewers often show a small HTML snippet and ask you to write a locator on the spot.
  • Browser situations: frames, multiple windows and tabs, JavaScript alerts, select and custom dropdowns, mouse and keyboard actions, and file uploads.
  • Framework skills: the Page Object Model, TestNG or pytest structure, data-driven tests, reports and screenshots on failure.
  • For experienced roles: Selenium Grid, parallel execution, CI pipelines, flaky test analysis and deciding what should not be tested through the UI at all.

How to prepare (freshers and experienced)

  • Freshers: pick one stack, Java with TestNG or Python with pytest, and automate a small flow end to end on a practice site: login, search, a form and logout.
  • Practise CSS and XPath in the browser DevTools console with $$() and $x() before the interview, so you can write locators without trial and error.
  • Learn the Selenium 4 way of doing things: find_element(By...) in Python, Duration-based waits in Java, Selenium Manager and relative locators. Old Selenium 3 syntax is a red flag.
  • Experienced engineers: be ready to explain the framework you built with numbers: suite size, run time, flaky rate, how it runs in CI and what you changed to make it stable.
  • Keep a short list of real bugs your automation caught and failures you debugged; interviewers ask for these stories more than for definitions.

Common mistakes and interview-day tips

  • Do not answer every timing problem with Thread.sleep or time.sleep. Say which explicit wait condition you would use and why.
  • Avoid absolute XPath and index-based locators in your answers; explain how you would pick a stable attribute or ask developers for a test id.
  • Do not claim Selenium can solve a CAPTCHA, read an OTP from a real phone or drive the desktop file dialog. Explain the test-environment approach instead.
  • When asked about a framework, talk about design choices and trade-offs, not only the tool names on your resume.
  • If you are unsure of an exact method name, say so and describe what the method does; a correct concept beats a confident wrong API.

Selenium interview questions: Easy questions (freshers)

20 questions

1. What is Selenium, and what are its main components?

Selenium is an open-source project for automating web browsers, used mainly to test web applications through the real user interface. Its main parts are Selenium WebDriver, a library with bindings for Java, Python, C#, JavaScript and Ruby that drives the browser; Selenium Grid, which runs tests on many machines and browsers in parallel; and Selenium IDE, a browser extension that records and plays back simple scripts. Most jobs mean WebDriver plus a test framework. On its own, Selenium only drives browsers: it does not test APIs or desktop software.

2. How does Selenium 4 WebDriver talk to the browser? (Python example)

Your test calls the language binding, here the Python selenium package. The binding sends each command as an HTTP request in the W3C WebDriver protocol to a browser driver such as chromedriver or geckodriver. The driver turns the command into the browser's own automation calls and sends the result back as JSON. So a click in your script becomes a request to the driver, which clicks in the real browser. Because Selenium 4 uses the W3C standard, every major browser vendor supports the same commands. quit() ends the session and stops the driver.

Example
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()      # starts chromedriver and Chrome
try:
    driver.get("https://jobs.example.com")
    print(driver.title)
    driver.find_element(By.NAME, "q").send_keys("QA engineer")
finally:
    driver.quit()                # ends the session, stops the driver

3. What changed in Selenium 4 compared with Selenium 3?

The biggest change is that Selenium 4 speaks the W3C WebDriver standard instead of the older JSON Wire Protocol, so commands behave more consistently across browsers. It also added relative locators such as above, below and near, a command to open a new tab or window, access to the Chrome DevTools Protocol, a rewritten Selenium Grid, and Selenium Manager (from 4.6) to set up drivers automatically. Old APIs were cleaned up: Python's find_element_by_id style methods were removed, and Java waits take a Duration.

4. Do you still need to download chromedriver and set its path in Selenium 4?

Usually not. Since Selenium 4.6, the bindings include Selenium Manager, which runs when no driver is found on the PATH or in a system property. It checks the installed browser version, downloads a matching driver, caches it and starts it, so new ChromeDriver() in Java or webdriver.Chrome() in Python just works. Recent 4.x releases can also fetch a browser if none is installed. Teams on locked-down networks still keep approved drivers themselves. A common mistake is an old System.setProperty line pointing to an outdated driver, which is used instead of Selenium Manager.

5. Which locator strategies does Selenium offer, and in what order do you prefer them? (Java)

Selenium has eight: id, name, className, tagName, linkText, partialLinkText, cssSelector and xpath. I prefer a unique, stable id or a test attribute such as data-testid first, then name, then a short CSS selector, and XPath when I need visible text or have to move from one element to a related one, such as from a label to its field. linkText suits links whose text is fixed. I avoid generated class names and anything based on position or layout, because those break when the design changes even though the feature still works.

Example
driver.findElement(By.id("email"));
driver.findElement(By.name("password"));
driver.findElement(By.cssSelector("[data-testid='login-submit']"));
driver.findElement(By.xpath(
        "//label[normalize-space()='City']/following-sibling::select"));
driver.findElement(By.linkText("Forgot password?"));
int rows = driver.findElements(By.tagName("tr")).size();

6. What is the difference between findElement and findElements?

findElement returns the first matching element and throws NoSuchElementException when nothing matches. findElements returns a list of all matches and simply returns an empty list when nothing matches, with no exception. Use findElement when the element must be there, so a missing element fails the test with a clear error. Use findElements to count rows or to check that something is absent. One trap: with an implicit wait set, findElements waits the full implicit timeout before it returns an empty list, so absence checks become slow.

7. What is the difference between absolute and relative XPath?

An absolute XPath starts with a single slash at the root and lists every step, such as /html/body/div[2]/div/form/div[3]/input. It breaks as soon as a developer adds a wrapper div or moves a section. A relative XPath starts with // and searches the whole page for a node that matches a condition, such as //input[@id='email']. Relative XPath is shorter, easier to read and survives layout changes, so it is the normal choice. DevTools often copies an index-heavy path; treat it as a starting point and rewrite it around stable attributes or text.

Example
Absolute: breaks when the layout changes
/html/body/div[2]/div/form/div[3]/input

Relative: anchored on stable attributes or text
//input[@id='email']
//button[normalize-space()='Apply now']
//label[normalize-space()='Email']/following-sibling::input

8. How do CSS selectors compare with XPath as locators?

CSS selectors are short and readable, and are the usual choice for id, class, attribute and parent-to-child paths. XPath can match visible text, which CSS cannot, and it can move up or sideways with axes such as ancestor and following-sibling, which CSS supports only partly through the newer :has() selector. Speed differences are small in modern browsers, so choose for readability and stability. A common mistake is writing :contains() in a CSS selector: it is a jQuery extension, not CSS, so the browser rejects it as an invalid selector.

Example
#email                  element with id email
.btn.primary            element that has both classes
input[name='phone']     attribute equals a value
form#signup > button    button that is a direct child of the form
a[href^='/jobs/']       href starts with /jobs/
li:nth-child(2)         li that is the second child of its parent

9. What is an implicit wait, and what is its default value?

An implicit wait tells the driver to keep polling for up to a set time whenever it looks for an element, before it gives up with NoSuchElementException. It is set once per session and applies to every find call, for example driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5)) in Java or driver.implicitly_wait(5) in Python. The default is zero, so without it Selenium fails at once if the element is not there yet. It only waits for the element to exist in the DOM, not to be visible or clickable, so it does not solve most timing problems.

10. What is an explicit wait? Show one in Python.

An explicit wait pauses until a specific condition is true, up to a timeout. You create WebDriverWait with the driver and a timeout and pass a condition from expected_conditions, such as element_to_be_clickable or visibility_of_element_located. It checks the condition every half second by default and returns as soon as it is met, so a fast page does not wait the full time, and until() returns the element so you can use it directly. If the timeout passes, it raises TimeoutException. It is the main tool for pages that load content dynamically.

Example
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
button = wait.until(EC.element_to_be_clickable((By.ID, "download-payslip")))
button.click()

11. Why is Thread.sleep or time.sleep a bad way to wait in Selenium tests?

A fixed sleep always waits the full time, even when the page is ready in 200 milliseconds, so a suite with hundreds of sleeps becomes very slow. It also guarantees nothing: when the server is slower than usual, say on a busy CI machine, the sleep is too short and the test fails at random. The test ends up both slow and flaky. An explicit wait for the real condition, such as a button becoming clickable or a spinner disappearing, returns as soon as it is true and fails with a clear timeout message when it is not.

12. What is the difference between driver.close() and driver.quit()?

close() closes only the current window or tab. If other windows are open, the session continues; closing the last window also ends the session, but the driver process can keep running. quit() closes every window, ends the session and stops the driver process. Always call quit() in teardown, in a finally block, an @AfterMethod(alwaysRun = true) or after the yield of a pytest fixture, otherwise failed tests leave browsers running and the CI machine runs out of memory. After close() on a tab, switch to another window handle before sending more commands.

13. How do you select a value from a dropdown built with the select tag? (Java)

Wrap the element in Selenium's Select class and choose by visible text, by value attribute or by index. selectByVisibleText is the most readable and matches what the user sees, selectByValue is stable when labels are translated, and selectByIndex is fragile because adding an option shifts the positions. getFirstSelectedOption returns the chosen option, getOptions lists them all, and deselectAll works only on a multi-select. Select works only on a real select element; on a div-based custom dropdown it throws UnexpectedTagNameException.

Example
Select state = new Select(driver.findElement(By.id("state")));
state.selectByVisibleText("Karnataka");   // by the text the user sees
// state.selectByValue("KA");             // or by the value attribute
// state.selectByIndex(3);                // or by position (fragile)
String chosen = state.getFirstSelectedOption().getText();
int count = state.getOptions().size();

14. How do you handle a JavaScript alert or confirm box? (Python)

A JavaScript alert, confirm or prompt is not part of the page DOM, so no locator can find it. You switch to it: driver.switch_to.alert in Python, driver.switchTo().alert() in Java. Then text reads the message, accept() presses OK, dismiss() presses Cancel and send_keys() types into a prompt. Wait for it with alert_is_present, because it often appears after a server call. If another command runs while an alert is open, it fails with UnexpectedAlertPresentException. A modal built from div elements is ordinary page content and is handled with locators.

Example
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver.find_element(By.ID, "delete-leave").click()
alert = WebDriverWait(driver, 5).until(EC.alert_is_present())
print(alert.text)        # "Delete this leave request?"
alert.accept()           # OK; alert.dismiss() would press Cancel

15. How do you work with an element inside an iframe? (Java)

An iframe holds a separate document, so the driver cannot see its elements until you switch into it. Use driver.switchTo().frame() with the frame's name or id, a WebElement for the iframe, or an index; the WebElement is the most reliable choice. Work inside the frame, then call switchTo().defaultContent() to return to the main page, or parentFrame() to go up one level in nested frames. Payment widgets, rich text editors and embedded forms are typical examples. If a locator that looks right throws NoSuchElementException, check whether the element sits in a frame.

Example
WebElement frame = driver.findElement(By.cssSelector("iframe#payment-frame"));
driver.switchTo().frame(frame);
driver.findElement(By.id("upi-id")).sendKeys("asha.test@upi");
driver.findElement(By.id("pay-btn")).click();

driver.switchTo().defaultContent();       // back to the main page
String status = driver.findElement(By.id("order-status")).getText();

16. What do getText, getAttribute, isDisplayed, isEnabled and isSelected return? (Python)

text (getText in Java) returns the visible text of an element, so it is empty for an input box. To read what is typed in a field, use get_attribute('value') or get_property('value'). Selenium 4 added get_dom_attribute, which returns the attribute exactly as written in the HTML, or None if it is absent. is_displayed() says whether the element is visible, is_enabled() whether it is usable rather than disabled, and is_selected() whether a checkbox, radio button or option is chosen. A common mistake is asserting on the text of an input and getting an empty string.

Example
city = driver.find_element(By.ID, "city")
city.send_keys("Pune")
print(repr(city.text))                   # '' : an input has no text
print(city.get_attribute("value"))       # Pune
print(city.get_property("value"))        # Pune : the live DOM property
print(city.get_dom_attribute("value"))   # the HTML attribute, or None

agree = driver.find_element(By.ID, "agree-terms")
print(agree.is_displayed(), agree.is_enabled(), agree.is_selected())

17. Which Selenium exceptions do you see most often, and what does each usually mean?

NoSuchElementException: the locator matched nothing, often a wrong locator, a missing wait or an element inside a frame. TimeoutException: an explicit wait's condition never became true. StaleElementReferenceException: the stored element was removed or re-rendered. ElementNotInteractableException: the element exists but is hidden or has no size. ElementClickInterceptedException: another element, such as a loader or banner, would get the click. NoSuchFrameException and NoSuchWindowException: a wrong switch target. The exception name usually points to the fix.

18. What are the main TestNG annotations, and in what order do they run? (Java)

The order is @BeforeSuite, @BeforeTest, @BeforeClass, @BeforeMethod, then the @Test method, then @AfterMethod, @AfterClass, @AfterTest and @AfterSuite. @BeforeMethod and @AfterMethod run around every test method, so they are the usual place to start and quit the browser. @BeforeTest is often misunderstood: it runs once before each test tag in testng.xml, not before each @Test method. Use alwaysRun = true on teardown methods so the browser is closed even after a failure or skip. Assertions come from org.testng.Assert.

Example
public class LoginTest {
    private WebDriver driver;

    @BeforeMethod
    public void setUp() {
        driver = new ChromeDriver();
        driver.get("https://hr.example.com/login");
    }

    @Test(groups = "smoke")
    public void validLoginOpensDashboard() {
        new LoginPage(driver).loginAs("qa.asha", System.getenv("QA_PASSWORD"));
        Assert.assertTrue(driver.getCurrentUrl().contains("/dashboard"));
    }

    @AfterMethod(alwaysRun = true)
    public void tearDown() {
        if (driver != null) {
            driver.quit();
        }
    }
}

19. What is the Page Object Model, and why do teams use it? (Python)

The Page Object Model is a design pattern in which each page, or major part of a page, gets a class that holds its locators and offers methods for what a user can do there, such as login_as or apply_leave. Tests call those methods instead of using locators directly. When the UI changes, you fix one page class instead of fifty tests, and the tests read like business steps. A method that leads to another page returns that page's object. Keep assertions in the tests and test data out of page classes, so one page class serves many scenarios.

Example
from selenium.webdriver.common.by import By

class LoginPage:
    USERNAME = (By.ID, "username")
    PASSWORD = (By.ID, "password")
    SUBMIT = (By.CSS_SELECTOR, "button[type='submit']")

    def __init__(self, driver):
        self.driver = driver

    def login_as(self, user, password):
        self.driver.find_element(*self.USERNAME).send_keys(user)
        self.driver.find_element(*self.PASSWORD).send_keys(password)
        self.driver.find_element(*self.SUBMIT).click()
        return DashboardPage(self.driver)

# In a test: LoginPage(driver).login_as("qa.ravi", password).open_leave_tab()

20. Which test cases should be automated with Selenium, and which should not?

Automate tests that run often and have a clear, stable expected result: smoke tests, regression of core flows such as login, search, checkout or leave approval, and data-driven checks with many input combinations. Do not automate one-time checks, features that change every sprint, exploratory and usability testing, visual judgement such as whether a layout looks right, or anything that needs a real CAPTCHA or an OTP sent to a real phone. Also avoid UI tests for logic an API or unit test can check faster. Automate when a test will run many times and its result is clear.

Ready to check yourself? Take the free Selenium mock test

Selenium interview questions: Medium questions (1-3 years)

20 questions

21. What is the difference between presenceOfElementLocated, visibilityOfElementLocated and elementToBeClickable?

presenceOfElementLocated waits only until the element exists in the DOM, even if it is hidden. visibilityOfElementLocated also requires it to be displayed with a height and width greater than zero. elementToBeClickable requires it to be visible and enabled. Use presence for elements you only read or that are hidden by design, visibility before reading text a user would see, and clickable before a click. None of them checks whether another element covers it, so a loader overlay can still cause ElementClickInterceptedException; wait for the overlay to go as well.

22. When would you use FluentWait, and how do you configure it? (Java)

FluentWait lets you set the timeout, the polling interval and the exceptions to ignore, and wait on any condition you write as a lambda. It suits slow back-end updates, such as a payment status that changes from PENDING to SUCCESS after some seconds, where checking every 500 milliseconds is wasteful. The lambda returns null or false to keep waiting and any other value to stop. WebDriverWait is itself a FluentWait with WebDriver defaults. A classic bug is importing java.util.NoSuchElementException instead of the Selenium one, so the ignore rule never matches.

Example
Wait<WebDriver> wait = new FluentWait<>(driver)
        .withTimeout(Duration.ofSeconds(30))
        .pollingEvery(Duration.ofSeconds(2))
        .ignoring(NoSuchElementException.class);  // org.openqa.selenium

String status = wait.until(d -> {
    String text = d.findElement(By.id("payment-status")).getText();
    return text.equals("SUCCESS") ? text : null;   // null = keep waiting
});

23. Why should you not mix implicit and explicit waits?

The Selenium documentation warns that mixing them can cause unpredictable wait times. An explicit wait calls find commands repeatedly, and each of those calls can itself wait for the full implicit timeout, so the real time is no longer what either setting says. Conditions that expect an element to be gone become very slow, because every check first waits out the implicit timeout before it can report the element missing. The usual practice is to keep the implicit wait at zero and use explicit waits where needed. Pick one approach and build it into the framework.

24. A test throws StaleElementReferenceException after applying a filter on a table. Why, and how do you fix it? (Python)

A WebElement is a reference to one node in the DOM. When the filter reloads or re-renders the table, the old row nodes are removed and new ones are created, so the stored reference points to nothing and Selenium raises StaleElementReferenceException. The fix is to wait for the change and then find the elements again: wait until the old row is stale, then look up the new rows. In page objects, store locators rather than WebElements so each action finds the element fresh. Catching the exception and retrying blindly hides the real timing problem.

Example
first_row = driver.find_element(By.CSS_SELECTOR, "#leave-table tbody tr")
driver.find_element(By.ID, "filter-pending").click()   # table re-renders

wait = WebDriverWait(driver, 10)
wait.until(EC.staleness_of(first_row))     # the old row is detached
rows = wait.until(EC.presence_of_all_elements_located(
    (By.CSS_SELECTOR, "#leave-table tbody tr")))
print(rows[0].text)                        # fresh reference, no error

25. A click fails with ElementClickInterceptedException. How do you debug and fix it? (Python)

The error message names the element that would receive the click, which is the key clue. Usually it is a loading overlay, a toast, a cookie banner or a sticky header covering the button. Wait for the overlay to disappear, close the banner, or scroll the element to the centre of the screen before clicking. Remember that element_to_be_clickable checks only visible and enabled, not covered. Do not switch to a JavaScript click just to make the test pass: a real user cannot click through the overlay either, so the JavaScript click can hide a genuine bug.

Example
wait = WebDriverWait(driver, 10)
wait.until(EC.invisibility_of_element_located(
    (By.CSS_SELECTOR, ".spinner-overlay")))
wait.until(EC.element_to_be_clickable((By.ID, "apply-leave"))).click()

26. Write a locator for the Edit button in the row of the employee Priya Sharma.

Anchor the locator on something unique and stable, the employee's name, and then move to the button in the same row. This XPath finds the tr that has a td whose trimmed text is Priya Sharma, and then the Edit button inside that row; on this table it matches exactly one button. It keeps working when rows are sorted, added or deleted, unlike (//button[normalize-space()='Edit'])[2], which depends on position. normalize-space() also ignores extra spaces and line breaks. If developers can put a data-emp-id attribute on each row, a CSS selector on it is even more stable.

Example
<table id="employees">
  <tr>
    <td>Rahul Verma</td>
    <td>Pune</td>
    <td><button class="btn edit">Edit</button></td>
  </tr>
  <tr>
    <td> Priya Sharma </td>
    <td>Bengaluru</td>
    <td><button class="btn edit">Edit</button></td>
  </tr>
</table>

//table[@id='employees']//tr[td[normalize-space()='Priya Sharma']]//button[normalize-space()='Edit']

27. Why can //button[contains(@class,'btn')] and //button[text()='Save'] pick the wrong elements or none?

contains(@class,'btn') is a substring test, so it also matches btn-link, btn-sm or submit-btn; in this snippet it matches both buttons. To match the whole class name in XPath, use contains(concat(' ', normalize-space(@class), ' '), ' btn '), or simply the CSS selector button.btn, which matches class tokens. text()='Save' compares only the button's own text nodes, and here Save sits inside a span, so it matches nothing. normalize-space()='Save' uses the whole text of the element and its children with spaces trimmed, so it finds exactly the Save button.

Example
<div class="actions">
  <button class="btn-link">Cancel</button>
  <button class="btn primary">
    <span>Save</span>
  </button>
</div>

//button[contains(@class,'btn')]        2 matches (Cancel too)
//button[text()='Save']                 0 matches
//button[normalize-space()='Save']      1 match
//button[contains(concat(' ', normalize-space(@class), ' '), ' btn ')]   1 match

28. How do you locate elements whose ids change on every page load, such as emp_48213_name?

Look for the part that does not change. The best option is a dedicated test attribute such as data-testid, agreed with the developers. Next come stable attributes such as name or aria-label, or the text of the field's label. If only part of the id is fixed, CSS supports prefix and suffix matching, input[id^='emp_'][id$='_name']. Browsers implement XPath 1.0, which has starts-with() and contains() but no ends-with(), so an XPath using ends-with fails as invalid. Avoid position-based locators, and check in DevTools that the final locator matches exactly one element.

29. How do you switch to a new tab that opens after a click, and come back? (Java)

Each window or tab has a handle string. Save the current handle, click the link, wait until the number of windows grows, then loop over getWindowHandles() and switch to the handle that is not the original. When you are done, close the new tab and switch back to the saved handle; the driver does not move back by itself, and commands fail with NoSuchWindowException until you switch. getWindowHandles() returns a Set, so do not rely on its order. Selenium 4 can also open a fresh tab directly with driver.switchTo().newWindow(WindowType.TAB).

Example
String original = driver.getWindowHandle();
driver.findElement(By.linkText("View payslip")).click();

new WebDriverWait(driver, Duration.ofSeconds(10))
        .until(ExpectedConditions.numberOfWindowsToBe(2));
for (String handle : driver.getWindowHandles()) {
    if (!handle.equals(original)) {
        driver.switchTo().window(handle);
        break;
    }
}
// ... check the payslip in the new tab ...
driver.close();
driver.switchTo().window(original);

30. A page has an iframe inside another iframe. How do you reach an element in the inner one, and what goes wrong most often?

Switch one level at a time: first into the outer frame, then into the inner frame from there, because a frame switch only looks at frames in the current document. parentFrame() moves up one level and defaultContent() goes straight back to the top page. The common mistakes are switching to the inner frame from the top page, which raises NoSuchFrameException, and forgetting to switch back, so the next step cannot find main-page elements. Frames often load late, so use frameToBeAvailableAndSwitchToIt, which waits for a frame and switches into it in one step.

31. How do you automate an auto-suggest box, such as a city search that shows suggestions as you type?

Type a few characters, wait for the suggestion list, then click the option by its text instead of pressing the Down arrow a fixed number of times, because the order of suggestions can change. Locate the option inside the list container, for example a ul with role listbox, and wait for it to be clickable, since suggestions arrive from a server call. After selecting, assert the final value of the input, not just that a click happened. Avoid extra clicks between typing and selecting, as the list may close when focus moves. Div-based dropdowns work the same way.

32. When do you need the Actions class, and how do you use it? (Java)

Use Actions for interactions that a plain click or sendKeys cannot express: hovering to open a menu, right-click, double-click, drag and drop, click and hold, and key combinations such as Ctrl+A. You chain the steps and finish with perform(), which builds the chain and sends it to the browser; forgetting perform() means nothing happens. Selenium 4 also added wheel actions such as scrollToElement. Hover menus are a common source of flakiness, so wait for the submenu item to be clickable after the hover. In Python the same API is called ActionChains.

Example
Actions actions = new Actions(driver);
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

actions.moveToElement(driver.findElement(By.id("reports-menu"))).perform();
wait.until(ExpectedConditions.elementToBeClickable(
        By.linkText("Attendance report"))).click();

WebElement card = driver.findElement(By.id("task-142"));
WebElement done = driver.findElement(By.id("column-done"));
actions.dragAndDrop(card, done).perform();

actions.keyDown(Keys.CONTROL).sendKeys("a").keyUp(Keys.CONTROL).perform();

33. When is JavascriptExecutor the right tool, and when is it a warning sign? (Java)

JavascriptExecutor runs JavaScript in the page and returns the result to the test. It is justified for things WebDriver has no command for: scrolling an element to the centre, reading document.readyState or an application flag, or collecting many values in one call. It is a warning sign when used to click or type past an error, because a JavaScript click skips the checks a real click goes through, such as visibility and overlays, so the test can pass while users are blocked. Pass elements as arguments[0], and note that JavaScript numbers come back as Long or Double in Java.

Example
JavascriptExecutor js = (JavascriptExecutor) driver;
WebElement submit = driver.findElement(By.id("submit-claim"));

js.executeScript("arguments[0].scrollIntoView({block: 'center'});", submit);
String state = (String) js.executeScript("return document.readyState;");
Long rows = (Long) js.executeScript(
        "return document.querySelectorAll('#claims tbody tr').length;");

// Warning sign: forces a click that a real user may not be able to make
// js.executeScript("arguments[0].click();", submit);

34. What does a good page object look like in a real framework? (Java)

It keeps locators as private By fields, takes the driver in its constructor and exposes methods named after user actions, such as apply or toastText. Waits live inside the page methods, so tests stay short. Methods return the page the user lands on, which allows chaining and makes navigation visible in the test. Storing By locators instead of WebElements avoids stale references after re-renders. PageFactory with @FindBy is an older style that creates lazy proxies, but adding @CacheLookup brings stale element errors back on dynamic pages. Assertions belong in tests.

Example
public class LeavePage {
    private final WebDriver driver;
    private final WebDriverWait wait;
    private final By leaveType = By.id("leave-type");
    private final By fromDate = By.name("from");
    private final By submit = By.cssSelector("[data-testid='apply-leave']");
    private final By toast = By.cssSelector(".toast-message");

    public LeavePage(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    public LeavePage apply(String type, String from) {
        new Select(driver.findElement(leaveType)).selectByVisibleText(type);
        driver.findElement(fromDate).sendKeys(from);
        driver.findElement(submit).click();
        return this;
    }

    public String toastText() {
        return wait.until(ExpectedConditions
                .visibilityOfElementLocated(toast)).getText();
    }
}

35. How do you write a data-driven test with TestNG's DataProvider? (Java)

A DataProvider method returns rows of parameters, usually as Object[][], and the test runs once per row, with each run reported as a separate result. This avoids copying the same test for every input, such as invalid login combinations and their error messages. Rows can come from code, a CSV or JSON file, an Excel sheet read with Apache POI, or a database. Give every row a clear expected result, and set parallel = true on the DataProvider only if the rows are fully independent. In pytest the same idea is @pytest.mark.parametrize.

Example
@DataProvider(name = "badLogins")
public Object[][] badLogins() {
    return new Object[][] {
        {"", "Secret@1", "Username is required"},
        {"ravi.k", "", "Password is required"},
        {"ravi.k", "wrong-pass", "Invalid username or password"},
    };
}

@Test(dataProvider = "badLogins")
public void showsLoginError(String user, String pass, String message) {
    LoginPage page = new LoginPage(driver).open();
    page.loginAs(user, pass);
    Assert.assertEquals(page.errorText(), message);
}

36. How do you structure Selenium tests with pytest fixtures? (Python)

Put browser setup in a fixture, usually in conftest.py, so each test receives a ready driver as an argument. Code before yield is setup and code after yield is teardown, and the teardown runs even when the test fails, so the browser always quits. The scope decides sharing: function scope gives each test a clean browser, while module or session scope is faster but lets one test's state leak into the next. Use parametrize to run a test with several inputs, and markers such as smoke to pick subsets with pytest -m smoke.

Example
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By

@pytest.fixture
def driver():
    options = webdriver.ChromeOptions()
    options.add_argument("--headless=new")
    drv = webdriver.Chrome(options=options)
    yield drv              # the test runs here
    drv.quit()             # teardown, also after a failure

@pytest.mark.smoke
@pytest.mark.parametrize("city", ["Pune", "Chennai", "Jaipur"])
def test_search_by_city(driver, city):
    driver.get("https://jobs.example.com/search?city=" + city)
    assert city in driver.find_element(By.TAG_NAME, "h1").text

37. How do you use testng.xml for groups and parallel runs, and what is the difference between priority and dependsOnMethods?

testng.xml lists the classes to run, the groups to include or exclude, parameters such as the browser, and parallel settings: parallel can be methods, classes, tests or instances, with a thread-count. Tests join a group through @Test(groups = "smoke"). priority only orders methods, lower numbers first with 0 as the default, and later tests still run if one fails. dependsOnMethods creates a hard link: if the method it depends on fails, the dependent test is skipped. Use dependencies sparingly; independent tests are easier to run in parallel and to rerun.

38. How do you capture a screenshot automatically when a test fails? (Python)

Hook into the framework's failure event instead of adding try and except to every test. In pytest, a pytest_runtest_makereport hook in conftest.py sees each test's result and can save a screenshot when the call phase fails. In TestNG, an ITestListener's onTestFailure does the same with ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE). Name files after the test, save the page source and URL too, and attach them to the report. Create the folder first: save_screenshot returns False instead of raising an error when the folder is missing.

Example
# conftest.py
import os
import pytest

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    report = outcome.get_result()
    if report.when == "call" and report.failed:
        driver = item.funcargs.get("driver")
        if driver is not None:
            os.makedirs("screenshots", exist_ok=True)
            driver.save_screenshot(f"screenshots/{item.name}.png")
            with open(f"screenshots/{item.name}.html", "w") as f:
                f.write(driver.page_source)

39. How do you upload a file in Selenium, and what changes when tests run on a remote Grid?

Selenium cannot control the operating system's file dialog, so do not click the Browse button. Find the input element of type file and call sendKeys with the absolute path of the file; the browser attaches it as if the user had picked it. Build the path from the project folder so it works on every machine. On a remote Grid the file is on the test machine, not on the node, so in Java set a LocalFileDetector on the RemoteWebDriver, and Selenium copies the file to the node first. Desktop tools such as AutoIt or Robot break in headless and remote runs.

40. A test passes on your laptop but fails in the CI pipeline. What do you check first? (Python)

Start from the evidence: the screenshot, page source and logs from the failed run. Then check the usual differences. CI often runs headless, where the default window can be smaller, so responsive layouts hide menus; set an explicit window size. CI machines are slower, which exposes missing waits. Test data may differ or be shared with parallel jobs. Browser versions, time zone and locale can differ too, such as dates shown in UTC instead of IST. Reproduce locally with the same headless options before changing the test, and never fix it with a sleep.

Example
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--window-size=1920,1080")   # same layout as desktop
driver = webdriver.Chrome(options=options)

Ready to check yourself? Take the free Selenium mock test

Selenium interview questions: Hard questions (experienced)

20 questions

41. What happens on the wire when a Selenium 4 script finds and clicks an element?

Each command is an HTTP request defined by the W3C WebDriver spec. Creating the driver sends POST /session with the capabilities, and the driver replies with a session id. A find sends POST /session/{id}/element with a strategy and a value, and the reply holds an element reference under a fixed key. A click is POST /session/{id}/element/{element id}/click. The standard defines only five strategies: css selector, link text, partial link text, tag name and xpath, so the bindings turn By.ID, By.NAME and By.CLASS_NAME into CSS selectors.

Example
POST /session
{"capabilities": {"alwaysMatch": {"browserName": "chrome"}}}
reply: {"value": {"sessionId": "8f2c...", "capabilities": {...}}}

POST /session/8f2c.../element
{"using": "css selector", "value": "[id=\"login\"]"}
reply: {"value": {"element-6066-11e4-a52e-4f735466cecf": "a91d..."}}

POST /session/8f2c.../element/a91d.../click
{}
reply: {"value": null}

(Python's find_element(By.ID, "login") sends the css selector shown above)

42. How does WebDriver decide whether an element can be clicked, and what does that mean for flaky clicks?

The W3C Element Click command first scrolls the element into view, then works out its in-view centre point. If the element cannot be brought into view, it returns element not interactable, and if another element is on top of that centre point, it returns element click intercepted. Only then does it send real pointer events at that point. So a click fails when an overlay, sticky header or running animation covers the centre at that moment, even though the element itself is visible. The fixes are waiting for the overlay or animation to finish and scrolling it clear of fixed headers.

43. Explain the Selenium Grid 4 architecture and its run modes.

Grid 4 is split into components. The Router receives every request, the New Session Queue holds new session requests, the Distributor picks a Node with a free slot that matches the capabilities, the Session Map records which Node owns each session, the Event Bus carries messages between them, and Nodes run the browsers. Standalone mode runs all of it in one process, good for a laptop or a small CI job. Hub and Node mode puts the central parts in a Hub with separate Nodes. Distributed mode runs each part on its own for large grids.

Example
# Standalone: every Grid component in one process
java -jar selenium-server-<version>.jar standalone

# Hub and Node: the hub on one machine, nodes on others
java -jar selenium-server-<version>.jar hub
java -jar selenium-server-<version>.jar node --hub http://<hub-ip>:4444

# Is the Grid up, and which slots are free?
curl http://<hub-ip>:4444/status

44. How do you run the same tests on Chrome, Firefox and Edge through a Grid?

Write a small driver factory that reads the browser name and Grid URL from configuration, builds the matching Options object, such as ChromeOptions or FirefoxOptions, and creates a RemoteWebDriver. Tests and page objects never create drivers themselves, so switching browser is a configuration change. In Selenium 4 you pass Options objects instead of the old DesiredCapabilities, and the Distributor sends each session to a Node with that browser. Record the browser version of every run in the report, because a silent browser update is a common cause of new failures.

45. Why do parallel Selenium tests need ThreadLocal drivers, and how do you implement it? (Java)

A WebDriver instance is not thread-safe, and a static driver field shared by the suite means parallel threads send commands to the same browser, causing random failures that vanish when tests run alone. ThreadLocal gives each thread its own driver: create it in @BeforeMethod, read it through a getter in tests and page objects, and quit and remove it in @AfterMethod. remove() matters because TestNG reuses pool threads. Tests must also be independent in data, for example each one uses its own employee record, or parallel runs still collide.

Example
public final class Drivers {
    private static final ThreadLocal<WebDriver> DRIVER = new ThreadLocal<>();

    private Drivers() {
    }

    public static void start(URL gridUrl, Capabilities options) {
        DRIVER.set(new RemoteWebDriver(gridUrl, options));
    }

    public static WebDriver get() {
        return DRIVER.get();
    }

    public static void stop() {
        WebDriver driver = DRIVER.get();
        if (driver != null) {
            driver.quit();
            DRIVER.remove();
        }
    }
}

46. How do you approach a suite where 5 percent of the tests fail at random?

Treat flakiness as a defect and use data. First measure: rerun the suite many times or use CI history to list which tests flake and how often. Then sort the causes: timing (missing or wrong waits, animations), test data (shared accounts, order dependence, leftovers from earlier runs), environment (slow shared servers, browser updates) and real product bugs such as race conditions. Fix the worst offenders first, quarantine a flaky test with an owner and a deadline so it does not block the pipeline, and track the flake rate as a team metric.

47. What are the trade-offs of automatic retries, such as a TestNG IRetryAnalyzer?

A retry reruns a failed test, which keeps the pipeline green when the failure came from a passing hiccup such as a slow environment. The cost is that it hides flaky tests, and it can hide real bugs that fail only some of the time, such as a race condition in the product. If you use retries, allow at most one, apply them to UI tests only, and report every retry so tests that pass on retry land on a flaky list someone fixes. Never retry tests that change shared data without cleanup, because the second run starts from a different state.

48. How would you design a Selenium framework for a large web application from scratch?

I would build it in layers. Tests describe business scenarios only. Page objects and reusable components such as tables, date pickers and modals hold locators and waits. A driver factory creates local or Grid browsers from configuration, with a ThreadLocal driver for parallel runs. Configuration comes from files plus environment variables, so the same code runs against dev, staging or a release build. Test data is created through APIs, not the UI. Reporting adds screenshots, logs and environment details to every failure, and test code gets the same code review as product code.

49. How do you manage test data for UI tests that run in parallel?

Each test should create the data it needs, use it and clean it up, so tests depend neither on each other nor on a shared account. Creating data through the application's API or a seed script is much faster and more reliable than clicking through setup screens. Add a unique suffix to names, emails and phone numbers so parallel runs never collide. A pytest fixture with yield, or TestNG before and after methods, fits well: create before, delete after. Never point tests at production data, and keep API keys in the CI secret store, not in the repository.

50. How do you keep page objects maintainable in a large application with repeated widgets? (Java)

Split pages into components. A data table, date picker or search bar that appears on many pages gets its own class, scoped to a root element, and pages compose those components instead of repeating locators. Inside a component, search from the root, and in XPath start with .// because // from an element still searches the whole page. Holding the root as a WebElement can go stale after a re-render, so on dynamic pages keep the root's By locator and find it again on each call. Each class stays small, and a UI change is fixed in one place.

Example
public class DataTable {
    private final WebDriver driver;
    private final By rootLocator;

    public DataTable(WebDriver driver, By rootLocator) {
        this.driver = driver;
        this.rootLocator = rootLocator;
    }

    private WebElement root() {
        return driver.findElement(rootLocator);  // found fresh every call
    }

    public int rowCount() {
        return root().findElements(By.cssSelector("tbody tr")).size();
    }

    public void sortBy(String column) {
        root().findElement(By.xpath(
                ".//th[normalize-space()='" + column + "']")).click();
    }
}

51. How do you find an element inside a shadow DOM in Selenium 4? (Java)

Elements inside a shadow root are not reachable by normal find calls on the page, so a locator that looks right fails. Selenium 4 added getShadowRoot() on the host element, which returns a SearchContext for the shadow tree; in Python it is the shadow_root property. Search from that context with CSS selectors, which are the dependable choice there; XPath does not work reliably inside a shadow root. For nested web components, step through each host in turn. Before Selenium 4, teams read shadowRoot through JavaScript; the built-in method is cleaner.

Example
WebElement host = driver.findElement(By.cssSelector("leave-date-picker"));
SearchContext shadow = host.getShadowRoot();
shadow.findElement(By.cssSelector("button.next-month")).click();
shadow.findElement(By.cssSelector("[data-day='15']")).click();

52. A UI regression suite takes three hours. How would you bring it under thirty minutes? (Python)

First profile it: find the slowest tests and how much time goes into setup. Common wins are logging in through an API and setting the session cookie instead of typing credentials in every test, creating data through APIs, removing sleeps and long implicit waits, and running in parallel on a Grid or with pytest-xdist. Move checks that do not need a browser down to API or unit tests. Split the suite into a fast smoke set for every commit and the full set nightly. Note that add_cookie works only after the browser is already on that site's domain.

Example
session_token = api_login("qa.meera@example.com")   # your API helper

driver.get("https://hr.example.com/favicon.ico")      # be on the domain first
driver.add_cookie({"name": "SESSION", "value": session_token,
                   "path": "/", "secure": True, "httpOnly": True})
driver.get("https://hr.example.com/dashboard")        # already logged in

53. How do you integrate Selenium tests into a CI pipeline?

The pipeline builds and deploys the application to a test environment, then runs the UI tests against it on a Grid or in containers with headless browsers. A small smoke group runs on every pull request, and the full regression runs nightly or before a release. Settings such as the base URL, browser and Grid address come from pipeline variables, and secrets from the CI secret store. The test command must exit with a non-zero code on failure so the stage fails. Publish JUnit XML results, screenshots and logs as build artifacts, and alert the team when a run fails.

54. What should a good Selenium test report contain, and why?

A report should let someone who did not write the test understand a failure without rerunning it. Per test: the name and business scenario, pass, fail or skip, duration, and for failures the error, the step that failed, a screenshot, the URL, the page source and browser console errors where available. Per suite: environment, build version, browser and its version, and trends over time such as flaky tests and duration. Allure or ExtentReports present this well, and JUnit XML lets the CI show results. A failure with only a stack trace wastes everyone's time.

55. What are the Chrome DevTools Protocol and WebDriver BiDi in Selenium 4, and when would you use them? (Python)

Classic WebDriver is one-way: the test sends a command and waits for the reply. The Chrome DevTools Protocol gives low-level control of Chromium browsers, such as emulating a time zone or network conditions, blocking URLs and reading console logs; Selenium 4 exposes it, for example as execute_cdp_cmd in Python. It works only with Chromium-based browsers and is tied to browser versions. WebDriver BiDi is the W3C standard for two-way, event-driven automation across browsers, requested with the webSocketUrl capability, and Selenium is moving such features onto it.

Example
driver = webdriver.Chrome()
# The CI server runs in UTC, but the app must show Indian time
driver.execute_cdp_cmd("Emulation.setTimezoneOverride",
                       {"timezoneId": "Asia/Kolkata"})
driver.get("https://hr.example.com/attendance")

56. What do you change when migrating a Selenium 3 framework to Selenium 4?

In Python, replace find_element_by_* calls with find_element(By...), because the old methods were removed in Selenium 4.3, and pass Options objects instead of desired capabilities, since later 4.x releases dropped the desired_capabilities argument of Remote. In Java, move waits and timeouts to Duration, use Options classes instead of DesiredCapabilities, and drop manual driver paths in favour of Selenium Manager. Move to Grid 4, which no longer needs the /wd/hub path. Then run the full suite on every browser, because the W3C protocol can change small behaviours.

57. How do you make locators stable across a large team and frequent UI redesigns?

Make locators a contract with developers. Agree on a dedicated attribute such as data-testid for anything tests touch, name it by meaning rather than looks, and add it in the same pull request as the feature. Ask reviewers to reject locators based on position, generated class names or long absolute paths. Avoid visible text in apps translated into Hindi or other languages, or keep text locators to one language build. Keep all locators inside page objects so a rename is a one-line fix, and have a quick CI check that each critical test id still exists.

58. How do you decide how much to test through Selenium versus API and unit tests?

Follow the test pyramid: many fast unit tests, a solid layer of API or service tests, and a small number of end-to-end UI tests for the journeys that matter most, such as sign-up, payment or payroll approval. UI tests are the slowest and most fragile, so each one should check something only a browser can show, such as a full user flow across screens. Validation rules, calculations and permission matrices are cheaper and more reliable at the API level. Review the suite regularly and delete UI tests that duplicate lower-level tests or never find bugs.

59. How do you test flows that involve OTP, CAPTCHA or two-factor login?

Do not try to defeat them in the UI: a CAPTCHA exists to stop automation, and reading OTPs from a real phone makes tests slow and fragile. Instead, agree a test-environment setup with developers: a test-only CAPTCHA key, an SMS or email stub that tests can read through an API, or a fixed OTP for named test accounts that exists only in that environment. Test the OTP rules themselves, such as expiry and retry limits, at the API level. Make sure no such bypass can ever be switched on in production, and log in through the API for tests that only need a session.

60. How do you write a reliable wait for a single-page application where data loads after the page is ready? (Java)

document.readyState only describes the first page load; in a React or Angular app, later screens fetch data in the background while readyState already says complete. Wait for an application signal instead: the loader disappearing, a row count, or an attribute the app sets when data has arrived, such as data-state='ready'. A lambda passed to WebDriverWait can check any of these. It keeps polling while the lambda returns false or null, and WebDriverWait ignores NotFoundException by default, so a missing element just means try again. Ask developers for such a signal if none exists.

Example
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
wait.until(ExpectedConditions.invisibilityOfElementLocated(
        By.cssSelector(".loader")));
wait.until(d -> "ready".equals(d.findElement(By.id("payroll-table"))
        .getDomAttribute("data-state")));

Practice questions for November 2026

New every month

3 questions from the Selenium mock test, the way they appear in it. A new set comes on the 1st of every month. Pick your answer, then open it.

  1. FresherTestNG and pytest

    In TestNG's Assert.assertEquals(a, b), what is the order of the two values?

    • The failure message first, then the expected value
    • Either order, because TestNG sorts them first
    • The expected value first, then the actual value
    • The actual value first, then the expected value
    Show the answer

    Answer: The actual value first, then the expected value. TestNG takes (actual, expected), the reverse of JUnit. Swapping them still compares correctly, but the failure message then labels the two values the wrong way round, which misleads whoever reads the report.

  2. Intermediate (1-5 years)Dropdowns and Forms

    What happens when deselectAll() is called on a Select that wraps a normal single-choice dropdown?

    • It throws UnsupportedOperationException
    • It selects the first option instead
    • It clears the choice and leaves the dropdown blank
    • Nothing, because the call is silently ignored
    Show the answer

    Answer: It throws UnsupportedOperationException. deselectAll and the deselectBy methods work only when isMultiple() is true. A normal dropdown always has one option selected, so Select refuses with UnsupportedOperationException. Check isMultiple() in shared helpers.

  3. Experienced (5+ years)Actions and JavaScript

    In Selenium 4 Java, where does moveToElement(el, 10, 5) put the pointer?

    • 10 pixels right of and 5 below the top-left corner of the page
    • 10 pixels right of and 5 below the centre of the element
    • On the element, after scrolling the page by 10 and 5 pixels
    • 10 pixels right of and 5 below the top-left corner of the element
    Show the answer

    Answer: 10 pixels right of and 5 below the centre of the element. W3C actions measure element offsets from the element's in-view centre point. Selenium 3 code written for the top-left corner lands somewhere else after an upgrade, a classic cause of misses on sliders and canvases.

Take the full Selenium mock test

Ready to apply?

Browse the open jobs on CoreHRx. Create a free profile once and apply with it.