Skip to content
RED SAGSkills

Automation Testing interview questions and answers

Automation testing questions cover building test suites that are fast, stable and worth maintaining, with tools like Selenium and Playwright.

Below are 60 Automation Testing questions with the correct answer and a short explanation, grouped from fresher to experienced level. Try each one before you open the answer.

What Automation Testing interviews usually check

  • ✓What to automate and what not to
  • ✓Locators, waits and flaky tests
  • ✓Page objects and framework design
  • ✓Running tests in CI
  • ✓Reporting and test data

Automation Testing interview questions for freshers easy

1. What HTTP/3 changes

HTTP/3 runs over QUIC instead of TCP. What is one key benefit?

  1. A.A lost packet does not stall the other streams
  2. B.It removes the need for HTTPS certificates
  3. C.It makes JavaScript files run faster
  4. D.It caches files forever in the browser
Show answer

Answer: A. A lost packet does not stall the other streams

With HTTP/2 over TCP, one lost packet blocks all streams until it is resent (head-of-line blocking). QUIC handles streams separately over UDP and also sets up connections faster, which helps most on lossy mobile networks.

2. Sharing test builds with QA

QA and the client need new Android and iOS test builds several times a day without going through store review. Which tool fits?

  1. A.Uploading the builds to production with a beta label
  2. B.Emailing the source code to each tester
  3. C.Firebase App Distribution or TestFlight internal testing
  4. D.Posting the builds on a public website
Show answer

Answer: C. Firebase App Distribution or TestFlight internal testing

Beta distribution tools deliver signed test builds directly to registered testers, with release notes and feedback. Firebase App Distribution works for Android and iOS (iOS needs registered devices or enterprise setups), and TestFlight internal testing needs no review.

3. Data-driven testing

You have one login test and a CSV file with 30 rows of username, password and expected message. Running the same steps once per row is called what?

  1. A.Exploratory testing
  2. B.Data-driven testing
  3. C.Monkey testing
  4. D.Smoke testing
Show answer

Answer: B. Data-driven testing

Data-driven testing keeps the steps in one place and reads inputs and expected results from an external source such as CSV or Excel. Adding a new case means adding a row, not writing a new test.

4. Choosing a stable locator

Which locator is usually the most stable for clicking a "Submit" button in a UI test?

  1. A.An absolute XPath like /html/body/div[2]/div/form/button[3]
  2. B.A CSS class generated by the build like .btn_x7f2a
  3. C.A role-based or test-id locator, for example getByRole('button', { name: 'Submit' }) or [data-testid="submit"]
  4. D.The pixel position of the button on the screen
Show answer

Answer: C. A role-based or test-id locator, for example getByRole('button', { name: 'Submit' }) or [data-testid="submit"]

Role and test-id locators depend on meaning, not page structure, so they survive layout and styling changes. Absolute XPaths and generated class names break whenever the DOM or build changes.

5. What a pytest fixture does

What is the main purpose of a pytest fixture such as the one below?

@pytest.fixture
def api_client():
    client = ApiClient(base_url=BASE_URL)
    yield client
    client.close()
  1. A.It marks the test as skipped
  2. B.It provides reusable setup to tests that ask for it by name, and runs the code after yield as teardown
  3. C.It runs the test in parallel automatically
  4. D.It turns the function into a test case
Show answer

Answer: B. It provides reusable setup to tests that ask for it by name, and runs the code after yield as teardown

A test that declares api_client as a parameter receives the yielded object. Code after yield runs as cleanup even if the test fails. Fixtures keep setup in one place instead of copying it into every test.

6. BeforeEach or BeforeAll

In JUnit 5, what is the difference between @BeforeEach and @BeforeAll?

  1. A.@BeforeEach runs once per test class; @BeforeAll runs before every test
  2. B.They are the same annotation with different names
  3. C.@BeforeEach runs before every test method; @BeforeAll runs once before all tests in the class
  4. D.@BeforeAll only runs when a test fails
Show answer

Answer: C. @BeforeEach runs before every test method; @BeforeAll runs once before all tests in the class

@BeforeEach gives each test fresh setup, which keeps tests isolated. @BeforeAll is for expensive one-time setup, such as starting a container, and is static by default. TestNG has similar @BeforeMethod and @BeforeClass annotations.

7. How Selenium talks to a browser

How does Selenium WebDriver control a browser?

  1. A.It sends commands through the W3C WebDriver protocol to a browser driver such as chromedriver or geckodriver
  2. B.It records the screen and replays mouse movements
  3. C.It edits the browser source code at runtime
  4. D.It only works by injecting jQuery into the page
Show answer

Answer: A. It sends commands through the W3C WebDriver protocol to a browser driver such as chromedriver or geckodriver

Your test code calls a client library, which sends standard WebDriver commands to a driver that controls the real browser. Selenium 4 also supports WebDriver BiDi for two-way events such as console logs and network activity. Selenium Manager can download the right driver automatically.

8. Screenshots on failure

Why configure the framework to save a screenshot when a UI test fails?

  1. A.Screenshots make the test pass on retry
  2. B.It is required by WCAG
  3. C.It shows what the page looked like at the moment of failure, which speeds up debugging
  4. D.It lowers the cost of the CI server
Show answer

Answer: C. It shows what the page looked like at the moment of failure, which speeds up debugging

A screenshot often reveals the cause at a glance, like an error banner, a cookie popup or a spinner that never stopped. Saving it only on failure keeps storage small.

9. Arrange, Act, Assert

Which description matches the Arrange-Act-Assert pattern for structuring a test?

  1. A.Set up data and objects, run the one behaviour under test, then check the outcome
  2. B.Write the assertion first, then the code, then refactor the test
  3. C.Run every action in the system, then assert all results at the end
  4. D.Arrange tests by priority, act on the failures, then assign owners
Show answer

Answer: A. Set up data and objects, run the one behaviour under test, then check the outcome

AAA keeps each test readable: a setup block, a single action, and focused assertions. When a test mixes many actions and checks, it becomes hard to see what failed and why. Given-When-Then in BDD expresses the same structure.

10. A double that returns fixed data

In a unit test, an exchange-rate service is replaced by an object that always returns 22.85 for AED to INR, with no checks on how it was called. What kind of test double is this?

  1. A.A mock
  2. B.A stub
  3. C.A spy
  4. D.A dummy
Show answer

Answer: B. A stub

A stub provides canned answers so the code under test can run. A mock is set up with expectations about how it is called and verifies them; a spy records calls on a real or fake object; a dummy is just passed around and never used.

11. Reading a Gherkin scenario

In a Gherkin scenario, what does each keyword describe?

Scenario: Free delivery for large orders
  Given a cart worth ₹2,500
  When the customer checks out
  Then delivery should be free
  1. A.Given is the starting context, When is the action, Then is the expected outcome
  2. B.Given is the expected outcome, When is the setup, Then is the action
  3. C.Given is the test name, When is the tag, Then is the data table
  4. D.Given lists the browsers, When lists the pages, Then lists the locators
Show answer

Answer: A. Given is the starting context, When is the action, Then is the expected outcome

Gherkin uses Given for preconditions, When for the event or action, and Then for the observable result, with And or But for extra steps. Scenarios should describe business behaviour, not UI clicks, so that they stay readable and stable.

12. A failure message that helps

A CI log shows only "AssertionError: expected false to be true". What change would make such failures faster to diagnose?

  1. A.Assert on the actual values, e.g. expect(status).toBe("PAID"), or add a clear message
  2. B.Wrap every assertion in try/catch and print "test failed" in the catch block
  3. C.Turn the assertion into a console.log so that the run never stops there
  4. D.Run the failing test again in CI with retries until it passes
Show answer

Answer: A. Assert on the actual values, e.g. expect(status).toBe("PAID"), or add a clear message

Asserting a boolean like expect(isPaid).toBe(true) hides what the real value was. Comparing the actual value, or adding a message such as "invoice 1043 status", shows expected and received directly in the log, so the cause is often clear without rerunning.

13. Expecting an exception in JUnit 5

In JUnit 5, how do you check that withdraw(500) on an account with ₹100 throws InsufficientFundsException and then inspect its message?

  1. A.@Test(expected = InsufficientFundsException.class) on the test method
  2. B.var ex = assertThrows(InsufficientFundsException.class, () -> account.withdraw(500));
  3. C.assertEquals(InsufficientFundsException.class, account.withdraw(500));
  4. D.assertTrue(account.withdraw(500) instanceof InsufficientFundsException);
Show answer

Answer: B. var ex = assertThrows(InsufficientFundsException.class, () -> account.withdraw(500));

assertThrows runs the lambda, fails if the expected exception is not thrown, and returns it so you can assert on getMessage(). @Test(expected=...) is JUnit 4 syntax and cannot inspect the exception. A method that throws cannot also return the exception for assertEquals.

14. Finding a button by role and name

A page has several buttons. Which Playwright locator best finds the one labelled "Place order" in a way that also reflects how users and screen readers see it?

  1. A.page.getByRole('button', { name: 'Place order' })
  2. B.page.locator('div > div:nth-child(3) > button')
  3. C.page.locator('//html/body/div[2]/form/button[1]')
  4. D.page.locator('.btn.btn-primary.mt-2')
Show answer

Answer: A. page.getByRole('button', { name: 'Place order' })

getByRole with a name uses the accessible role and name, which is what users and assistive technology rely on. It survives layout and styling changes, while positional CSS, absolute XPath and utility classes break whenever the markup is rearranged.

15. Uploading a file

How do you upload a file through an <input type="file"> in Playwright?

  1. A.await page.getByLabel('Invoice').fill('fixtures/invoice.pdf')
  2. B.await page.keyboard.type('C:\\fixtures\\invoice.pdf')
  3. C.await page.getByLabel('Invoice').setInputFiles('fixtures/invoice.pdf')
  4. D.await page.getByLabel('Invoice').click({ file: 'invoice.pdf' })
Show answer

Answer: C. await page.getByLabel('Invoice').setInputFiles('fixtures/invoice.pdf')

setInputFiles sets the files on the input directly, without opening the operating system file dialog, which automation cannot drive. You can pass one path, several paths, or an in-memory buffer with a name and MIME type.

16. A menu that opens on hover

A sub-menu item only appears when the mouse hovers over "Reports". How do you click it in Playwright?

  1. A.Click the sub-menu item directly with { force: true }
  2. B.Change the CSS in the test so that the sub-menu is always visible
  3. C.Wait five seconds so that the sub-menu has time to appear on its own
  4. D.Hover over 'Reports' first, then click the sub-menu item's locator
Show answer

Answer: D. Hover over 'Reports' first, then click the sub-menu item's locator

await page.getByRole("menuitem", { name: "Reports" }).hover() reproduces what a user does, then the sub-menu item becomes visible and actionable. force: true or CSS hacks skip the behaviour you are supposed to be testing.

17. Keeping videos only for failures

You want videos for failed tests but not for passing ones, to save CI storage. Which setting fits?

  1. A.video: 'retain-on-failure'
  2. B.video: 'on-first-retry'
  3. C.video: 'off'
  4. D.screenshot: 'only-on-failure'
Show answer

Answer: A. video: 'retain-on-failure'

retain-on-failure records every test but deletes the video when the test passes. on keeps all videos, which uses a lot of space. Traces (for example on-first-retry) are often even more useful than videos for debugging.

18. The Select helper in Selenium

Which Selenium approach chooses "Abu Dhabi" from a native <select id="emirate">?

  1. A.driver.findElement(By.id("emirate")).sendKeys(Keys.ENTER, "Abu Dhabi")
  2. B.driver.findElement(By.id("emirate")).setValue("Abu Dhabi")
  3. C.new Select(driver.findElement(By.id("emirate"))).selectByVisibleText("Abu Dhabi")
  4. D.driver.switchTo().select("emirate").choose("Abu Dhabi")
Show answer

Answer: C. new Select(driver.findElement(By.id("emirate"))).selectByVisibleText("Abu Dhabi")

The Select class wraps a <select> element and offers selectByVisibleText, selectByValue and selectByIndex. It only works with real <select> elements; custom dropdowns built from divs need clicks instead.

19. What Selenium Grid is for

What is Selenium Grid mainly used for?

  1. A.Running tests on remote machines and browsers, often in parallel
  2. B.Recording tests by watching a manual tester's clicks
  3. C.Comparing screenshots against stored baseline images
  4. D.Generating test data for forms automatically
Show answer

Answer: A. Running tests on remote machines and browsers, often in parallel

Grid routes WebDriver sessions to nodes that have the requested browser and platform, so many tests can run at once across different browsers and operating systems. It can run as a single standalone process or as separate hub and node components.

20. Reading ease scores

A readability tool shows a Flesch Reading Ease score. What does a higher score mean?

  1. A.The text is longer
  2. B.The text has more keywords
  3. C.The text is harder to read
  4. D.The text is easier to read
Show answer

Answer: D. The text is easier to read

Flesch Reading Ease runs roughly from 0 to 100, and higher scores mean easier text, driven by shorter sentences and shorter words. Scores of about 60 to 70 suit most general audiences. Treat the score as a guide, not a goal; clarity and accuracy come first.

Automation Testing intermediate interview questions medium

21. toBe fails on equal objects

Why does this test fail even though both objects look the same?

expect(getUser()).toBe({ id: 1, name: 'Ana' })
  1. A.toBe only works with strings
  2. B.toBe uses Object.is, which compares object references, so a different object never matches; use toEqual
  3. C.Vitest cannot compare objects that contain strings
  4. D.The test must be marked async to compare objects
Show answer

Answer: B. toBe uses Object.is, which compares object references, so a different object never matches; use toEqual

toBe checks identity with Object.is, so it passes only if both sides are the exact same object in memory. toEqual compares values recursively, and toStrictEqual also checks undefined properties and class types. Use toBe for primitives and toEqual for objects and arrays.

22. Flaky end-to-end test

This Playwright test passes locally but fails randomly in CI. What is the best fix?

await page.getByRole('button', { name: 'Save' }).click()
await page.waitForTimeout(2000)
expect(await page.getByText('Saved').isVisible()).toBe(true)
  1. A.Increase the timeout to 10000 ms
  2. B.Use await expect(page.getByText('Saved')).toBeVisible(), which auto-retries
  3. C.Run the tests with retries set to 5
  4. D.Mock the whole backend with a static JSON file so the timing is always identical
Show answer

Answer: B. Use await expect(page.getByText('Saved')).toBeVisible(), which auto-retries

A fixed sleep guesses how long the save takes, and slower CI machines often need more. Web-first assertions keep polling until the condition is true, so they pass as soon as the UI is ready and fail with a clear message if it never is. More retries only hide the flakiness.

23. Flaky UI test timing

An Espresso or XCUITest test fails randomly because it checks a label before a network-backed screen has finished loading. What is the best fix?

  1. A.Add a fixed sleep of a few seconds before every check, tuned on the slowest CI machine, so the screen always has time to finish loading first
  2. B.Wait for a condition (idling resources in Espresso, waitForExistence in XCUITest, waitUntil in Compose tests) and replace the real network with a fake
  3. C.Retry the test until it passes and ignore failures
  4. D.Delete the test, since UI tests are always flaky
Show answer

Answer: B. Wait for a condition (idling resources in Espresso, waitForExistence in XCUITest, waitUntil in Compose tests) and replace the real network with a fake

Fixed sleeps are either too short on slow CI machines or waste time on fast ones. Waiting on a real condition makes the test as fast as possible and reliable. A fake network layer removes variable latency and server data from the test entirely.

24. Native module undefined in Jest

A Jest test fails with "NativeModule: AsyncStorage is null" when rendering a screen. What is the standard fix?

  1. A.Run Jest on a real Android device instead of in Node
  2. B.Install the native module again with pod install
  3. C.Mock the native module, for example with the library's mock
  4. D.Switch the test environment to jsdom for the web
Show answer

Answer: C. Mock the native module, for example with the library's mock

Jest runs in Node, where no native modules exist. Libraries usually ship a mock (for AsyncStorage, @react-native-async-storage/async-storage/jest/async-storage-mock) that you register with jest.mock or in a setup file. That isolates the test from native code.

25. Same test, many inputs

You want to run the same login validation test with 12 different invalid inputs. What is the cleanest approach?

  1. A.Copy the test 12 times with small edits
  2. B.Put all 12 inputs in one test and stop at the first failure
  3. C.Test only the first input
  4. D.Use a parameterised (data-driven) test, for example pytest.mark.parametrize or a loop that generates one test per row
Show answer

Answer: D. Use a parameterised (data-driven) test, for example pytest.mark.parametrize or a loop that generates one test per row

Parameterised tests keep one test body and feed it data. Each input runs and reports as a separate case, so one failure does not hide the others, and adding a new case is just adding a row.

26. Click intercepted by an overlay

A test fails with "element click intercepted: another element would receive the click". A loading overlay fades out after data loads. What is the best fix?

  1. A.Use force: true so the click ignores the overlay
  2. B.Add a 3 second sleep before the click
  3. C.Wait for the overlay to be hidden (or for the loaded data to appear), then click normally
  4. D.Click with JavaScript using element.click() in the browser
Show answer

Answer: C. Wait for the overlay to be hidden (or for the loaded data to appear), then click normally

The overlay tells you the page is not ready, so the test should wait for the real ready signal. Forcing or JavaScript clicks skip the checks a user would face and can hide real bugs where the overlay never goes away.

27. Splitting a suite across machines

What does npx playwright test --shard=2/4 do?

  1. A.Runs each test 2 times on 4 browsers
  2. B.Uses 2 workers and 4 retries
  3. C.Runs the second quarter of the test files, so 4 machines together run the whole suite
  4. D.Runs only tests whose names contain 2 or 4
Show answer

Answer: C. Runs the second quarter of the test files, so 4 machines together run the whole suite

Sharding splits the suite between CI machines, while workers run tests in parallel within one machine. Combine shard reports with the blob reporter and merge-reports to get one HTML report.

28. Passes in the suite, fails alone

A test passes when the whole suite runs but fails when run on its own. What does this most likely show?

  1. A.The test runner is broken
  2. B.The test is too short
  3. C.The test should be deleted
  4. D.The test depends on state created by an earlier test, so it is not isolated
Show answer

Answer: D. The test depends on state created by an earlier test, so it is not isolated

Hidden dependencies on earlier tests break when order changes, when sharding splits the suite or when you rerun one test. Each test should create or request the state it needs through fixtures or API setup.

29. Tests for several user roles

You need tests for admin and viewer users. Logging in through the UI in every test is slow. What is a clean approach in Playwright?

  1. A.Share one browser tab between all tests
  2. B.Run a setup project that logs in each role once and saves separate storage state files; tests choose the file for their role
  3. C.Turn off authentication in production
  4. D.Log in as admin for all tests and hide admin controls with CSS
Show answer

Answer: B. Run a setup project that logs in each role once and saves separate storage state files; tests choose the file for their role

Setup projects with dependencies create admin.json and viewer.json once per run. Each test then starts already logged in as the right role, which is fast and still uses real sessions.

30. A test that passes for the wrong reason

This test passes even when fetchUser rejects. Why, and what is a fix?

test('loads user', () => {
  fetchUser(7).then((user) => {
    expect(user.name).toBe('Asha')
  })
})
  1. A.Jest ignores assertions inside then(), so move it to an afterEach hook
  2. B.toBe cannot compare strings, so it should use toEqual instead
  3. C.The promise is not returned or awaited; use async and await fetchUser(7)
  4. D.The test needs a longer timeout so the promise can finish
Show answer

Answer: C. The promise is not returned or awaited; use async and await fetchUser(7)

Jest finishes the test as soon as the function returns, before the promise settles, so the assertion never affects the result. Returning or awaiting the promise fixes it, and expect.assertions(1) adds a guard that an assertion actually ran.

31. The app uses data-qa, not data-testid

Your app marks elements with data-qa="..." instead of data-testid. How do you make page.getByTestId() use it?

  1. A.Rename every attribute in the app to data-testid before testing
  2. B.Use getByTestId('[data-qa=submit]') with the full attribute selector
  3. C.getByTestId cannot be changed, so use XPath for these elements
  4. D.Set use: { testIdAttribute: 'data-qa' } in playwright.config
Show answer

Answer: D. Set use: { testIdAttribute: 'data-qa' } in playwright.config

Playwright reads data-testid by default, but testIdAttribute in the config changes it for the whole suite. Then getByTestId("submit") finds data-qa="submit" with no other changes.

32. Changing a request on its way out

You want real API calls to go through, but with an extra header x-feature: beta. Which route handler does that?

await page.route('**/api/**', async (route) => {
  // ?
})
  1. A.route.continue({ headers: { ...route.request().headers(), 'x-feature': 'beta' } })
  2. B.route.fulfill({ status: 200, headers: { 'x-feature': 'beta' }, body: '{}' })
  3. C.route.abort('failed'); route.continue({ headers: { 'x-feature': 'beta' } })
  4. D.route.fulfill({ headers: { ...route.request().headers(), 'x-feature': 'beta' } })
Show answer

Answer: A. route.continue({ headers: { ...route.request().headers(), 'x-feature': 'beta' } })

route.continue sends the request to the real server, optionally with changed URL, method, headers or body. route.fulfill returns a fake response without calling the server, and route.abort fails the request.

33. Picking one product card

A product grid has many cards with an "Add to cart" button each. Which locator clicks the button inside the card for "Basmati Rice 5kg"?

  1. A.page.getByTestId('product-card').first().getByRole('button', { name: 'Add to cart' })
  2. B.page.getByText('Basmati Rice 5kg').getByRole('button', { name: 'Add to cart' })
  3. C.page.getByRole('button', { name: 'Add to cart' }).nth(4).filter({ visible: true })
  4. D.page.getByTestId('product-card').filter({ hasText: 'Basmati Rice 5kg' }).getByRole('button')
Show answer

Answer: D. page.getByTestId('product-card').filter({ hasText: 'Basmati Rice 5kg' }).getByRole('button')

filter({ hasText }) narrows the cards to the one containing that text, and the chained getByRole then finds the button inside it. Position-based first() or nth() breaks when sort order changes, and the text element itself does not contain the button.

34. First run of a screenshot test

A new test uses await expect(page).toHaveScreenshot(). On its very first run, with no baseline image, what happens?

  1. A.It passes and silently compares the page against a blank image
  2. B.It downloads a matching baseline image from the Playwright website
  3. C.It skips the assertion until someone uploads a reference image
  4. D.It fails, saves the actual image as the baseline, and passes next time
Show answer

Answer: D. It fails, saves the actual image as the baseline, and passes next time

With no expected image, Playwright saves the actual screenshot and reports a failure so you notice. Baselines are named per browser and platform, so they should be generated in the same environment as CI, for example the official Docker image.

35. Checking the number of results

After applying a filter, the list should show exactly 3 items, but it updates asynchronously. Which check is most reliable?

  1. A.await expect(page.getByRole('listitem')).toHaveCount(3)
  2. B.expect(await page.getByRole('listitem').count()).toBe(3)
  3. C.expect((await page.getByRole('listitem').all()).length).toBe(3)
  4. D.expect(await page.locator('li').isVisible()).toBe(true)
Show answer

Answer: A. await expect(page.getByRole('listitem')).toHaveCount(3)

toHaveCount is a web-first assertion that retries until the count matches or times out. count() and all() read the DOM once, so they may run before the list updates and give a flaky result.

36. A wait that ignores early errors

A status label appears after a few seconds. Which Selenium FluentWait setup waits up to 20 seconds, checks every 500 ms and ignores "not found" errors while waiting?

Wait<WebDriver> wait = new FluentWait<>(driver)
    .withTimeout(Duration.ofSeconds(20))
    .pollingEvery(Duration.ofMillis(500))
    .ignoring(NoSuchElementException.class);
  1. A.The same code but without ignoring(), as FluentWait ignores all errors anyway
  2. B.Thread.sleep(20000) followed by one findElement call
  3. C.This one: timeout, polling interval and ignored exception set as shown
  4. D.driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(20))
Show answer

Answer: C. This one: timeout, polling interval and ignored exception set as shown

FluentWait lets you set the maximum time, how often to poll and which exceptions to ignore between polls. Without ignoring(), a NoSuchElementException during the wait would end it early. WebDriverWait is a FluentWait with NotFoundException ignored by default.

37. The risk of @CacheLookup

In a Selenium PageFactory page object, adding @CacheLookup to a field made a test fail with StaleElementReferenceException after a list refreshed. Why?

  1. A.The element was found once and reused, so the replaced DOM node went stale
  2. B.@CacheLookup makes Selenium look up the element on every single call
  3. C.@CacheLookup only works with XPath locators, not with CSS selectors
  4. D.PageFactory fields cannot be used once the page has been reloaded
Show answer

Answer: A. The element was found once and reused, so the replaced DOM node went stale

By default, PageFactory proxies look the element up each time a method is called on it. @CacheLookup stores the first result, which is faster but breaks when the app replaces the node. Use it only for elements that never re-render.

38. A date picker used on ten pages

The same date picker widget appears on ten different pages. What is a good way to model it in your page objects?

  1. A.Copy the date picker methods into each of the ten page objects
  2. B.A small component object, created with a root locator, reused by each page object
  3. C.Put all ten pages into one huge page object so the methods are shared
  4. D.Avoid modelling it and write raw locators in each test instead
Show answer

Answer: B. A small component object, created with a root locator, reused by each page object

Component objects wrap reusable widgets (date pickers, tables, modals) and are scoped to a root element, so they work wherever the widget appears. Page objects compose them, which avoids duplication and keeps changes in one place.

39. Checking a sorted column

After clicking the "Amount" header, the table should sort by amount ascending. Values look like "₹1,200.00". What is a sound way to verify it?

  1. A.Check that the first row has the smallest amount and ignore the rest
  2. B.Compare the cell strings with a copy sorted alphabetically as text
  3. C.Check that a sort arrow icon is shown on the Amount header
  4. D.Read all amount cells, parse them to numbers, and compare with a sorted copy
Show answer

Answer: D. Read all amount cells, parse them to numbers, and compare with a sorted copy

Sorting "₹1,200.00" as text would put "₹10,000" before "₹2,000", so values must be parsed into numbers first. Comparing the whole column with a sorted copy checks every row, not just the first, and the arrow icon only shows the UI state.

40. Organic landing pages in GA4

In GA4, how do you see which landing pages bring the most organic search sessions and conversions?

  1. A.Use the Realtime report only
  2. B.Open the Landing page report and filter or compare by session default channel group equal to Organic Search
  3. C.Look at the Demographics report
  4. D.GA4 cannot show organic data; only Search Console can
Show answer

Answer: B. Open the Landing page report and filter or compare by session default channel group equal to Organic Search

The Landing page report shows sessions, engagement and key events by first page. Filtering by the Organic Search channel isolates SEO traffic. Linking Search Console to GA4 adds query and impression data alongside it.

Automation Testing interview questions for experienced candidates hard

41. Noisy screenshot tests

Visual regression tests fail on most runs with tiny pixel differences in fonts, plus a changing date and a carousel. Developers now ignore the failures. What is the best fix?

  1. A.Raise the allowed pixel difference to 30% for all tests
  2. B.Delete all screenshot tests
  3. C.Run screenshots in one fixed environment (same container, browser and fonts), mask or freeze dynamic content, and disable animations
  4. D.Take screenshots only on developers' own laptops
Show answer

Answer: C. Run screenshots in one fixed environment (same container, browser and fonts), mask or freeze dynamic content, and disable animations

Font rendering differs between operating systems and GPUs, so baselines must come from the same environment, often a Docker image. Dynamic areas should be masked or given fixed data and clocks, and animations turned off. A huge threshold would hide real layout bugs.

42. When automation pays off

A regression set takes 4 hours to run by hand. Automating it takes 40 hours, and each automated run needs 1 hour of upkeep and analysis. After how many runs does automation start saving time?

  1. A.10 runs
  2. B.40 runs
  3. C.14 runs
  4. D.8 runs
Show answer

Answer: C. 14 runs

Each run saves 4 − 1 = 3 hours. 40 ÷ 3 ≈ 13.3, so it pays back on the 14th run. Ignoring upkeep (40 ÷ 4 = 10) overstates the benefit, a common mistake in automation business cases.

43. Element inside an iframe

In Selenium, a payment card field is inside an iframe, and findElement(By.id("card")) throws NoSuchElementException. What is needed?

  1. A.Switch to the frame first with driver.switchTo().frame(...), interact, then switch back with defaultContent()
  2. B.Use a longer implicit wait
  3. C.Use an absolute XPath from the top document
  4. D.Run the test in headless mode
Show answer

Answer: A. Switch to the frame first with driver.switchTo().frame(...), interact, then switch back with defaultContent()

Each iframe has its own document, so Selenium only searches the current browsing context. You must switch into the frame. Playwright handles this with page.frameLocator() or locator.contentFrame().

44. Waiting for network idle

A team waits for "networkidle" after every navigation. Tests are slow and still flaky on pages with analytics and polling. What is the better approach?

  1. A.Increase the networkidle timeout to 60 seconds
  2. B.Block all network requests
  3. C.Wait for the specific UI state the test needs, using web-first assertions on visible content
  4. D.Use page.waitForTimeout(5000) instead
Show answer

Answer: C. Wait for the specific UI state the test needs, using web-first assertions on visible content

Pages with polling, websockets or analytics may never be idle, and idle does not mean the right content is shown. Playwright's docs discourage networkidle for testing. Asserting on the content you care about is faster and more meaningful.

45. DRY or DAMP tests

A framework has helpers so abstract that a test reads: runScenario(config[7]). Reviewers cannot tell what it checks. What guideline applies?

  1. A.Tests should be as DRY as possible, even if unreadable
  2. B.Prefer DAMP (descriptive and meaningful phrases) in tests: some repetition is fine if each test clearly shows its setup, action and expected result
  3. C.Remove all helpers and copy code everywhere
  4. D.Move all assertions into the helpers
Show answer

Answer: B. Prefer DAMP (descriptive and meaningful phrases) in tests: some repetition is fine if each test clearly shows its setup, action and expected result

Tests are documentation and are read when they fail. Share mechanics (fixtures, page objects, builders) but keep the test-specific inputs and expectations visible in the test body.

46. Testing with generated inputs

A function splits a bill among N people in whole paise. Instead of a few hand-picked examples, you want to check that the shares always add up to the total for many random inputs. Which approach is this?

  1. A.Snapshot testing of the output for one large input
  2. B.Mutation testing of the function's source code
  3. C.Contract testing between the bill service and its users
  4. D.Property-based testing, for example Hypothesis or fast-check
Show answer

Answer: D. Property-based testing, for example Hypothesis or fast-check

Property-based tools generate many inputs, check that an invariant holds, and shrink any failure to a minimal example. They are good at finding edge cases, such as totals that do not divide evenly, that example-based tests miss.

47. Shuffling test order on purpose

Why might a team run tests in random order (for example with pytest-randomly or jest --randomize) in CI?

  1. A.To make the suite run faster by spreading slow tests evenly
  2. B.To expose hidden dependencies between tests, with a seed to replay
  3. C.To give every test in the suite an equal chance of being skipped
  4. D.To make results differ each time so flaky tests are hidden
Show answer

Answer: B. To expose hidden dependencies between tests, with a seed to replay

Tests that only pass in a fixed order secretly rely on state left by others. Randomising order flushes these out before they cause confusing failures in parallel runs. The seed is printed so the exact failing order can be replayed.

48. SQLite in tests, Postgres in production

Tests run against SQLite for speed while production uses PostgreSQL. Which bug is most likely to slip through?

  1. A.A type, constraint or collation rule that SQLite handles differently
  2. B.A typo in a local variable name inside the repository class
  3. C.A missing import of the database driver in the main application code
  4. D.A wrong HTTP status code returned by the API controller
Show answer

Answer: A. A type, constraint or collation rule that SQLite handles differently

SQLite has looser typing, different collation and date handling, and different locking and constraint behaviour. Code that relies on Postgres semantics can pass on SQLite and fail in production. Run at least the repository tests against the real engine, for example with Testcontainers.

49. A cache that remembers old tests

A singleton PriceCache is filled by one test with a ₹999 price. Another test later expects ₹1,099 from a stubbed service but gets ₹999. What is the best long-term fix?

  1. A.Order the tests so that the ₹1,099 test always runs first
  2. B.Inject the cache so each test gets a fresh one, or reset it in a fixture
  3. C.Add a sleep so the cache entry expires before the second test
  4. D.Mark the second test as flaky and allow two retries
Show answer

Answer: B. Inject the cache so each test gets a fresh one, or reset it in a fixture

Global or static state survives between tests and makes results depend on order and parallel scheduling. Injecting dependencies, or at least resetting shared state in setup, restores isolation. Ordering, sleeps and retries only hide the coupling.

50. A test that can never fail

Why does this test always pass, even when no "Overdue" invoice exists?

test('flags overdue invoices', () => {
  const invoices = getInvoices()
  invoices.filter((i) => i.status === 'Overdue').forEach((i) => {
    expect(i.reminderSent).toBe(true)
  })
})
  1. A.If the filter returns no items, no assertion runs and the test passes
  2. B.forEach runs asynchronously, so Jest misses the assertions inside
  3. C.toBe(true) always passes when the property is undefined
  4. D.Jest skips tests that use filter() on arrays of objects
Show answer

Answer: A. If the filter returns no items, no assertion runs and the test passes

Assertions inside loops or callbacks pass vacuously when the loop runs zero times. Assert the precondition, for example expect(overdue.length).toBeGreaterThan(0), or use expect.assertions(n), so the test fails when the data it depends on is missing.

51. Checking structure, not pixels

Screenshot tests of a navigation menu break with every font or colour change, but the team mainly cares that the right links exist in the right order. Which check fits better?

  1. A.toHaveScreenshot() with a 50% pixel difference tolerance
  2. B.Asserting that the menu's innerHTML equals a saved string
  3. C.expect(locator).toMatchAriaSnapshot() comparing the accessibility tree
  4. D.Comparing the CSS class list of every link to a saved list
Show answer

Answer: C. expect(locator).toMatchAriaSnapshot() comparing the accessibility tree

An ARIA snapshot compares roles, names and structure in a YAML-like form, so styling changes do not break it but missing or reordered links do. Comparing raw HTML is brittle, and a huge pixel tolerance would hide real visual bugs too.

52. Paying one invoice in a table

In a table of invoices, each row has one button, "Pay", and rows = page.getByRole("row"). Which locator finds "Pay" only in the row whose invoice cell is exactly "INV-1043" (and not "INV-10431")?

  1. A.rows.filter({ has: page.getByRole('cell', { name: 'INV-1043', exact: true }) }).getByRole('button')
  2. B.rows.filter({ hasText: 'INV-1043' }).first().getByRole('button', { name: 'Pay', exact: true })
  3. C.page.getByText('INV-1043').locator('..').getByRole('button', { name: 'Pay' }).first()
  4. D.rows.getByRole('button', { name: 'Pay', exact: true }).nth(1043).filter({ hasText: 'Pay' })
Show answer

Answer: A. rows.filter({ has: page.getByRole('cell', { name: 'INV-1043', exact: true }) }).getByRole('button')

hasText matches substrings, so "INV-1043" would also match "INV-10431" and cause a strict mode error or the wrong click. filter({ has }) with an exact cell locator selects the right row precisely, and the chained button locator stays within that row.

53. Extra words in a table cell

A sortable column header shows "Amount", but allTextContents() returns "Amount sorted ascending" because of a <span style="display:none">. Which method returns only the rendered text?

  1. A.allTextContents()
  2. B.allInnerTexts()
  3. C.getAttribute('textContent')
  4. D.evaluate((el) => el.outerHTML)
Show answer

Answer: B. allInnerTexts()

textContent includes all text nodes, even hidden ones. innerText reflects rendered text and skips display:none content. Pick the one that matches what you mean to assert: what a user sees (innerText) or the raw DOM text.

54. Clicking through JavaScript

A tester "fixes" an intercepted click by using ((JavascriptExecutor) driver).executeScript("arguments[0].click()", button). Why can this be harmful?

  1. A.It clicks even when a real user could not, so it can hide a real bug
  2. B.JavaScript clicks are always slower than WebDriver clicks
  3. C.executeScript does not work on buttons, only on links
  4. D.It permanently disables the overlay for all other tests
Show answer

Answer: A. It clicks even when a real user could not, so it can hide a real bug

A JavaScript click skips visibility and hit-testing, so a button hidden under a modal or off-screen will still be "clicked". The test passes while users are blocked. Use it only for deliberate edge cases, after understanding why the real click failed.

55. Logging in on another domain in Cypress

The app redirects to an identity provider at login.idp.com for SSO. In Cypress, commands on that page fail. What is the supported way to interact with it?

  1. A.Set chromeWebSecurity to false and use cy.visit for every page
  2. B.Open the identity provider in a new tab with cy.window().open()
  3. C.Wrap those steps in cy.origin('https://login.idp.com', () => { ... })
  4. D.Use cy.wait(5000) so Cypress can switch to the other domain
Show answer

Answer: C. Wrap those steps in cy.origin('https://login.idp.com', () => { ... })

Because Cypress runs inside the browser alongside the app, cross-origin pages need cy.origin to run commands in that origin. Often a better choice is to log in programmatically (for example via cy.request to get tokens) and use cy.session, testing the SSO UI in only one test.

56. Finding an item in an infinite feed

A feed loads 20 more items each time you scroll to the bottom. A test must find a post created a week ago. Which approach is most robust?

  1. A.Scroll with an unbounded while loop until the post finally appears
  2. B.Scroll once and wait 30 seconds for all the posts to load
  3. C.Create the post in the test, or scroll in a bounded loop until found
  4. D.Zoom the browser to 10% so every post fits on the screen
Show answer

Answer: C. Create the post in the test, or scroll in a bounded loop until found

Tests should control their data: creating a fresh post means it appears at the top. If you must search, scroll with a limit on attempts and wait for new items after each scroll, so the test fails clearly instead of hanging when the item is missing.

57. getText() returns an empty string

A hidden <span> with display:none holds a tracking number. Selenium's getText() returns "". What explains this, and how do you read it?

  1. A.The element is stale; find it again and call getText() once more
  2. B.getText() fails on spans; use getTagName() to read the value
  3. C.Hidden text is encrypted; use executeScript to decrypt it
  4. D.getText() returns only visible text; read getDomProperty("textContent")
Show answer

Answer: D. getText() returns only visible text; read getDomProperty("textContent")

WebDriver getText() is defined as the rendered, visible text, so hidden elements give an empty string. textContent reads the raw DOM text. Ask whether the test should be reading hidden text at all, since users cannot see it.

58. Article text on a phone

On a 360 px wide phone, an article uses 13 px text with 8 px side margins to fit more words per line. What is the main problem and fix?

  1. A.Lines are too short; use 11 px text
  2. B.Margins are too wide; remove them
  3. C.Line height is too large; set it to 1.0
  4. D.Text is too small; use 16 px+ and wider margins
Show answer

Answer: D. Text is too small; use 16 px+ and wider margins

Small text strains eyes on phones and tiny margins make text crowd the edge. About 16 px or more body text with 16 px margins gives roughly 35–45 characters per line, which is comfortable on mobile.

59. Setting text for readers with dyslexia

A government portal wants body text that is easier for readers with dyslexia. Which change has the strongest support from guidance such as the British Dyslexia Association style guide?

  1. A.A special dyslexia font set in all caps
  2. B.Fully justified text in narrow columns
  3. C.Light grey text on pure white for softness
  4. D.Left-aligned, well-spaced text, no long italics
Show answer

Answer: D. Left-aligned, well-spaced text, no long italics

Guidance stresses layout: left-aligned text, line spacing around 1.5, avoiding long italic or underlined passages, and good but not glaring contrast. Evidence that special dyslexia fonts help is weak; spacing and setting matter more.

60. A sales cut-off problem

The year ends on 31 March. Goods were dispatched on 3 April, but the invoice was dated 30 March and recorded as a sale for the year. Control passes on dispatch. What is the effect, and which assertion is affected?

  1. A.Revenue understated; completeness
  2. B.No effect, because the invoice date decides the period
  3. C.Revenue and receivables overstated (and inventory understated); cut-off
  4. D.Expenses overstated; classification
Show answer

Answer: C. Revenue and receivables overstated (and inventory understated); cut-off

Control passed on 3 April, so the revenue belongs to the next year. Recording it on 30 March overstates revenue and receivables, and if inventory was removed from the books, understates inventory at year end. This is a cut-off error, and sales just before year end are a classic area for testing and for fraud risk.

Ready to test yourself?

Take a 15-question Automation Testing MCQ test with a score at the end, or practise the full Automation Testing question bank and earn points on the leaderboard.