Playwright Interview Q&A (Polished
Answers)
What is WebSocket?
WebSocket is a communication protocol that provides full-duplex, real-time communication
between the client and server over a single TCP connection. Unlike HTTP, which is request-
response based, WebSockets allow the server to push updates instantly to the client. They
are widely used in real-time applications like chat systems, stock tickers, and gaming
platforms.
How does Playwright handle browser-level events, like a new tab or window?
Playwright provides event listeners like `page.on` or `context.waitForEvent` to handle
browser-level events. For example, when clicking a link that opens a new tab, I would use
`context.waitForEvent('page')` in parallel with the click. This ensures my test waits for the
new tab to appear, and I can then interact with it. This makes Playwright very reliable for
multi-tab workflows.
Why are user-facing locators preferred over CSS/XPath selectors?
I prefer user-facing locators such as `getByRole`, `getByLabel`, or `getByText` because they
directly map to how a user interacts with the UI. They are less brittle compared to CSS or
XPath, since they don’t break if the DOM structure or CSS changes. This makes tests more
stable and maintainable in the long run.
When might you still use CSS or XPath in Playwright?
Although user-facing locators are the first choice, there are cases where CSS or XPath is still
useful. For example, when dealing with legacy applications that don’t have proper
accessibility roles, or when I need to traverse parent-child or sibling relationships in the
DOM. They’re also handy for dynamic elements with generated IDs or for quick debugging.
So, I use them only when user-facing locators are not sufficient.
Difference between locator.click() and page.click() when multiple elements
exist. Which is safer?
`page.click()` resolves the selector immediately and clicks the first matching element, which
can lead to flakiness if multiple elements match or the DOM updates. In contrast,
`locator.click()` re-resolves the element each time, has built-in auto-waiting, and throws an
error if multiple elements match unless I refine it with `.first()` or `.nth()`. This strictness
makes `locator.click()` the safer and more robust choice for automation.
How do you handle dynamic or non-deterministic elements in Playwright?
For dynamic elements like generated IDs, I avoid relying on brittle selectors. Instead, I use
stable strategies such as user-facing locators, or I work with `data-testid` attributes if the
developers provide them. If that’s not possible, I use partial attribute matching like `id^=`,
`id*=`, or refine locators with `hasText` or `has`. In lists, I might use `.first()`, `.last()`, or
`.nth()`. This approach keeps my tests stable even in highly dynamic UIs.
How does Playwright interact with shadow DOM elements?
Playwright natively supports shadow DOM, so I can directly interact with elements inside it
using locators. I usually chain locators with `>>` or use `locator().locator()` for clarity. For
example, `page.locator('custom-element >> button#submit')` works without extra
JavaScript. This makes Playwright much simpler than Selenium, where you need JS
execution to pierce shadow roots.