QA Interview
Playwright Python Pytest Interview Questions (2026)
Prepare for playwright python pytest interview questions with 48 practical answers on fixtures, locators, waits, network mocking, parallelism, CI and debugging.
25 min read | 3,931 words
TL;DR
Prepare for Playwright Python and pytest interviews by explaining the mechanism, product requirement, failure mode, and cleanup owner behind each API. The highest-value topics are fixture lifecycles, context isolation, semantic locators, web-first assertions, network control, parallel data safety, and trace-based debugging.
Key Takeaways
- Separate the responsibilities of Playwright, pytest, and the pytest-playwright integration plugin.
- Explain how BrowserContext isolation protects browser state without isolating backend records.
- Use semantic locators, actionability checks, and retrying assertions instead of fixed sleeps.
- Assign fixture scope and cleanup according to resource ownership and mutation risk.
- Design network interception, authentication reuse, and Page Objects around explicit product contracts.
- Make parallel workers safe with unique data and retain protected failure evidence in CI.
The best way to prepare for playwright python pytest interview questions is to connect each API to a testing decision. You should be able to explain browser isolation, locator retry behavior, fixture ownership, network control, parallel data safety, and the evidence you preserve when a test fails.
This interview hub gives you 48 concise model answers plus runnable examples. Read the Playwright Python fixtures with pytest guide when you want a deeper implementation walkthrough, then use /practice to rehearse the answers aloud.
TL;DR
| Topic | Interview-ready point | Risk to mention |
|---|---|---|
| Runner integration | pytest-playwright supplies page, context, browser, and related fixtures |
Plugin CLI flags do not configure manually created objects |
| Locators | Locators resolve against the current DOM and retry relevant operations | Broad selectors can fail strictness or match the wrong control |
| Waiting | Actions perform actionability checks, while expect assertions retry |
Sleeps hide races and waste the full delay |
| Isolation | Each default page belongs to a fresh browser context |
Backend accounts and records can still collide |
| Parallelism | pytest-xdist uses separate worker processes | Session fixtures usually run once per worker |
| Debugging | Traces, screenshots, logs, and the first exception explain the failure | Retained artifacts can contain credentials or personal data |
A strong candidate names the boundary between Playwright, pytest, and the integration plugin. A senior candidate also explains resource ownership, failure modes, and why a chosen design remains deterministic in CI.
1. Playwright Python Pytest Interview Questions: Core Architecture
Q: What roles do Playwright, pytest, and pytest-playwright each perform?
Playwright is the browser automation library that provides browsers, contexts, pages, locators, events, and web-first assertions. Pytest is the Python runner responsible for discovery, fixtures, parameterization, markers, reporting hooks, and exit status. The pytest-playwright plugin connects them by supplying fixtures and browser-related command-line options, so attributing every feature to Playwright alone is inaccurate.
Q: Why is BrowserContext isolation important?
A BrowserContext behaves like a clean, incognito-style browser profile with separate cookies, local storage, and permissions. The plugin creates a fresh context for each test using its default page fixture, which prevents authentication state from leaking through the browser. That boundary does not reset databases, inboxes, or shared users, so server-side test data still needs deliberate isolation.
Q: When would you choose the sync API instead of the async API?
The sync API fits a conventional pytest suite when tests perform one browser flow at a time and the surrounding code is synchronous. It produces direct code without an await on every browser call, which can reduce framework complexity for many QA teams. Choose the async API when the application harness already uses asyncio or the test must coordinate genuine concurrent async work, and use pytest-playwright-asyncio consistently rather than mixing both APIs in one process flow.
Q: What happens when a test requests the page fixture?
Pytest resolves the fixture dependency through the plugin, which starts or reuses the selected browser and creates an isolated context and page for the test. The test receives a Page object, while plugin teardown closes its owned resources after the test. A test should not cache that page globally because its lifetime ends with the fixture scope.
2. Installation, Configuration, and Collection
Q: How do you install a minimal Playwright Python pytest project?
Install the plugin and browser binary as separate steps because the Python package does not make every browser executable available by itself. The following commands create an isolated environment, install current packages, download Chromium, and verify that pytest can collect the plugin options. In CI, lock the resolved dependency versions after validating the upgrade.
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip pytest pytest-playwright
python -m playwright install chromium
pytest --help
Q: How do you run headed, cross-browser, and targeted tests?
pytest --headed shows the browser, while repeated --browser options create runs for Chromium, Firefox, or WebKit. A node ID such as pytest tests/test_login.py::test_valid_user selects one precise case, and -k filters by name expression. Keep local debugging flags out of the committed CI defaults unless every pipeline job is intended to use them.
Q: Where should stable pytest options be configured?
Place shared discovery rules, registered markers, and modest default options in one supported configuration source such as pyproject.toml or pytest.ini. Repository configuration should make the ordinary command predictable without hiding expensive cross-browser matrices behind a plain pytest. Secrets, deployment URLs, and one-time debug switches belong in environment or CI configuration rather than source-controlled addopts.
Q: Why might --headed or --device appear to have no effect?
The plugin applies its CLI options to the default browser, context, and page fixtures. If framework code calls playwright.chromium.launch() or browser.new_context() directly, those objects are outside the plugin-managed configuration path. Either consume the standard fixtures, override documented option fixtures such as browser_context_args, or pass the needed settings explicitly when constructing manual resources.
3. Locators, Strictness, and Actionability
Q: Why are locators preferred over stored element handles?
A locator describes how to find an element and resolves it against the current DOM when an operation runs. That behavior survives many re-renders that would make a previously captured handle stale or detached. Locators also integrate with strictness, actionability checks, and retrying assertions, making them the primary abstraction for resilient Playwright tests.
Q: Which locator strategy should you choose first?
Start with user-facing semantics such as get_by_role() plus an accessible name, then consider labels, text, alt text, titles, or a stable test ID. A role locator checks the same accessibility concepts that assistive technology uses and makes intent visible in review. CSS and XPath remain available for cases without a meaningful contract, but selectors tied to layout or generated classes are more fragile.
Q: What does strictness mean in Playwright?
Operations that imply one target, such as clicking a locator, fail when the locator resolves to multiple elements. This is useful pressure to make the selector match a unique product concept rather than silently selecting the first node. Use a more specific accessible name or filter when uniqueness is expected, and use nth() only when position itself is part of the requirement.
Q: What checks occur before locator.click()?
Playwright waits for the locator to resolve to exactly one element that is visible, stable, enabled, and able to receive pointer events. If those conditions do not become true before the action timeout, it raises a TimeoutError with a call log. The force=True escape hatch skips some checks, so it should represent a deliberate non-user interaction rather than a routine flakiness fix.
from playwright.sync_api import Page, expect
def test_payment_status_uses_semantic_locators(page: Page) -> None:
page.set_content(
"""
<button onclick="document.querySelector('#status').textContent='Paid'">
Pay now
</button>
<p id="status" role="status">Pending</p>
"""
)
pay_button = page.get_by_role("button", name="Pay now")
expect(pay_button).to_be_enabled()
pay_button.click()
expect(page.get_by_role("status")).to_have_text("Paid")
4. Assertions, Waiting, and Events
Q: How are Playwright assertions different from plain Python asserts?
expect(locator).to_have_text() retries until its condition passes or its assertion timeout expires. A plain assert locator.text_content() == "Ready" takes one snapshot and can fail during a valid transition. Use web-first assertions for changing browser state, while plain asserts remain suitable for already materialized Python values and pure business logic.
Q: Why is page.wait_for_timeout() usually the wrong synchronization tool?
A fixed sleep waits the full duration even when the application becomes ready immediately and still fails when a slower run exceeds the guess. Synchronize on the product signal, such as visible text, a URL, a response, or an enabled control. A short explicit timeout can help reproduce a race during diagnosis, but it should not become the permanent oracle.
Q: How do you wait for a response caused by a click?
Register the expectation before performing the action by using with page.expect_response(predicate) as response_info. The context manager avoids the race where the response arrives before a later listener starts. After the block, inspect response_info.value for status, URL, headers, or JSON that belongs to the requirement.
Q: When should you use wait_for_load_state()?
Navigation methods already wait for their documented load milestone, and locator assertions often express readiness more precisely. Add wait_for_load_state("domcontentloaded") when a new page requires that specific document event, not as a universal post-click ritual. Treat networkidle cautiously because analytics, polling, and persistent connections can make network quiet unrelated to usable UI.
from playwright.sync_api import Page, expect
def test_status_retries_until_the_ui_updates(page: Page) -> None:
page.set_content(
"""
<button onclick="
setTimeout(() => {
document.querySelector('#message').textContent = 'Saved';
}, 100)
">Save</button>
<div id="message" role="status">Waiting</div>
"""
)
page.get_by_role("button", name="Save").click()
expect(page.get_by_role("status")).to_have_text("Saved", timeout=2_000)
For a more detailed explanation of action checks and assertion polling, study Playwright Python auto-waiting and Playwright Python assertions.
5. Pytest Fixtures and State Ownership
Q: How should you choose a pytest fixture scope?
Use function scope for mutable browser or test data unless reuse has a measured cost and a safe reset strategy. Module or session scope can suit an immutable configuration object or expensive service process, but broader scope widens the sharing boundary. Remember that pytest-xdist creates separate worker processes, so session scope is not necessarily once for the entire distributed run.
Q: Why are yield fixtures useful?
Code before yield acquires the resource, the yielded value reaches the test, and code after it performs teardown. This expresses ownership in one place and allows pytest to unwind completed fixture dependencies when a later step fails. Acquire resources in small fixtures or register cleanup immediately after success so partial setup does not strand records.
Q: What is an appropriate use of an autouse fixture?
Autouse is reasonable for a universal invariant such as resetting a clock stub or attaching a required diagnostic listener to every test in a limited directory. It is risky for business data creation because the dependency becomes invisible in the test signature. Prefer an explicit fixture when a reader needs to know that state exists to understand the scenario.
Q: Should a custom fixture close the plugin-provided page?
No, the plugin owns the page and its context, so its teardown should close them. A custom fixture may configure that page, create domain data, and clean up only the resources it acquired. Closing borrowed infrastructure early can break later fixtures and obscure which layer violated the lifetime contract.
from collections.abc import Iterator
import pytest
from playwright.sync_api import Page, expect
@pytest.fixture
def checkout_page(page: Page) -> Iterator[Page]:
page.set_content(
"""
<h1>Checkout</h1>
<p role="status">Cart ready</p>
"""
)
yield page
# The pytest-playwright plugin closes page and context.
def test_checkout_starts_ready(checkout_page: Page) -> None:
expect(checkout_page.get_by_role("heading", name="Checkout")).to_be_visible()
expect(checkout_page.get_by_role("status")).to_have_text("Cart ready")
6. Parameterization, Markers, and Browser Matrices
Q: How should you use pytest.mark.parametrize in UI tests?
Parameterize cases that share the same workflow but represent meaningful boundaries or equivalence classes. Give each row a readable ID so reports identify the failing business case instead of an opaque index. Split the test when a row requires different navigation, setup, or assertions because one large conditional test hides behavior.
Q: How do you run a test only on one browser?
The Playwright plugin provides @pytest.mark.only_browser("chromium") when a scenario is intentionally browser-specific. Use @pytest.mark.skip_browser("firefox") for a documented unsupported combination, including a nearby reason or issue reference. Do not use browser marks to conceal an unexplained product defect that should fail the compatibility matrix.
Q: What is the difference between -k and -m?
-k selects collected items by a name expression involving test names, classes, files, and keywords. -m evaluates registered marker expressions such as smoke and not destructive. Markers should express a stable execution property, while test names should express behavior. Use both selectors in local triage only when their scopes remain clear.
Q: Why are descriptive parameter IDs operationally valuable?
IDs become part of each node ID, test report, rerun command, and CI failure message. A case named quantity-zero is easier to triage than case2, especially when dozens of rows execute across browsers. Keep IDs stable enough for tooling, but do not encode secrets or volatile customer data in them.
import pytest
from playwright.sync_api import Page, expect
@pytest.mark.parametrize(
("quantity", "expected"),
[(0, "Empty cart"), (1, "1 item"), (3, "3 items")],
ids=["zero", "single", "multiple"],
)
def test_cart_quantity_message(
page: Page, quantity: int, expected: str
) -> None:
page.set_content(
"""
<input aria-label="Quantity" type="number">
<button onclick="
const value = Number(document.querySelector('input').value);
document.querySelector('#result').textContent =
value === 0 ? 'Empty cart' : value === 1 ? '1 item' : value + ' items';
">Update</button>
<p id="result" role="status"></p>
"""
)
page.get_by_label("Quantity").fill(str(quantity))
page.get_by_role("button", name="Update").click()
expect(page.get_by_role("status")).to_have_text(expected)
7. Network Mocking and API Testing
Q: What is the difference between observing and intercepting network traffic?
Event listeners such as page.on("response", handler) observe traffic without changing it. page.route() or context.route() intercepts matching requests and can continue, abort, or fulfill them. Choose observation for evidence and interception for a controlled test condition, then remove or scope routes so they do not affect unrelated requests. An interception handler should fail loudly when an unexpected request shape reaches it.
Q: Why might you define a route on BrowserContext instead of Page?
A context route applies to requests from every page in that context, including popups created later. That scope is useful when authentication, feature flags, or a shared backend stub must cover a multi-page workflow. A page route is safer when only one tab needs the override because its smaller blast radius reduces accidental masking.
Q: How does Playwright support direct API testing?
APIRequestContext sends HTTP requests without rendering a page and can seed server state or verify postconditions. The plugin exposes a playwright fixture from which a suite can create a request context, while browser_context.request shares cookie storage with that browser context. Dispose manually created request contexts and avoid logging authorization headers or response bodies containing sensitive data.
Q: Does a 404 response trigger requestfailed?
No, an HTTP error status still represents a completed HTTP exchange, so it produces a response rather than a transport failure. requestfailed covers failures such as name resolution, connection errors, or cancellation before an HTTP response completes. Assert response.status for status-code behavior and inspect failure details only for the transport path. This distinction prevents a server-side validation defect from being mislabeled as network instability.
import json
from playwright.sync_api import Page, Route, expect
def test_profile_ui_with_an_intercepted_api(page: Page) -> None:
def serve_app(route: Route) -> None:
if route.request.url.endswith("/api/profile"):
route.fulfill(
status=200,
content_type="application/json",
body=json.dumps({"name": "Asha"}),
)
return
route.fulfill(
status=200,
content_type="text/html",
body="""
<button onclick="
fetch('/api/profile')
.then(response => response.json())
.then(data => {
document.querySelector('#profile').textContent = data.name;
})
">Load profile</button>
<p id="profile" role="status"></p>
""",
)
page.route("https://app.example.test/**", serve_app)
page.goto("https://app.example.test/")
page.get_by_role("button", name="Load profile").click()
expect(page.get_by_role("status")).to_have_text("Asha")
Practice broader interception tradeoffs with Playwright Python network mocking and direct service checks with Playwright Python API testing.
8. Popups, Downloads, Uploads, and Dialogs
Q: How do you test a popup opened by a user action?
Wrap the triggering click in with page.expect_popup() as popup_info, then obtain the new page from popup_info.value. This ordering captures a popup even when it opens immediately. Assert a stable URL or visible element in the popup, and let the owning context close it during normal teardown.
Q: How do you verify a download without relying on a shared folder?
Use with page.expect_download() around the action and inspect the returned Download. Validate the suggested filename, then save to tmp_path when file contents are part of the contract. The temporary per-test directory prevents filename collisions across parallel workers.
Q: What is the reliable way to upload a file?
Create the content under pytest's tmp_path, locate the file input or file chooser, and call set_input_files() with that path. This bypasses operating-system picker automation while exercising the browser's upload behavior. Assert the product outcome, such as an uploaded filename or server confirmation, rather than only checking that the input accepted a path.
Q: How are JavaScript dialogs handled?
Register page.expect_dialog() or a page.on("dialog") handler before the action that opens the alert, confirm, or prompt. Accept or dismiss it and optionally validate its type and message. An unhandled dialog can block the triggering action, so handler timing matters more than adding a delay.
9. Authentication Reuse and Page Objects
Q: When should authentication state be reused?
Reuse a verified storage-state file when login is not the behavior under test and repeated authentication is slow or rate limited. Generate the state in a controlled setup, keep it short lived, and refresh it when the account or environment changes. Maintain separate direct login tests so reuse does not eliminate coverage of the authentication journey.
Q: What security risks come with storage_state?
The file can contain session cookies and local-storage tokens that grant account access. Exclude it from version control, restrict CI artifact access, and use a low-privilege test identity. A trace or video recorded after login may expose the same class of information, so artifact retention needs equal scrutiny.
Q: What belongs in a Page Object?
A Page Object should expose meaningful UI operations and stable component locators, such as signing in or adding a product. Assertions can remain in tests when they describe the scenario outcome, while component-level readiness checks may live near the component contract. Avoid a generic wrapper for every Playwright method because it adds indirection without expressing the product domain.
Q: Why is composition often better than a deep Page Object inheritance tree?
Modern pages share components such as navigation, dialogs, and tables rather than forming a clean inheritance hierarchy. Composing small component objects lets a page use exactly what it contains and prevents a base class from accumulating unrelated helpers. This structure also makes locators easier to review when one component changes.
from playwright.sync_api import Page, expect
class LoginPage:
def __init__(self, page: Page) -> None:
self.page = page
self.email = page.get_by_label("Email")
self.password = page.get_by_label("Password")
self.submit = page.get_by_role("button", name="Sign in")
def load_test_document(self) -> None:
self.page.set_content(
"""
<label>Email <input type="email"></label>
<label>Password <input type="password"></label>
<button onclick="
document.querySelector('#result').textContent = 'Welcome';
">Sign in</button>
<p id="result" role="status"></p>
"""
)
def sign_in(self, email: str, password: str) -> None:
self.email.fill(email)
self.password.fill(password)
self.submit.click()
def test_login_page_object_exposes_user_intent(page: Page) -> None:
login = LoginPage(page)
login.load_test_document()
login.sign_in("qa@example.test", "local-test-value")
expect(page.get_by_role("status")).to_have_text("Welcome")
See Playwright Python authentication reuse for state lifecycle details and Playwright Python page object model for maintainable composition patterns.
10. Playwright Python Pytest Interview Questions: Parallelism and CI
Q: How does pytest-xdist change test execution?
pytest-xdist distributes collected tests to separate worker processes with commands such as pytest -n auto. Ordinary Python globals are not shared across those processes, but external systems remain shared. Size the worker count for browser memory and backend capacity instead of assuming the CPU count is always optimal.
Q: Why can session-scoped fixtures surprise teams under xdist?
Each worker runs its own pytest session, so a session fixture commonly initializes once in every worker. That can create duplicate tenants, collide on a fixed port, or exceed a service quota. Use worker-aware names, a controller-side provisioning strategy, or a truly concurrency-safe shared resource based on what the dependency supports.
Q: Which xdist distribution mode would you choose?
The default load scheduling balances individual tests well when cases are independent. loadscope keeps a module or class together, loadfile groups a file, and loadgroup honors explicit xdist_group marks for resources that must share a worker. Grouping improves fixture reuse but can reduce load balance, so select it from measured suite behavior. Start with load and change modes only when fixture affinity provides a concrete benefit.
Q: What artifacts should CI retain for failed browser tests?
Start with the pytest failure and Playwright trace because together they show the assertion, action timeline, DOM snapshots, and network activity. Add a screenshot, video, console output, or application logs only when each artifact answers a recurring diagnostic question. Apply access controls and retention limits because browser evidence can capture user data, tokens, and internal URLs.
pytest tests/e2e \
-n 4 \
--dist load \
--tracing retain-on-failure \
--screenshot only-on-failure \
--output test-results
python -m playwright show-trace test-results/path-to-trace.zip
11. Debugging Failures and Flaky Tests
Q: How do you investigate a strict mode violation?
Read the call log to see the locator and every matching element, then inspect whether the product contract expects one or many. Refine the locator with a role, accessible name, parent scope, or filter that represents the intended control. Using .first merely to silence ambiguity is defensible only when first position is itself a tested rule.
Q: What is your process for a Playwright timeout?
Identify whether the timeout came from navigation, an actionability check, an event wait, or an assertion because each points to a different stalled condition. Inspect the trace and the earliest application error, reproduce the node ID alone, and compare the expected product signal with what appeared. Increase a targeted timeout only after confirming that the operation is valid but legitimately needs a larger failure budget.
Q: How do you diagnose a CI-only failure?
Compare browser build, operating system dependencies, viewport, locale, timezone, base URL, environment variables, worker count, and backend data with the local run. Retain a trace from CI and reproduce inside the same container or image when possible. Change one variable at a time so the eventual fix has evidence rather than coincidence.
Q: Are automatic reruns a good fix for flakiness?
No, a rerun changes reporting but leaves the race, shared state, or environmental limit in place. If policy temporarily reruns a quarantined test, preserve the first failure and assign an owner plus expiry. The durable fix removes the uncontrolled variable or synchronizes on an observable condition.
12. Advanced Framework Decisions
Q: When should you create contexts manually instead of using page?
Manual contexts are justified when one test must model multiple independent users, grant distinct permissions, or control context lifetime explicitly. Create each with browser.new_context(), close each in a finally block or owning fixture, and keep the default path plugin-managed. Do not use browser.new_page() in framework code when you need exact context ownership because it is a convenience for short single-page snippets.
Q: How would you test two users interacting in one scenario?
Create two BrowserContexts from the browser fixture, then open one page per context so cookies and local storage remain separate. Allocate distinct backend identities and correlate the shared business object, such as an order or chat room, through an API or fixture. Assert each user's observable state and close both contexts even when the first assertion fails.
Q: How do sync and async Playwright tests differ under pytest?
Sync tests import from playwright.sync_api and call methods directly, while async tests import from playwright.async_api and await browser operations. Current Playwright guidance uses pytest-playwright-asyncio for async fixtures and requires a compatible pytest-asyncio configuration. A framework should select one model for a suite boundary because passing sync objects into async helpers produces confusing ownership and event-loop problems.
Q: How would you review a Playwright Python pytest framework design?
Trace one test from collection through fixtures, browser context creation, data setup, assertion, artifact capture, and cleanup. Check semantic locators, bounded waits, secret handling, parallel resource naming, plugin configuration, and whether helpers expose business intent. Then run the case alone, in a browser matrix, and with multiple workers to reveal hidden order or capacity assumptions.
How Interviewers Grade Your Answers
Interviewers usually score more than API recall. Use this answer structure for design questions:
- State the mechanism and which tool owns it.
- Connect it to a concrete test requirement.
- Name one realistic failure mode or tradeoff.
- Explain the verification signal and cleanup owner.
A junior answer may correctly show page.get_by_role("button").click(). A stronger answer explains why the accessible name is the selector contract, what actionability checks guard the click, which assertion proves the outcome, and how a trace exposes failure. For framework questions, expect follow-ups about worker processes, backend data, secrets, and partial setup failures.
During a coding round, keep the first solution small and executable. Run collection, execute one node ID, and narrate why every fixture and wait exists. If you want targeted practice before the interview, compare these answers with the broader top pytest interview questions and bring one real framework tradeoff from your own project.
Common Mistakes
- Saying Playwright supplies parameterization or that pytest supplies browser locators, which blurs ownership.
- Treating a fresh BrowserContext as proof that server-side test data is isolated.
- Replacing web-first assertions with immediate
text_content()checks on changing UI. - Adding
wait_for_timeout()after every action instead of waiting for a product signal. - Using
.first,force=True, or blanket retries to hide an unexplained failure. - Closing plugin-owned pages inside fixtures that did not create them.
- Assuming a session fixture runs only once across all xdist workers.
- Recording authentication state, traces, or videos without protecting secrets.
- Building Page Objects as a mirror of HTML rather than a vocabulary of user operations.
- Increasing the global timeout until an overloaded environment appears green.
Correct these problems by making dependencies, state boundaries, and expected outcomes visible in code. A maintainable suite has a clear owner for every context, account, route, artifact, and cleanup action.
Conclusion
These playwright python pytest interview questions cover the decisions interviewers use to distinguish API familiarity from framework engineering. Prepare concise explanations for isolation, fixtures, locators, retry behavior, network control, artifacts, and parallel data ownership, then support each explanation with one concrete failure mode.
Run the examples locally, adapt one to your application, and practice explaining the tradeoff without reading notes. That combination of executable code and operational reasoning is what makes an answer credible.
Interview Questions and Answers
What is the relationship between Playwright, pytest, and pytest-playwright?
Playwright controls browsers and exposes pages, locators, events, and assertions. Pytest collects and runs tests while resolving fixtures and parameters. The pytest-playwright plugin supplies browser fixtures and CLI integration between them.
How does the page fixture isolate tests?
The plugin gives each test a page inside a fresh BrowserContext. Cookies and local storage therefore start separately from another test. External records remain shared unless the framework creates unique data.
Why are Playwright locators resilient?
A locator resolves against the current DOM when an operation executes. It participates in strictness, actionability, and retrying assertions. Semantic role or label locators also express a more stable user-facing contract.
What is a web-first assertion?
It is an assertion such as `expect(locator).to_be_visible()` that polls until the browser condition succeeds or times out. This matches asynchronous UI behavior without a fixed delay. The timeout remains a failure budget rather than test pacing.
How do you manage teardown in pytest fixtures?
A yield fixture acquires resources before `yield` and releases its own resources afterward. Dependencies that completed setup unwind even when the test fails. Cleanup should sit close to successful acquisition so partial setup remains safe.
How do you mock an API response in Playwright Python?
Register `page.route()` or `context.route()` before the request occurs. The handler can fulfill a deterministic response, continue the request, or abort it. Scope the route narrowly and assert the visible or service-level result.
Why can xdist expose test design defects?
Workers execute in separate processes and do not preserve a dependable test order. They can still collide through shared users, ports, files, and backend rows. Parallel failures often reveal hidden state or capacity assumptions.
How do you debug a Playwright timeout?
Classify the timed-out operation first, then inspect its call log and trace. Reproduce the exact node ID and compare the expected signal with the captured DOM and network state. Change the timeout only when a valid operation has a justified longer limit.
What should a Page Object contain?
It should provide product-language operations and stable locators for a page or component. Keep scenario outcomes visible in tests where that improves clarity. Favor composition so shared components do not create a bloated inheritance hierarchy.
What makes a senior Playwright Python interview answer strong?
A senior response identifies API ownership, state boundaries, and resource cleanup. It names a plausible failure mode and the evidence used to diagnose it. It also explains how the choice behaves under parallel CI execution.
Frequently Asked Questions
What should I study for a Playwright Python pytest interview?
Prioritize fixture lifecycles, BrowserContext isolation, locator strictness, actionability, web-first assertions, network routing, authentication state, and CI artifacts. Add pytest parameterization, markers, configuration, and xdist worker behavior. Practice explaining a failure mode for each feature.
Is pytest-playwright the same as Playwright?
No. Playwright is the automation library, while pytest-playwright is the integration plugin that supplies pytest fixtures and browser CLI options. Pytest still controls discovery, fixture resolution, parameterization, and reporting.
Should Playwright Python tests use sync or async APIs?
Use the sync API for a straightforward synchronous pytest suite. Select the async API when the surrounding architecture genuinely relies on asyncio, and install the documented async pytest integration. Keep the execution model consistent within the suite.
How many Playwright Python interview questions should I practice?
Depth matters more than memorizing a number. Cover at least one question in every major area: setup, fixtures, locators, waiting, events, network, files, authentication, architecture, parallelism, and debugging. Rehearse follow-ups that ask for tradeoffs.
Are Playwright tests automatically free from flakiness?
No. Auto-waiting removes many timing guesses, but unstable data, ambiguous locators, environment contention, and product races still cause nondeterminism. Use traces and repeated controlled runs to identify the variable.
Can Playwright Python pytest tests run in parallel?
Yes, pytest-xdist can distribute cases across worker processes. Browser contexts isolate browser state, but accounts, files, queues, and database rows need worker-safe allocation. Choose worker count from measured capacity.
What should CI save when a Playwright test fails?
Retain the original pytest error and a Playwright trace first. Add screenshots, video, console logs, or server logs when they shorten recurring investigations. Protect and expire artifacts because they may contain sensitive state.
Related Guides
- Junior SDET Playwright Trace Debugging Interview Questions (2026)
- Playwright API Testing Interview Questions (2026)
- Playwright Component Testing Interview Questions for Angular (2026)
- Playwright Debugging Interview Questions for Senior QA (2026)
- Playwright Fixtures Interview Questions for TypeScript Testers (2026)
- Playwright Network Mocking Interview Questions for Senior QA (2026)