Skip to content

Latest commit

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Playwright Automation with Python and Pytest Showcase

Written by Brian McCarthy

A complete hands-on Playwright automation guide using Python, Pytest, pytest-playwright, Page Object Model design, fixtures, web-first assertions, API testing, network interception, login testing, CI/CD execution, data-driven testing, behavior-driven development, Docker, visual testing, and framework architecture.

This README is organized as a numbered tutorial. Each module explains the main purpose, what the user needs to know, code examples, and expected results. Supplemental modules add framework-building guidance, framework-selection guidance, advanced CI/CD, API testing, and login testing material.


Table of Contents

Section / ModuleContents Covered
1. Project OverviewExplains the purpose of the repository and the Playwright/Python/Pytest automation topics covered.
2. Repository GoalsLists the portfolio and learning objectives for UI automation, API testing, fixtures, POM, CI/CD, login testing, and framework design.
3. Languages, Tools, and FrameworksSummarizes Python, Playwright, Pytest, pytest-playwright, Behave, GitHub API, GitHub Actions, Docker, visual tools, and JavaScript/TypeScript concepts.
4. Project File LinksLinks to the repository’s S01-S21 sections and describes each folder’s main focus.
5. Core CommandsProvides setup and execution commands for dependencies, browsers, Pytest, tracing, and Behave.
6. Module 1 - Getting StartedCovers installation, browser launch, first navigation, link clicking, and basic script structure.
7. Module 2 - LocatorsCovers role, input, text, alt text, title, CSS, hierarchy, pseudo-class, XPath, test ID, and filtering locator strategies.
8. Module 3 - ActionsCovers mouse actions, keyboard actions, text input, radio buttons, checkboxes, switches, select options, dropdowns, and uploads.
9. Module 4 - EventsCovers auto-waiting, navigation waits, event listeners, dialogs, downloads, popups, and sync/async usage.
10. Module 5 - AuthenticationCovers login flows, saved storage state, auth reuse, edge cases, MFA limitations, and credential handling.
11. Module 6 - Automated Mail CheckerCovers mailbox automation, locating new emails, extracting sender/subject/body data, and terminal checks.
12. Module 7 - PytestCovers writing/running tests, type hints, test state, fixtures, fixture usage, fixture scope, and assertions.
13. Module 8 - pytest-playwright PluginCovers plugin setup, page/browser fixtures, Pytest config, hooks, and browser CLI options.
14. Module 9 - Playwright ToolsCovers codegen, inspector, headed mode, slow motion, screenshots, traces, videos, and debugging.
15. Module 10 - Web-First AssertionsCovers page, element, text, attribute, input, checkbox, option menu, generic assertion, and soft assertion patterns.
16. Module 11 - UI Testing PlaygroundCovers dynamic IDs, hidden layers, Ajax, dynamic tables, progress bars, visibility, hover, NBSP, and overlays.
17. Module 12 - Playwright FixturesCovers function/session fixtures, browser selection, launch args, context args, and reusable setup.
18. Module 13 - Page Object ModelCovers POM design, reusable page classes, locator encapsulation, page methods, and readable tests.
19. Module 14 - Network EventsCovers request/response inspection, routing, interception, mocked responses, blocking resources, and response modification.
20. Module 15 - API TestingCovers API request contexts, GET/POST/PUT/PATCH/DELETE, query strings, response assertions, auth headers, and cleanup.
21. Module 16 - OptimizationCovers blocking images/fonts, disabling JavaScript, parallel execution, selective runs, and performance-friendly patterns.
22. Module 17 - Tips and TricksCovers CLI args, debugger usage, device emulation, JavaScript evaluation, reports, and local debugging.
23. Module 18 - GitHub APICovers GitHub API testing, token usage, authorized request contexts, public repo metadata, and environment variables.
24. Module 19 - Continuous IntegrationCovers GitHub Actions setup, browser installation, CI-safe execution, artifacts, reports, and PR validation.
25. Module 20 - Data-Driven TestingCovers Pytest parametrization, multiple input rows, expected results, and coverage expansion.
26. Module 21 - Behavior-Driven DevelopmentCovers Behave, Gherkin feature files, Given/When/Then steps, hooks, and scenario execution.
27. Supplemental Module 22 - Playwright vs CypressCompares Playwright and Cypress architecture, browser support, API testing, locator style, and best-fit scenarios.
28. Supplemental Module 23 - Development Environment, Test Application, and JavaScript TypeScript FundamentalsCovers environment checks, VS Code/Git/Node/Python setup, JavaScript basics, and TypeScript concepts.
29. Supplemental Module 24 - DOM Terminology and Advanced Locator ArchitectureCovers DOM structure, attributes, IDs, classes, parent/child locators, filters, extracted values, test IDs, and timeouts.
30. Supplemental Module 25 - Advanced UI Widgets and Complex InteractionsCovers tooltips, tables, date pickers, sliders, iframes, drag-and-drop, and overlapped elements.
31. Supplemental Module 26 - Advanced Page Object ArchitectureCovers base pages, helper methods, page managers, reusable components, and scalable framework architecture.
32. Supplemental Module 27 - Advanced API State, Mocking, Authentication, and CleanupCovers API preconditions, UI/API hybrid flows, API login, mocked state, browser response capture, and teardown cleanup.
33. Supplemental Module 28 - Advanced Framework Configuration, Environment Variables, Retries, Tags, and Test DataCovers .env, Faker, Pytest markers, retries, parallel workers, global setup/teardown, and test data strategy.
34. Supplemental Module 29 - Reporting, Screenshots, Videos, and Visual TestingCovers screenshots, element screenshots, videos, snapshot testing, report export, Allure-style reports, and visual diffing.
35. Supplemental Module 30 - Docker, GitHub Actions, and Argos CICovers Dockerfile setup, docker-compose, report volume mapping, GitHub Actions artifacts, and Argos visual validation.
36. Supplemental Module 31 - Building a Playwright Framework from ScratchExplains when to build a custom framework, required files, required dependencies, folder structure, setup steps, and starter code.
37. Supplemental Module 32 - Custom Framework vs Out-of-the-Box FrameworkExplains when a custom framework is worth it and when to use popular existing Playwright tooling or templates.
38. Supplemental Module 33 - Best and Popular Playwright Framework Options by ScenarioDescribes recommended Playwright framework approaches for UI testing, API testing, BDD, visual testing, CI, Docker, enterprise use, and quick projects.
39. Supplemental Module 34 - Thorough CI/CD Strategy for PlaywrightAdds detailed CI/CD pipeline stages, artifacts, secrets, browser install, matrix runs, quality gates, and GitHub Actions examples.
40. Supplemental Module 35 - Thorough API Testing StrategyAdds detailed API testing design, request clients, fixtures, schemas, auth headers, CRUD tests, cleanup, negative tests, and expected results.
41. Supplemental Module 36 - Thorough Login Testing StrategyAdds login test coverage for valid login, invalid login, locked users, session reuse, storage state, logout, MFA notes, and secure credentials.
42. Playwright Automation Top 20 Interview Questions and AnswersProvides top Playwright interview Q&A covering framework concepts, contexts, locators, auto-waiting, assertions, POM, API testing, network mocking, CI, and debugging.
43. Best Practices and TroubleshootingSummarizes Playwright best practices and fixes for missing browsers, flaky locators, login failures, 401s, downloads, and CI differences.
44. AuthorLists author credit for Brian McCarthy and the Playwright automation showcase.

1. Project Overview

This repository demonstrates browser automation and test engineering with Playwright for Python. It starts with installation and browser launch scripts, then progresses into locators, actions, event handling, authentication, automated email checking, Pytest, plugin fixtures, Playwright debugging tools, web-first assertions, UI challenge automation, custom fixtures, Page Object Model, network events, API testing, performance optimization, GitHub API automation, CI/CD, data-driven testing, BDD, Docker, and visual validation.

The repository is designed as a practical learning and portfolio project. It shows that the author can create reliable UI tests, API tests, login tests, reusable fixtures, maintainable page objects, CI-ready automation, Docker-compatible runs, and scalable framework patterns.


2. Repository Goals

  1. Demonstrate Playwright automation in Python.
  2. Show reliable locator strategies for modern web apps.
  3. Use realistic user actions: clicks, text input, file upload, dropdowns, keyboard shortcuts, hover, and drag-and-drop.
  4. Handle auto-waiting, navigation, dialogs, downloads, asynchronous operations, and events.
  5. Save and reuse authentication state.
  6. Build Pytest test cases with fixtures and scoped setup.
  7. Use pytest-playwright fixtures such as page, context, and browser.
  8. Apply web-first assertions to reduce flaky test behavior.
  9. Organize UI automation with Page Object Model.
  10. Test APIs with Playwright request contexts.
  11. Mock and intercept network requests.
  12. Improve runtime with optimization patterns.
  13. Run tests in CI/CD using GitHub Actions.
  14. Expand coverage using data-driven and BDD techniques.
  15. Build or evaluate custom Playwright framework architecture.
  16. Add supplemental coverage for environment setup, JavaScript/TypeScript fundamentals, advanced widgets, reporting, Docker, and visual validation.

3. Languages, Tools, and Frameworks

Tool / LanguagePurpose
PythonMain automation language
Playwright for PythonBrowser automation, UI assertions, event handling, API request contexts, tracing, screenshots, and network mocking
PytestTest discovery, test execution, fixtures, parametrization, and reporting
pytest-playwrightPlugin-provided browser/page/context fixtures and command-line browser options
BehaveBDD feature files and Given/When/Then step definitions
FakerTest data generation
python-dotenvEnvironment configuration from .env files
pytest-xdistParallel test execution
pytest-rerunfailuresControlled retry behavior for unstable external dependencies
GitHub APIAuthenticated API automation practice
GitHub ActionsContinuous integration and delivery execution
DockerContainerized test execution
Visual comparison toolsScreenshot comparison and visual regression workflows
JavaScript / TypeScript conceptsSupplemental understanding for users who read JS/TS Playwright examples or migrate frameworks

4. Project File Links

SectionLinkMain Focus
1S01 - Getting StartedInstallation, browser launch, documentation, link clicking, script overview
2S02 - LocatorsRole, input, text, alt text, title, CSS, XPath, and other locators
3S03 - ActionsMouse, text input, radio buttons, checkboxes, switches, select options, dropdowns, uploads, shortcuts
4S04 - EventsAuto-waiting, navigation waits, custom waits, listeners, dialogs, downloads, sync/async
5S05 - AuthenticationSign-in, storage state, auth reuse, login edge cases
6S06 - Automated Mail CheckerEmail location, email data extraction, combined locators, terminal checks
7S07 - pytestPytest basics, writing/running tests, type hints, state, fixtures, scope
8S08 - pytest-playwright PluginPlugin setup, Playwright tests, config, hooks
9S09 - Playwright ToolsCodegen, inspector, trace viewer, screenshots, debugging tools
10S10 - Web-First AssertionsPage, element state, text, attributes, inputs, checkboxes, option menus
11S11 - UI Testing PlaygroundDynamic IDs, hidden layers, Ajax, dynamic tables, progress bars, visibility, login, hover
12S12 - Playwright FixturesFunction scope, session scope, browser selection, launch/context args
13S13 - Page Object ModelPOM implementation and usage
14S14 - Network EventsRequests, request handling, response modification
15S15 - API TestingAPI calls, request context, query strings, CRUD, mocks
16S16 - OptimizationRequest interception, disabling JavaScript, parallel execution
17S17 - Tips and TricksCLI args, debugger, device emulation, JS evaluation, reports
18S18 - GitHub APIToken setup, authorized API context, GitHub tests
19S19 - Continuous IntegrationGitHub Actions, automated test runs
20S20 - Data Driven TestingPytest parametrization
21S21 - Behaviour Driven DevelopmentBehave feature files and step implementations

5. Core Commands

pip install pytest playwright pytest-playwright behave faker python-dotenv pytest-xdist pytest-rerunfailures
playwright install
pytest
pytest --headed
pytest --browser chromium
pytest path/to/test_file.py
pytest -k login
pytest -m smoke
pytest -n auto
pytest --tracing on
playwright show-trace trace.zip
behave

Expected result: Dependencies install, Playwright browsers are downloaded, Pytest/Behave discover tests, and pass/fail results are printed in the terminal.


6. Module 1 - Getting Started

Subtopics covered: Playwright installation, Playwright documentation, browser launch, clicking a link element, and script overview.

fromplaywright.sync_apiimportsync_playwrightwithsync_playwright() asp:
browser=p.chromium.launch(headless=False)
page=browser.new_page()
page.goto("https://playwright.dev/python/")
print(page.title())
page.get_by_role("link", name="Docs").click()
print(page.url)
browser.close()

Expected result: Chromium opens, loads the Playwright Python site, prints the title, clicks the Docs link, prints the resulting URL, and closes.

Fast and reliable end-to-end testing for modern web apps | Playwright Python
https://playwright.dev/python/docs/intro

7. Module 2 - Locators

Subtopics covered: Role locators, input locators, text locators, alt text, title, CSS selectors, hierarchy, pseudo-classes, XPath, XPath functions, and other locator strategies.

fromplaywright.sync_apiimportPage, expectdeftest_locator_examples(page: Page):
page.goto("https://playwright.dev/python/")
expect(page.get_by_role("heading", name="Playwright")).to_be_visible()
page.get_by_role("link", name="Docs").click()
expect(page).to_have_url(lambdaurl: "docs"inurl)
deftest_css_and_xpath(page: Page):
page.goto("https://example.com")
page.locator("main nav a:first-child").click()
page.locator("xpath=//button[contains(., 'Save')]").click()

Expected result: Elements are found by accessibility role, text, CSS hierarchy, pseudo-class, or XPath function and then interacted with.


8. Module 3 - Actions

Subtopics covered: Mouse actions, text input, radio buttons, checkboxes, switches, select options, dropdown menus, file upload, and keyboard shortcuts.

fromplaywright.sync_apiimportPage, expectdeftest_form_actions(page: Page):
page.goto("https://example.com/form")
page.get_by_label("First Name").fill("Brian")
page.get_by_label("Subscribe").check()
page.get_by_label("Country").select_option("US")
page.locator("input[type='file']").set_input_files("tests/data/sample.txt")
page.keyboard.press("Control+S")
page.get_by_role("button", name="Submit").click()
expect(page.get_by_text("Form submitted")).to_be_visible()

Expected result: Text fields are filled, checkbox-style controls are selected, dropdowns change, a file is attached, keyboard shortcuts are sent, and the form is submitted.


9. Module 4 - Events

Subtopics covered: Auto-waiting, navigation waiting, custom waits, event listeners, dialogs, downloads, sync vs. async Playwright.

fromplaywright.sync_apiimportPage, expectdeftest_dialog(page: Page):
page.goto("https://the-internet.herokuapp.com/javascript_alerts")
page.on("dialog", lambdadialog: dialog.accept())
page.get_by_text("Click for JS Alert").click()
expect(page.locator("#result")).to_have_text("You successfully clicked an alert")
deftest_download(page: Page):
page.goto("https://example.com/downloads")
withpage.expect_download() asdownload_info:
page.get_by_text("Download report").click()
download_info.value.save_as("downloaded-report.pdf")

Expected result: Dialogs are handled and downloads are captured safely using Playwright event APIs.


10. Module 5 - Authentication

Subtopics covered: Sign-in concepts, saving authentication state, reusing authentication state, and login problems.

fromplaywright.sync_apiimportsync_playwrightwithsync_playwright() asp:
browser=p.chromium.launch(headless=False)
context=browser.new_context()
page=context.new_page()
page.goto("https://example.com/login")
page.get_by_label("Email").fill("user@example.com")
page.get_by_label("Password").fill("password")
page.get_by_role("button", name="Sign in").click()
context.storage_state(path="auth_state.json")
browser.close()
deftest_reuse_auth_state(browser):
context=browser.new_context(storage_state="auth_state.json")
page=context.new_page()
page.goto("https://example.com/account")
assert"account"inpage.url

Expected result: The first script creates auth_state.json; the test reuses it and skips repetitive login steps.


11. Module 6 - Automated Mail Checker

Subtopics covered: Project setup, locating new emails, locating email data, combining locators, and checking email data from terminal execution.

fromplaywright.sync_apiimportPage, expectdeftest_locate_email(page: Page):
page.goto("https://example-mail-app.test/inbox")
email=page.locator(".email-row").filter(has_text="Password reset")
expect(email).to_be_visible()
expect(email.locator(".subject")).to_contain_text("Password reset")

Expected result: The test finds the target email row and verifies the subject.


12. Module 7 - Pytest

Subtopics covered: Writing tests, running tests, type hints, test state, fixtures, fixture usage, and fixture scope.

importpytest@pytest.fixturedefuser_data() ->dict:
return {"username": "brian", "role": "qa"}
deftest_user_role(user_data: dict):
assertuser_data["role"] =="qa"

Expected result: Pytest injects the fixture and reports the test as passed.

1 passed

13. Module 8 - pytest-playwright Plugin

Subtopics covered: Installing the plugin, writing Playwright tests with plugin fixtures, Pytest config, running tests, and hooks.

fromplaywright.sync_apiimportPage, expectdeftest_homepage(page: Page):
page.goto("https://playwright.dev/python/")
expect(page).to_have_title(lambdatitle: "Playwright"intitle)
[pytest]addopts = --browser chromium

Expected result: The plugin creates the page fixture automatically and runs the browser test.


14. Module 9 - Playwright Tools

Subtopics covered: Codegen, inspector, headed mode, slow motion, screenshots, tracing, trace viewer, videos, and reports.

deftest_screenshot(page):
page.goto("https://playwright.dev/python/")
page.screenshot(path="homepage.png", full_page=True)
playwright codegen https://playwright.dev/python/
pytest --headed --slowmo 500
pytest --tracing on
playwright show-trace trace.zip

Expected result: Screenshots, trace files, and generated locator code help debug and author tests.


15. Module 10 - Web-First Assertions

Subtopics covered: Page assertions, element state, text, attributes, input fields, checkboxes, option menu assertions, generic assertions, locator assertions, and soft assertions.

fromplaywright.sync_apiimportexpectdeftest_assertions(page):
page.goto("https://example.com/settings")
expect(page).to_have_url(lambdaurl: "settings"inurl)
expect(page.get_by_role("heading", name="Settings")).to_be_visible()
expect(page.get_by_label("Email")).to_have_value("user@example.com")

Expected result: Playwright waits for UI states automatically and fails only if expected conditions are not met within timeout.


16. Module 11 - UI Testing Playground

Subtopics covered: Dynamic IDs, class attributes, hidden layers, load delay, Ajax request, click actions, input fields, scrollbars, dynamic tables, text verification, progress bars, visibility, app login, mouse hover, NBSP, and overlapped elements.

fromplaywright.sync_apiimportexpectdeftest_ajax_request(page):
page.goto("http://uitestingplayground.com/ajax")
page.get_by_role("button", name="Button Triggering AJAX Request").click()
expect(page.locator(".bg-success")).to_contain_text("Data loaded")
deftest_dynamic_table(page):
page.goto("http://uitestingplayground.com/dynamictable")
chrome_row=page.get_by_role("row").filter(has_text="Chrome")
expect(chrome_row).to_contain_text("Chrome")

Expected result: Tests handle dynamic UI behavior without brittle sleeps or unstable IDs.


17. Module 12 - Playwright Fixtures

Subtopics covered: Function scope fixtures, session scope fixtures, browser selection, launch arguments, and context arguments.

importpytest@pytest.fixturedeflogged_in_page(page):
page.goto("https://example.com/login")
page.get_by_label("Email").fill("user@example.com")
page.get_by_label("Password").fill("password")
page.get_by_role("button", name="Sign in").click()
returnpagedeftest_dashboard(logged_in_page):
logged_in_page.goto("https://example.com/dashboard")
assert"dashboard"inlogged_in_page.url

Expected result: Tests receive preconfigured pages without repeating setup logic.


18. Module 13 - Page Object Model

Subtopics covered: POM concept, implementation, usage, Playwright homepage POM, and POM tests.

fromplaywright.sync_apiimportPageclassLoginPage:
def__init__(self, page: Page):
self.page=pageself.email=page.get_by_label("Email")
self.password=page.get_by_label("Password")
self.submit=page.get_by_role("button", name="Sign in")
defopen(self):
self.page.goto("https://example.com/login")
deflogin(self, email: str, password: str):
self.email.fill(email)
self.password.fill(password)
self.submit.click()

Expected result: Tests call meaningful page methods instead of repeating locator code.


19. Module 14 - Network Events

Subtopics covered: Network events, request inspection, request handling, and response modification.

deftest_mock_user_api(page):
page.route("**/api/user", lambdaroute: route.fulfill(
status=200,
content_type="application/json",
body='{"name":"Brian","role":"QA"}'
))
page.goto("https://example.com/profile")

Expected result: The browser receives mocked API data instead of the real backend response.


20. Module 15 - API Testing

Subtopics covered: API calls, request context, query string, CRUD operations, and mock API.

fromplaywright.sync_apiimportPlaywrightdeftest_get_post(playwright: Playwright):
api=playwright.request.new_context(base_url="https://jsonplaceholder.typicode.com")
response=api.get("/posts/1")
assertresponse.okassertresponse.json()["id"] ==1api.dispose()

Expected result: The API returns post 1, the response is OK, and the JSON body contains id == 1.


21. Module 16 - Optimization

Subtopics covered: Intercept requests, disabling JavaScript, and parallel execution.

deftest_block_fonts_and_images(page):
defhandle(route):
ifroute.request.resource_typein ["image", "font"]:
route.abort()
else:
route.continue_()
page.route("**/*", handle)
page.goto("https://playwright.dev/python/")
assert"playwright"inpage.url
pytest -n auto

Expected result: Nonessential resources are blocked and tests can run in parallel when pytest-xdist is installed.


22. Module 17 - Tips and Tricks

Subtopics covered: CLI arguments, debugger, device emulation, JavaScript evaluation, and reports.

deftest_evaluate_javascript(page):
page.goto("https://example.com")
title=page.evaluate("() => document.title")
assertisinstance(title, str)
deftest_device_emulation(playwright):
iphone=playwright.devices["iPhone 12"]
browser=playwright.webkit.launch()
context=browser.new_context(**iphone)
page=context.new_page()
page.goto("https://example.com")
browser.close()

Expected result: JavaScript executes in the browser page and mobile emulation opens the page with a mobile viewport/user-agent profile.


23. Module 18 - GitHub API

Subtopics covered: GitHub API introduction, project setup, token usage, authorized context, writing tests, and running tests.

importosfromplaywright.sync_apiimportPlaywrightdeftest_github_authenticated_user(playwright: Playwright):
token=os.getenv("GITHUB_TOKEN")
api=playwright.request.new_context(
base_url="https://api.github.com",
extra_http_headers={"Authorization": f"Bearer {token}"}
)
response=api.get("/user")
assertresponse.statusin [200, 401]
api.dispose()

Expected result: A valid token returns the authenticated GitHub user; a missing or invalid token returns unauthorized.


24. Module 19 - Continuous Integration

Subtopics covered: GitHub CI introduction, repository setup, writing tests, GitHub Actions, and running automated tests.

name: Playwright Python Testson:
push:
pull_request:
jobs:
test:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5with:
python-version: '3.11'
- run: pip install pytest playwright pytest-playwright
- run: playwright install --with-deps
- run: pytest --tracing on

Expected result: GitHub Actions installs dependencies, installs Playwright browsers, runs tests, and marks the workflow pass/fail.


25. Module 20 - Data-Driven Testing

Subtopics covered: Data-driven testing, Pytest parametrization, and running the same test with multiple data rows.

importpytest@pytest.mark.parametrize("username,password,expected", [ ("standard_user", "secret_sauce", True), ("locked_out_user", "secret_sauce", False), ("invalid", "bad", False),])deftest_login_data(username, password, expected):
result=username=="standard_user"andpassword=="secret_sauce"assertresult==expected

Expected result: Pytest executes the test three times.

3 passed

26. Module 21 - Behavior-Driven Development

Subtopics covered: BDD concepts, project setup, feature files, step definitions, hooks, and Behave execution.

Feature: LoginScenario: Valid user logs inGiven the login page is open
When the user logs in with valid credentials
Then the dashboard should be displayed
frombehaveimportgiven, when, thenfromplaywright.sync_apiimportexpect@given("the login page is open")defopen_login_page(context):
context.page.goto("https://example.com/login")
@when("the user logs in with valid credentials")deflogin(context):
context.page.get_by_label("Email").fill("user@example.com")
context.page.get_by_label("Password").fill("password")
context.page.get_by_role("button", name="Sign in").click()
@then("the dashboard should be displayed")defverify_dashboard(context):
expect(context.page).to_have_url(lambdaurl: "dashboard"inurl)

Expected result: Behave maps feature steps to Python functions and reports the scenario as passed.


27. Supplemental Module 22 - Playwright vs Cypress

Why this was added: Playwright and Cypress are both popular browser automation tools, but they fit different scenarios.

TopicPlaywrightCypress
Browser supportChromium, Firefox, WebKitBest known for Chromium-family browsers; Firefox support also exists
Multi-context supportStrong isolated browser contextsMore constrained architecture
Language ecosystemPython, TypeScript, JavaScript, Java, .NETJavaScript and TypeScript
API testingBuilt-in request contextcy.request()
Best fitCross-browser E2E, UI + API, complex auth, network mockingFront-end developer workflow and JS/TS app testing
fromplaywright.sync_apiimportexpectdeftest_playwright_style(page):
page.goto("https://example.com")
expect(page.locator("h1")).to_be_visible()
it('checks heading',()=>{cy.visit('https://example.com')cy.get('h1').should('be.visible')})

Expected result: Both tests validate a heading, but Playwright and Cypress use different runtime models and syntax.


28. Supplemental Module 23 - Development Environment, Test Application, and JavaScript TypeScript Fundamentals

python --version
git --version
node --version
code --version
constuser={name: 'Brian',role: 'QA'}constskills=['Playwright','Pytest','API Testing']functionformatUser(profile){return`${profile.name} works in ${profile.role}`}console.log(formatUser(user))console.log(skills.join(', '))
interfaceUserProfile{name: stringrole: string}constuser: UserProfile={name: 'Brian',role: 'QA'}console.log(user.name)

Expected result: The environment commands confirm installed tools. JavaScript and TypeScript examples help users understand Playwright examples written in JS/TS.


29. Supplemental Module 24 - DOM Terminology and Advanced Locator Architecture

<sectionid="profile" class="card"><h2>Profile</h2><buttondata-testid="save-profile">Save</button></section>
fromplaywright.sync_apiimportexpectdeftest_dom_and_advanced_locators(page):
page.set_content(''' <section id="profile" class="card"> <h2>Profile</h2> <button data-testid="save-profile">Save</button> </section> ''')
card=page.locator("section.card").filter(has_text="Profile")
button=card.get_by_test_id("save-profile")
expect(button).to_have_text("Save")
deftest_extract_values(page):
page.set_content('<input id="email" value="user@example.com"><p class="status">Ready</p>')
assertpage.locator("#email").input_value() =="user@example.com"assertpage.locator(".status").inner_text() =="Ready"

Expected result: Tests select elements by DOM structure, parent/child relationships, filtered text, test IDs, and extracted values.


30. Supplemental Module 25 - Advanced UI Widgets and Complex Interactions

fromplaywright.sync_apiimportexpectdeftest_tooltip(page):
page.goto("https://example.com/tooltips")
page.get_by_role("button", name="Help").hover()
expect(page.get_by_role("tooltip")).to_contain_text("Helpful information")
deftest_table_row_by_column(page):
page.goto("https://example.com/users")
row=page.get_by_role("row").filter(has_text="brian@example.com")
expect(row).to_contain_text("Active")
row.get_by_role("button", name="Edit").click()
deftest_iframe_drag_drop(page):
page.goto("https://example.com/iframe-dragdrop")
frame=page.frame_locator("iframe[name='demo-frame']")
frame.locator("#source").drag_to(frame.locator("#target"))

Expected result: The examples demonstrate hover, table-row targeting, iframe handling, and drag-and-drop interactions.


31. Supplemental Module 26 - Advanced Page Object Architecture

fromplaywright.sync_apiimportPage, expectclassBasePage:
def__init__(self, page: Page):
self.page=pagedefopen(self, path: str):
self.page.goto(f"https://example.com{path}")
defexpect_heading(self, name: str):
expect(self.page.get_by_role("heading", name=name)).to_be_visible()
classNavigationPage(BasePage):
defopen_menu_item(self, menu: str, item: str):
menu_button=self.page.get_by_role("button", name=menu)
ifmenu_button.get_attribute("aria-expanded") !="true":
menu_button.click()
self.page.get_by_role("link", name=item).click()
classPageManager:
def__init__(self, page: Page):
self.navigation=NavigationPage(page)
deftest_page_manager(page):
app=PageManager(page)
app.navigation.open("/")
app.navigation.open_menu_item("Forms", "Date Picker")

Expected result: Tests use high-level objects instead of directly managing every page class or locator.


32. Supplemental Module 27 - Advanced API State, Mocking, Authentication, and Cleanup

importjsonfromplaywright.sync_apiimportPlaywrightdefcreate_auth_state_with_api(playwright: Playwright):
api=playwright.request.new_context(base_url="https://example.com")
token_response=api.post("/api/login", data={"email": "user@example.com", "password": "password"})
token=token_response.json()["token"]
withopen("auth_token.json", "w") asfile:
json.dump({"token": token}, file)
api.dispose()
deftest_ui_create_then_api_cleanup(page, playwright):
withpage.expect_response("**/api/articles") asresponse_info:
page.goto("https://example.com/articles/new")
page.get_by_label("Title").fill("Temporary Article")
page.get_by_role("button", name="Save").click()
article_id=response_info.value.json()["id"]
api=playwright.request.new_context(base_url="https://example.com/api")
api.delete(f"/articles/{article_id}")
api.dispose()

Expected result: API calls create state quickly, UI tests validate user-facing behavior, and cleanup removes generated data.


33. Supplemental Module 28 - Advanced Framework Configuration, Environment Variables, Retries, Tags, and Test Data

importosfromdotenvimportload_dotenvload_dotenv()
BASE_URL=os.getenv("BASE_URL", "https://example.com")
TEST_USER=os.getenv("TEST_USER")
fromfakerimportFakerfake=Faker()
deftest_generated_user_data():
email=fake.email()
assert"@"inemail
[pytest]markers =
smoke: critical smoke tests
regression: broader regression tests
addopts = --maxfail=1
pytest -m smoke
pytest --reruns 2
pytest -n 2

Expected result: Tests can use environment-specific configuration, generated test data, filtered test execution, retries, and parallel workers.


34. Supplemental Module 29 - Reporting, Screenshots, Videos, and Visual Testing

deftest_page_and_element_screenshot(page):
page.goto("https://example.com")
page.screenshot(path="artifacts/page.png", full_page=True)
image_bytes=page.locator("img").first.screenshot()
assertlen(image_bytes) >0
deftest_video_recording(browser):
context=browser.new_context(record_video_dir="videos/", record_video_size={"width": 1280, "height": 720})
page=context.new_page()
page.goto("https://example.com")
context.close()
fromplaywright.sync_apiimportexpectdeftest_visual_snapshot(page):
page.goto("https://example.com")
expect(page).to_have_screenshot("home-page.png", max_diff_pixel_ratio=0.01)
pytest --junitxml=reports/junit.xml
pytest --html=reports/report.html
pytest --update-snapshots

Expected result: Screenshots, videos, visual baselines, and machine-readable reports are produced for debugging and CI evidence.


35. Supplemental Module 30 - Docker, GitHub Actions, and Argos CI

FROM mcr.microsoft.com/playwright/python:v1.45.0-jammy
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["pytest", "--junitxml=reports/junit.xml"]
services:
tests:
build: .volumes:
- ./reports:/app/reportsenvironment:
- BASE_URL=https://example.com
docker compose up --build
npx argos upload screenshots

Expected result: Tests run in a consistent container, reports are mapped back to the host, and visual screenshots can be uploaded to a visual validation service.


36. Supplemental Module 31 - Building a Playwright Framework from Scratch

A Playwright framework is needed when a team wants reusable structure beyond one-off scripts. A good framework standardizes setup, browser configuration, fixtures, page objects, test data, reporting, CI/CD, retries, artifacts, environment switching, login state, and API helpers.

When to Build a Custom Framework

Build a custom framework when:

  • The test suite will grow beyond a few simple tests.
  • Multiple QA engineers or developers will contribute tests.
  • The project needs common login, data setup, cleanup, and reporting.
  • The team must support multiple environments such as dev, QA, staging, and production smoke checks.
  • The app needs Page Object Model or Screenplay-style abstraction.
  • Tests must run in CI/CD with artifacts and quality gates.
  • API and UI tests need shared fixtures and authentication.

Avoid building a heavy framework when:

  • The project only needs a few smoke tests.
  • The team is still exploring Playwright basics.
  • A generated Playwright/Pytest starter is sufficient.
  • Maintenance cost would exceed the value of abstraction.

Required Files and Folder Structure

playwright-python-framework/
├── README.md
├── requirements.txt
├── pytest.ini
├── .env.example
├── .gitignore
├── conftest.py
├── pages/
│ ├── __init__.py
│ ├── base_page.py
│ ├── login_page.py
│ └── dashboard_page.py
├── tests/
│ ├── ui/
│ │ └── test_login.py
│ ├── api/
│ │ └── test_users_api.py
│ └── smoke/
│ └── test_homepage.py
├── utils/
│ ├── __init__.py
│ ├── config.py
│ ├── data_factory.py
│ └── api_client.py
├── test_data/
│ └── users.json
├── artifacts/
│ ├── screenshots/
│ ├── videos/
│ └── traces/
└── .github/
└── workflows/
└── playwright-tests.yml

Requirements File

pytest
playwright
pytest-playwright
python-dotenv
faker
pytest-xdist
pytest-rerunfailures
pytest-html

Step-by-Step Framework Build

  1. Create the repository and virtual environment.
  2. Install dependencies.
  3. Install Playwright browsers.
  4. Add pytest.ini for markers and default options.
  5. Add .env.example for environment variables.
  6. Create utils/config.py for environment configuration.
  7. Create conftest.py for fixtures.
  8. Create pages/base_page.py for shared page methods.
  9. Create page objects for each major application screen.
  10. Create UI tests under tests/ui/.
  11. Create API tests under tests/api/.
  12. Add screenshots, traces, and videos for failure evidence.
  13. Add smoke/regression markers.
  14. Add GitHub Actions workflow.
  15. Add README instructions for setup and execution.

pytest.ini

[pytest]addopts = -ra --browser chromium --tracing retain-on-failure
markers =
smoke: critical smoke tests
regression: full regression tests
login: login and authentication tests
api: API tests
ui: UI tests

.env.example

BASE_URL=https://example.com
API_BASE_URL=https://example.com/api
TEST_USER_EMAIL=user@example.com
TEST_USER_PASSWORD=password
GITHUB_TOKEN=replace_me

utils/config.py

importosfromdotenvimportload_dotenvload_dotenv()
classSettings:
BASE_URL=os.getenv("BASE_URL", "https://example.com")
API_BASE_URL=os.getenv("API_BASE_URL", "https://example.com/api")
TEST_USER_EMAIL=os.getenv("TEST_USER_EMAIL", "user@example.com")
TEST_USER_PASSWORD=os.getenv("TEST_USER_PASSWORD", "password")
settings=Settings()

conftest.py

importpytestfromutils.configimportsettings@pytest.fixture(scope="session")defbase_url():
returnsettings.BASE_URL@pytest.fixturedefauthenticated_page(page):
page.goto(f"{settings.BASE_URL}/login")
page.get_by_label("Email").fill(settings.TEST_USER_EMAIL)
page.get_by_label("Password").fill(settings.TEST_USER_PASSWORD)
page.get_by_role("button", name="Sign in").click()
returnpage@pytest.fixture(scope="session")defapi_base_url():
returnsettings.API_BASE_URL

pages/base_page.py

fromplaywright.sync_apiimportPage, expectclassBasePage:
def__init__(self, page: Page):
self.page=pagedefopen(self, path: str=""):
self.page.goto(path)
defexpect_title_contains(self, text: str):
expect(self.page).to_have_title(lambdatitle: textintitle)
defclick_by_role(self, role: str, name: str):
self.page.get_by_role(role, name=name).click()

pages/login_page.py

fromplaywright.sync_apiimportPage, expectfrompages.base_pageimportBasePageclassLoginPage(BasePage):
def__init__(self, page: Page):
super().__init__(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")
self.error=page.get_by_role("alert")
defopen_login(self, base_url: str):
self.page.goto(f"{base_url}/login")
deflogin(self, email: str, password: str):
self.email.fill(email)
self.password.fill(password)
self.submit.click()
defexpect_error(self, message: str):
expect(self.error).to_contain_text(message)

tests/ui/test_login.py

importpytestfrompages.login_pageimportLoginPagefromutils.configimportsettings@pytest.mark.login@pytest.mark.uideftest_valid_login(page, base_url):
login=LoginPage(page)
login.open_login(base_url)
login.login(settings.TEST_USER_EMAIL, settings.TEST_USER_PASSWORD)
assert"dashboard"inpage.url@pytest.mark.login@pytest.mark.uideftest_invalid_login(page, base_url):
login=LoginPage(page)
login.open_login(base_url)
login.login("bad@example.com", "wrong")
login.expect_error("Invalid")

Expected result: The framework can run UI tests, API tests, login tests, smoke tests, and regression tests consistently locally and in CI/CD.


37. Supplemental Module 32 - Custom Framework vs Out-of-the-Box Framework

Use a Custom Framework When

ScenarioWhy Custom Helps
Large enterprise appRequires shared patterns, environment switching, custom reporting, and test data management
Complex login/authNeeds storage state, API auth, multiple roles, and secure secret handling
UI + API hybrid testsNeeds API setup/cleanup combined with UI validation
Regulated QA evidenceNeeds artifacts, traces, screenshots, reports, and repeatable evidence
Multiple teamsNeeds standardized POM, naming conventions, tags, and fixtures

Use Out-of-the-Box Tooling When

ScenarioBetter Option
Small smoke suitepytest-playwright defaults are enough
Learning PlaywrightSimple scripts or generated code are faster
Front-end JS/TS teamOfficial Playwright Test runner in TypeScript may be more natural
BDD collaborationBehave + Playwright or Playwright-BDD style framework
Visual regression focusPlaywright screenshots + Argos, Percy, or Applitools

Decision Rule

Use the simplest framework that supports the real requirement. A custom framework should solve repeated problems, not create unnecessary abstraction.


38. Supplemental Module 33 - Best and Popular Playwright Framework Options by Scenario

ScenarioRecommended Framework / ApproachWhy
Python UI testingpytest-playwrightBest fit for Python teams using Pytest fixtures and assertions
TypeScript/JavaScript UI testingOfficial Playwright TestMost feature-complete Playwright runner, strong config/projects/reporting support
API testing in PythonPlaywright APIRequestContext + PytestFast backend validation with shared fixtures
BDD in PythonBehave + PlaywrightGood for Given/When/Then collaboration and readable acceptance tests
BDD in TypeScriptPlaywright-BDD / Cucumber-style approachGood for JS/TS teams needing Gherkin
Visual testingPlaywright screenshots + Argos/Percy/ApplitoolsBest for detecting UI regressions through screenshots
Enterprise smoke/regressionCustom Pytest framework + POM + CI/CDSupports tagging, environment control, artifacts, and standard test patterns
Fast PR validationOfficial Playwright Test or Pytest markersRun only smoke/high-risk tests on pull requests
Dockerized automationPlaywright Docker imageConsistent browser dependencies and reproducible runs
Cross-browser validationPlaywright projects or Pytest browser matrixValidate Chromium, Firefox, and WebKit behavior

Popular Framework Choices

  1. Official Playwright Test for TypeScript/JavaScript: Best all-around Playwright-native test runner.
  2. pytest-playwright for Python: Best for Python QA automation teams and Pytest-based test suites.
  3. Behave + Playwright Python: Best when stakeholders want Gherkin scenarios.
  4. Playwright + Page Object Model: Best maintainability pattern for medium/large UI suites.
  5. Playwright + APIRequestContext: Best for API + UI hybrid automation.
  6. Playwright + Docker + GitHub Actions: Best for reproducible CI execution.
  7. Playwright + Argos/Percy/Applitools: Best for visual regression workflows.

39. Supplemental Module 34 - Thorough CI/CD Strategy for Playwright

A strong CI/CD pipeline makes Playwright tests repeatable, observable, and useful as a quality gate.

Recommended CI/CD Stages

  1. Checkout source code.
  2. Set up Python.
  3. Install Python dependencies.
  4. Install Playwright browsers and OS dependencies.
  5. Run linting or formatting checks.
  6. Run smoke tests first.
  7. Run regression tests or browser matrix if needed.
  8. Upload artifacts: traces, screenshots, videos, reports.
  9. Publish test results.
  10. Fail the workflow when critical tests fail.

GitHub Actions Workflow

name: Playwright Python CIon:
pull_request:
push:
branches: [ main ]jobs:
smoke:
runs-on: ubuntu-latestenv:
BASE_URL: ${{ secrets.BASE_URL }}TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5with:
python-version: '3.11'
- run: pip install -r requirements.txt
- run: playwright install --with-deps
- run: pytest -m smoke --tracing retain-on-failure --junitxml=reports/smoke-results.xml
- uses: actions/upload-artifact@v4if: always()with:
name: smoke-artifactspath: | reports/ test-results/ artifacts/regression:
needs: smokeruns-on: ubuntu-lateststrategy:
fail-fast: falsematrix:
browser: [chromium, firefox, webkit]steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5with:
python-version: '3.11'
- run: pip install -r requirements.txt
- run: playwright install --with-deps
- run: pytest -m regression --browser ${{ matrix.browser }} --tracing retain-on-failure
- uses: actions/upload-artifact@v4if: always()with:
name: regression-${{ matrix.browser }}-artifactspath: | test-results/ reports/ artifacts/

CI/CD Best Practices

  • Run smoke tests on every PR.
  • Run full regression on scheduled builds or before releases.
  • Store secrets in GitHub repository secrets.
  • Never commit .env, passwords, tokens, or real auth state.
  • Upload traces and screenshots on failure.
  • Use browser matrix only when cross-browser coverage is valuable.
  • Keep CI tests independent so they can run in parallel.
  • Use API setup/cleanup instead of manual test data dependencies.
  • Use stable test accounts and dedicated test environments.

40. Supplemental Module 35 - Thorough API Testing Strategy

API tests validate backend behavior quickly and can also support UI tests by creating setup data and cleaning up test data.

Recommended API Test Structure

tests/api/
├── test_auth_api.py
├── test_users_api.py
├── test_tasks_api.py
└── test_negative_api.py
utils/
├── api_client.py
└── schemas.py

API Client Helper

fromplaywright.sync_apiimportPlaywright, APIRequestContextclassApiClient:
def__init__(self, playwright: Playwright, base_url: str, token: str|None=None):
headers= {"Accept": "application/json"}
iftoken:
headers["Authorization"] =f"Bearer {token}"self.context: APIRequestContext=playwright.request.new_context(
base_url=base_url,
extra_http_headers=headers
)
defget_user(self, user_id: int):
returnself.context.get(f"/users/{user_id}")
defcreate_user(self, payload: dict):
returnself.context.post("/users", data=payload)
defdelete_user(self, user_id: int):
returnself.context.delete(f"/users/{user_id}")
defdispose(self):
self.context.dispose()

API Fixture

importpytestfromutils.api_clientimportApiClientfromutils.configimportsettings@pytest.fixturedefapi_client(playwright):
client=ApiClient(playwright, settings.API_BASE_URL)
yieldclientclient.dispose()

CRUD Test

deftest_create_read_delete_user(api_client):
payload= {"name": "Brian", "role": "QA"}
created=api_client.create_user(payload)
assertcreated.statusin [200, 201]
created_body=created.json()
user_id=created_body["id"]
fetched=api_client.get_user(user_id)
assertfetched.okassertfetched.json()["name"] =="Brian"deleted=api_client.delete_user(user_id)
assertdeleted.statusin [200, 202, 204]

Negative API Test

deftest_create_user_missing_required_name(api_client):
response=api_client.create_user({"role": "QA"})
assertresponse.statusin [400, 422]

API Testing Checklist

AreaWhat to Validate
Status codes200, 201, 204, 400, 401, 403, 404, 409, 422, 500 handling
Response bodyRequired fields, correct values, correct types
HeadersContent type, auth, caching, correlation IDs if used
AuthMissing token, invalid token, expired token, role-based access
Query stringsFiltering, sorting, pagination, limits
CRUDCreate, read, update, patch, delete, cleanup
Negative testsMissing fields, invalid values, invalid IDs, duplicate records
Data cleanupDelete generated data after tests
Contract checksSchema expectations and required fields

41. Supplemental Module 36 - Thorough Login Testing Strategy

Login testing is one of the most important workflows because many applications depend on authenticated user sessions.

Login Scenarios to Cover

ScenarioExpected Result
Valid username/passwordUser reaches dashboard or authenticated landing page
Invalid passwordError message is displayed and user remains logged out
Invalid usernameError message is displayed and user remains logged out
Empty username/passwordRequired field validation appears
Locked userLocked-account message appears
Disabled userAccess denied or account disabled message appears
LogoutSession ends and protected pages redirect to login
Session reuseSaved storage state opens authenticated pages without logging in again
Expired sessionUser is redirected to login or receives session-expired message
Role-based loginUser sees only permissions allowed for the role

Page Object for Login Testing

fromplaywright.sync_apiimportPage, expectclassLoginPage:
def__init__(self, page: Page):
self.page=pageself.email=page.get_by_label("Email")
self.password=page.get_by_label("Password")
self.sign_in=page.get_by_role("button", name="Sign in")
self.error=page.get_by_role("alert")
defopen(self, base_url: str):
self.page.goto(f"{base_url}/login")
deflogin(self, email: str, password: str):
self.email.fill(email)
self.password.fill(password)
self.sign_in.click()
defexpect_error(self, message: str):
expect(self.error).to_contain_text(message)

Valid Login Test

fromutils.configimportsettingsfrompages.login_pageimportLoginPagedeftest_valid_login(page, base_url):
login=LoginPage(page)
login.open(base_url)
login.login(settings.TEST_USER_EMAIL, settings.TEST_USER_PASSWORD)
assert"dashboard"inpage.url

Expected result: The user lands on the dashboard or another authenticated page.

Invalid Login Test

deftest_invalid_login_shows_error(page, base_url):
login=LoginPage(page)
login.open(base_url)
login.login("bad@example.com", "wrong-password")
login.expect_error("Invalid")

Expected result: The app displays an invalid-login message and does not enter the authenticated area.

Logout Test

deftest_logout_ends_session(authenticated_page):
authenticated_page.get_by_role("button", name="Account").click()
authenticated_page.get_by_role("menuitem", name="Logout").click()
assert"login"inauthenticated_page.url

Expected result: The user is redirected to login and protected pages should no longer be accessible.

Storage State Login Reuse

# One-time setup after successful logincontext.storage_state(path="auth_state.json")
# Reuse in testscontext=browser.new_context(storage_state="auth_state.json")
page=context.new_page()
page.goto("https://example.com/dashboard")

Expected result: Tests start authenticated without repeating UI login.

Login Testing Best Practices

  • Use test-only accounts, not personal accounts.
  • Store credentials in secrets or .env files ignored by Git.
  • Avoid testing real MFA unless a test MFA bypass or automation-safe method exists.
  • Keep one or two UI login tests, then reuse storage state for most authenticated tests.
  • Test authorization separately from authentication.
  • Use API login where possible for fast setup.
  • Validate both success and failure paths.
  • Confirm logout destroys or invalidates the active session.

42. Playwright Automation Top 20 Interview Questions and Answers

1. What is Playwright?

Playwright is an end-to-end automation framework for testing web applications across Chromium, Firefox, and WebKit. It supports browser automation, UI testing, API testing, tracing, screenshots, videos, network interception, and multiple languages including Python.

2. Why use Playwright instead of Selenium?

Playwright has built-in auto-waiting, modern locator strategies, browser contexts for isolation, native network interception, trace viewer, API testing support, and strong handling for modern single-page applications.

3. What is a browser context?

A browser context is an isolated browser session. Each context has its own cookies, local storage, session storage, permissions, and viewport.

4. What is the difference between browser, context, and page?

browser is the launched browser process. context is an isolated session inside the browser. page is a browser tab inside a context.

5. What are Playwright locators?

Locators are Playwright objects used to find and interact with elements. They auto-wait and re-query the DOM.

6. Which locator strategy is preferred?

Prefer user-facing and accessibility-based locators such as get_by_role, get_by_label, get_by_text, and get_by_placeholder.

7. What is auto-waiting?

Auto-waiting means Playwright waits for elements to be actionable before performing actions.

8. What are web-first assertions?

Web-first assertions automatically wait until an expected condition is met or a timeout occurs.

9. How do you handle alerts or dialogs?

Use the dialog event with page.on("dialog", handler).

10. How do you handle downloads?

Wrap the download-triggering action with page.expect_download().

11. How do you save authentication state?

After login, call context.storage_state(path="auth_state.json") and reuse the file in future contexts.

12. What is Page Object Model?

POM is a design pattern that stores locators and page behavior inside page classes.

13. How does Pytest integrate with Playwright?

Pytest runs the tests, while Playwright controls browser behavior. pytest-playwright provides browser fixtures.

14. What is a Pytest fixture?

A fixture is reusable setup/teardown logic used by tests.

15. How do you perform API testing in Playwright?

Use playwright.request.new_context() to create an API client.

16. How do you intercept network requests?

Use page.route() to continue, abort, or fulfill matching requests.

17. How do you mock an API response?

Use route.fulfill() to provide a custom response.

18. How do you run Playwright tests in CI?

Install dependencies, install Playwright browsers, and run Pytest inside the CI workflow.

19. How do you debug flaky Playwright tests?

Use headed mode, slow motion, screenshots, videos, traces, console logs, network logs, and web-first assertions.

20. What is data-driven testing?

Data-driven testing runs the same test logic with multiple input values and expected results.


43. Best Practices and Troubleshooting

Best Practices

  1. Prefer semantic locators over CSS and XPath.
  2. Use Playwright expect() assertions instead of time.sleep().
  3. Centralize setup with Pytest fixtures.
  4. Use Page Object Model for repeated page workflows.
  5. Keep test data isolated.
  6. Use API tests for backend validation and UI tests for user journeys.
  7. Store credentials and tokens in environment variables.
  8. Save authentication state for repeated authenticated tests.
  9. Capture traces, screenshots, and videos for debugging.
  10. Keep CI tests deterministic, independent, and headless by default.
  11. Use custom frameworks only when repeated complexity justifies the maintenance cost.
  12. Keep smoke tests fast and regression tests broader.

Troubleshooting

ProblemLikely CauseFix
Browser does not launchBrowsers not installedRun playwright install
Element not foundLocator is unstable or wrongUse role/label/text locators or inspect with codegen
Test is flakyPage changes asynchronouslyUse web-first assertions and event waits
Login fails in CIMissing secret or blocked login flowUse storage state and repository secrets
API test returns 401Missing/invalid tokenSet token as an environment variable
Download test failsEvent not wrapped correctlyUse page.expect_download() before clicking
File upload failsBad pathUse repo-relative file paths
Test passes locally but fails in CIEnvironment mismatchRun locally headless and capture traces
Custom framework becomes hard to maintainToo much abstractionSimplify fixtures, remove unused helpers, and keep tests readable

44. Author

Brian McCarthy
Playwright Automation with Python and Pytest Showcase

About

Playwright Python and Pytest for Web Automation Testing

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages