DEV Community

Arun Dhole
Arun Dhole

Posted on

10 Python Playwright Debugging Techniques to Supercharge Your Test Automation

Debugging is the unsung hero of programming. When working with Playwright, a powerful Python framework for browser automation, errors like TimeoutError, KeyError, or unexpected element states can derail your tests or scripts. While writing automation scripts gets the spotlight, mastering debugging turns frustrating stack traces into opportunities for growth. Below, I share 10 Python debugging techniques each with detailed implementation steps tailored for Playwright. These moves will streamline your workflow, helping you pinpoint and fix issues faster.


1. Interactive Debugging with pdb

The Python Debugger (pdb) is a built-in tool that lets you pause execution and inspect your Playwright script interactively, far surpassing basic print() statements.

Implementation in Playwright:

  • Insert import pdb; pdb.set_trace() where you want to pause your script.
  • Use commands like n (next line), s (step into function), or p variable (print variable) to explore.
  • Ideal for inspecting page states, locators, or Playwright API responses during test execution.

Example:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto("https://example.com")

    # Pause execution to debug
    import pdb; pdb.set_trace()

    # Check if an element exists
    element = page.query_selector("h1")
    if element:
        print(element.inner_text())
    else:
        print("Element not found")
    browser.close()
Enter fullscreen mode Exit fullscreen mode

Steps:

  1. Run the script; execution pauses at pdb.set_trace().
  2. Type p page.url to check the current URL or p element to inspect the element.
  3. Use n to move to the next line or c to continue execution.
  4. Debug issues like missing elements or navigation failures.

Why It’s Useful: pdb lets you inspect Playwright’s page objects, locators, or API responses in real-time, saving you from guessing why a selector failed.


2. Enhanced Debugging with ipdb

ipdb is an upgraded pdb with features like tab completion and syntax highlighting, making it more user-friendly for Playwright debugging.

Implementation in Playwright:

  • Install: pip install ipdb
  • Replace pdb with import ipdb; ipdb.set_trace().
  • Use it to debug complex Playwright interactions, like form submissions or async events.

Example:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto("https://example.com")

    import ipdb; ipdb.set_trace()

    page.fill("input[name='q']", "Playwright")
    page.press("input[name='q']", "Enter")
    browser.close()
Enter fullscreen mode Exit fullscreen mode

Steps:

  1. Install ipdb and add the set_trace() line where you suspect issues (e.g., before a page.fill).
  2. Run the script; use tab completion to explore page methods or attributes (e.g., page.<tab>).
  3. Inspect variables like page.content() or step through to debug form interactions.

Why It’s Useful: ipdb’s enhanced interface simplifies debugging Playwright’s dynamic browser interactions.


3. Logging with the logging Module

The logging module provides persistent, configurable logs, superior to print() for tracking Playwright script execution.

Implementation in Playwright:

  • Configure logging to output to the console or a file.
  • Log key Playwright actions (e.g., navigation, clicks) with timestamps and severity levels.

Example:

import logging
from playwright.sync_api import sync_playwright

logging.basicConfig(level=logging.DEBUG, filename="playwright.log", format="%(asctime)s - %(levelname)s - %(message)s")

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()

    logging.info("Navigating to example.com")
    page.goto("https://example.com")

    logging.debug("Checking for h1 element")
    element = page.query_selector("h1")
    if element:
        logging.info(f"Found h1: {element.inner_text()}")
    else:
        logging.error("h1 element not found")
    browser.close()
Enter fullscreen mode Exit fullscreen mode

Steps:

  1. Set up logging with desired level (DEBUG, INFO, etc.) and output (file or console).
  2. Add logging.info/debug/error calls to track Playwright actions or errors.
  3. Check playwright.log for a detailed execution trail.

Why It’s Useful: Logs persist across runs, helping you trace Playwright errors like failed navigation or missing elements without rerunning the script.


4. Assertions for Early Bug Detection

Assertions validate assumptions in your Playwright scripts, catching logical errors early (e.g., ensuring an element exists before interaction).

Implementation in Playwright:

  • Use assert to check conditions like element presence or page state.
  • Include descriptive messages for clarity.

Example:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto("https://example.com")

    element = page.query_selector("h1")
    assert element is not None, "Failed to find h1 element on page"

    text = element.inner_text()
    assert "Example" in text, "Expected 'Example' in h1 text"
    browser.close()
Enter fullscreen mode Exit fullscreen mode

Steps:

  1. Add assert statements before critical Playwright actions (e.g., clicking or filling forms).
  2. Run the script; if an assertion fails, the error message pinpoints the issue.
  3. Use assertions to validate Playwright locators or page content.

Why It’s Useful: Assertions stop execution early, preventing cascading errors in Playwright tests.


5. IDE Debuggers (PyCharm/VS Code)

Modern IDEs like PyCharm or Visual Studio Code offer graphical debuggers, ideal for visually inspecting Playwright scripts.

Implementation in Playwright:

  • Set breakpoints in your IDE to pause execution.
  • Inspect Playwright objects (e.g., page, browser) via variable explorers.

Example (VS Code):

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto("https://example.com")  # Set breakpoint here

    element = page.query_selector("h1")
    if element:
        print(element.inner_text())
    browser.close()
Enter fullscreen mode Exit fullscreen mode

Steps:

  1. Open your script in VS Code or PyCharm.
  2. Click the gutter next to a line (e.g., page.goto) to set a breakpoint.
  3. Run the debugger (F5 in VS Code); inspect page.url or element in the variable pane.
  4. Step through code using “Step Over” (F10) or “Step Into” (F11).

Why It’s Useful: Graphical debuggers simplify inspecting Playwright’s browser context or element states without manual commands.


6. Try-Except Blocks for Exception Handling

try-except blocks catch Playwright-specific errors (e.g., TimeoutError, Error) and provide context for debugging.

Implementation in Playwright:

  • Wrap Playwright actions in try-except to handle failures gracefully.
  • Log or print error details for analysis.

Example:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()

    try:
        page.goto("https://example.com", timeout=5000)  # Short timeout for testing
    except Exception as e:
        print(f"Navigation failed: {e}")

    browser.close()
Enter fullscreen mode Exit fullscreen mode

Steps:

  1. Identify risky Playwright actions (e.g., page.goto, page.click).
  2. Wrap them in try-except and log the exception.
  3. Analyze the error message to fix issues like timeouts or network failures.

Why It’s Useful: Prevents script crashes and provides actionable error details for Playwright failures.


7. Using traceback for Detailed Error Analysis

The traceback module provides full stack traces, helping you trace Playwright errors across function calls.

Implementation in Playwright:

  • Use traceback.print_exc() to log detailed error information.
  • Useful for debugging nested Playwright test suites.

Example:

import traceback
from playwright.sync_api import sync_playwright

def navigate_page(page):
    page.goto("https://nonexistent-site.com")  # Will fail

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()

    try:
        navigate_page(page)
    except:
        traceback.print_exc()
    browser.close()
Enter fullscreen mode Exit fullscreen mode

Steps:

  1. Import traceback and wrap Playwright code in try-except.
  2. Use traceback.print_exc() to print the stack trace.
  3. Analyze the trace to find the exact line and function causing the error.

Why It’s Useful: Helps debug complex Playwright scripts with multiple function calls or test cases.


8. Interactive Debugging with IPython or Jupyter

IPython or Jupyter Notebooks offer interactive debugging for Playwright, especially for prototyping scripts.

Implementation in Playwright:

  • Use %debug in IPython to enter a post-mortem debugger after an error.
  • Run Playwright code in Jupyter cells for step-by-step inspection.

Example (Jupyter):

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto("https://example.com")

    element = page.query_selector("h2")  # Non-existent element
    element.inner_text()  # Will fail
    browser.close()
Enter fullscreen mode Exit fullscreen mode

Steps:

  1. Install IPython (pip install ipython) or use Jupyter.
  2. Run the script; when an error occurs, type %debug in IPython to inspect.
  3. In Jupyter, split code into cells to isolate Playwright actions and inspect variables.

Why It’s Useful: Interactive environments make it easy to test and debug Playwright locators or actions iteratively.


9. Profiling with cProfile for Performance Debugging

cProfile identifies performance bottlenecks in Playwright scripts, such as slow page loads or excessive API calls.

Implementation in Playwright:

  • Use cProfile.run() to profile a Playwright function.
  • Analyze which Playwright operations are slowing down your script.

Example:

import cProfile
from playwright.sync_api import sync_playwright

def run_playwright():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()
        page.goto("https://example.com")
        for _ in range(10):  # Simulate heavy operation
            page.reload()
        browser.close()

cProfile.run("run_playwright()")
Enter fullscreen mode Exit fullscreen mode

Steps:

  1. Wrap your Playwright code in a function.
  2. Run cProfile.run("function_name()") to generate a performance report.
  3. Check the output for slow Playwright calls (e.g., page.goto, page.reload).

Why It’s Useful: Identifies performance issues in Playwright scripts, like excessive reloads or slow locators.


10. Linting with pylint or flake8

Static analysis tools like pylint or flake8 catch potential bugs in Playwright scripts before runtime, such as undefined variables or incorrect API usage.

Implementation in Playwright:

  • Install: pip install pylint flake8
  • Run pylint script.py or flake8 script.py to analyze your code.

Example:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto("https://example.com")
    undefined_variable  # Will be caught by linter
    browser.close()
Enter fullscreen mode Exit fullscreen mode

Steps:

  1. Install pylint or flake8.
  2. Run the linter on your Playwright script: pylint script.py.
  3. Fix reported issues, like undefined variables or unused imports.

Why It’s Useful: Prevents runtime errors in Playwright scripts by catching issues early.


Conclusion

Debugging Playwright scripts doesn’t have to be a nightmare. By moving beyond print() to tools like pdb, ipdb, logging, and IDE debuggers, you can tackle errors with confidence. These 10 techniques—tailored for Playwright’s browser automation context—cover interactive debugging, error handling, performance profiling, and static analysis. Incorporate them into your workflow to make debugging a superpower, not a struggle.


Notes:

  • The article assumes familiarity with Playwright’s sync_api. For async scripts, adapt examples using async/await.
  • Always close browsers (browser.close()) to avoid resource leaks during debugging.

Top comments (0)