Complex scenarios come up in every automation interview. The interviewer wants to know if you have automated beyond simple form filling. Iframes, tabs, file uploads, drag-and-drop -- these separate a junior from a mid-level automation engineer. Know these cold.
Q: How do you handle iframes in Playwright? How is it different from Selenium?
A: In Playwright, I use page.frameLocator() to scope into an iframe by its CSS selector. Then I chain regular locators like getByRole() and getByLabel(). For nested iframes, I chain multiple frameLocator() calls. The key difference from Selenium: there is no switchTo().frame(). In Selenium, you switch the entire driver context to the iframe and then back to the parent. In Playwright, frameLocator() creates a scoped locator context. I can interact with both the main page and the iframe in the same test without any switching.
Q: How do you handle multiple browser tabs in Playwright?
A: Each tab is a separate Page object. When a link opens a new tab, I use Promise.all with context.waitForEvent('page') and the click. For window.open popups, I use page.waitForEvent('popup'). I create manual tabs with context.newPage(). There is no switchTo().window() like Selenium -- I just use the Page variable directly. The critical rule: set up the event listener BEFORE the click that opens the tab.
Q: Explain how you handle JavaScript dialogs in Playwright.
A: I use page.once('dialog', handler) to register a handler before the action that triggers the dialog. The handler gets a Dialog object with type() (alert/confirm/prompt), message(), accept(), and dismiss() methods. For prompts, I pass text to accept('my text'). The critical mistake is registering the handler after the click -- Playwright auto-dismisses unhandled dialogs, so the handler never runs. I use once() for single dialogs and on() for multiple.
Q: How do you handle file uploads when there is no visible file input?
A: When the file input is hidden behind a custom button, I use the fileChooser event. I set up page.waitForEvent('filechooser') in Promise.all with the click on the custom upload button. The fileChooser object has a setFiles() method where I pass the file path. For visible file inputs, I use the simpler setInputFiles() directly on the input element. I always verify the upload by checking for the filename or a success message.
Q: What approaches do you use for drag and drop in Playwright?
A: Two approaches. First, locator.dragTo(target) -- one line, works for standard HTML5 drag-and-drop. Second, manual mouse steps for custom drag libraries like react-dnd: get bounding boxes, mouse.move() to source center, mouse.down(), mouse.move() to target center with { steps: 10 } for smooth motion, then mouse.up(). The steps parameter is critical because some libraries need intermediate mousemove events. I always try dragTo() first and fall back to manual only if it fails.
Q: How do you avoid flaky tests caused by timing issues?
A: Playwright auto-waits for most actions, which eliminates most timing issues. For explicit waits, I use waitForResponse() for API calls, waitForURL() for navigation, waitForSelector({ state: 'hidden' }) for spinners to disappear, and expect assertions that auto-retry. For complex conditions, I use expect.poll(). I never use waitForTimeout() -- that is a hard sleep. When a test is flaky, I find the right condition to wait for instead of adding delays. The right wait is always a condition, never a duration.
Q: How do you handle custom dropdowns that are not native <select> elements?
A: First, I inspect the DOM to check if it is a native <select> or a custom component. For native, I use selectOption(). For custom dropdowns (React Select, Material UI), I click the trigger to open the list, wait for the listbox to be visible, then click the desired option using getByRole('option'). For searchable dropdowns, I fill() the search text first, wait for filtered options, then click. I always verify the selected value after selection. The most common mistake is trying selectOption() on a custom dropdown -- it throws an error.
| Question | One-Line Answer |
|---|---|
| frameLocator vs frame()? | frameLocator() is modern and auto-waits. frame() is legacy. Use frameLocator(). |
| page.on vs page.once for dialogs? | once() for single dialog (self-removes). on() for multiple dialogs. |
| How to clear a file upload? | setInputFiles([]) -- pass an empty array. |
| dragTo() not working? | Use manual mouse steps: mouse.down(), mouse.move({ steps }), mouse.up(). |
| keyboard.type() vs fill()? | type() fires key events per character. fill() sets value instantly. |
| How to wait for a spinner? | waitForSelector('.spinner', { state: 'hidden' }) |
| waitForTimeout() in tests? | Never. Use condition-based waits. Sleep masks real timing issues. |
| How to verify a download? | waitForEvent('download'), check suggestedFilename(), saveAs(), verify with fs. |
Key Point: Complex scenarios are interview differentiators. Know iframes, tabs, dialogs, file ops, drag-and-drop, dropdowns, and waits. Practice explaining each in 3-4 sentences.
Answer all 5 questions, then submit to see your score.
1. What is the correct way to interact with elements inside an iframe in Playwright?
2. When handling a JavaScript dialog in Playwright, what happens if you do NOT register a dialog handler?
3. What is the correct way to capture a new tab opened by clicking a link with target="_blank"?
4. When locator.dragTo() does not trigger a drop on a custom drag-and-drop library, what should you do?
5. Why should you never use page.waitForTimeout() (sleep) in production tests?