How to Debug Web Elements Using Zendriver’s Descriptive `repr`

Zendriver’s Element class automatically generates a human-readable HTML-like string via its __repr__ method, displaying the tag name, attributes, and text content to streamline debugging without serializing the entire DOM tree.

Zendriver is a high-level Python library that wraps Chrome DevTools Protocol (CDP) interactions for browser automation. When scraping or testing web applications, understanding the structure of selected elements is critical for troubleshooting selectors and validation logic. The library’s descriptive repr implementation in zendriver/core/element.py provides immediate visual feedback by converting CDP DOM nodes into compact, inspectable HTML snippets.

How Zendriver’s Descriptive repr Works

The Element class encapsulates CDP DOM nodes and overrides __repr__ to produce debugging output that resembles the original HTML structure.

Core Implementation Details

In zendriver/core/element.py (lines 1167‑1194), the __repr__ method constructs the debug string by aggregating four specific data points from the underlying CDP node:

  • Tag name: Derived from self.node.node_name.lower().
  • Attributes: All entries in self.attrs render as key="value" pairs; the special class_ key is normalized to display as class.
  • Child content: The method recursively walks child nodes, concatenating their string representations to show nested structure.
  • Text nodes: When node_type == 3, the method returns only self.node_value (the raw text), omitting any tag wrapper.

Because the implementation avoids full DOM serialization, it remains performant for REPL sessions and logging while exposing the most relevant debugging information—tag identity, attribute state, and visible text.

Integration with Selector Queries

The query_selector and query_selector_all helpers in zendriver/core/tab.py (lines 478‑483) return Element instances that immediately leverage this representation. After executing a selector, printing the result invokes the descriptive repr automatically, allowing you to verify that you’ve targeted the correct node before proceeding with interactions.

Practical Code Examples for Debugging Web Elements

Basic Element Inspection

After fetching an element, simply print it to view its compact HTML representation:

import zendriver

async def demo():
    driver = await zendriver.start()
    tab = await driver.new_tab()
    await tab.goto("https://example.com")

    heading = await tab.query_selector("h1")
    print(heading)           # <h1>Example Domain</h1>

    print(repr(heading))     # Same output: <h1>Example Domain</h1>

    await driver.close()

Examining Nested Structures and Attributes

The representation includes all attributes and recursively renders children, making it ideal for inspecting complex components:

async def inspect_article():
    tab = await driver.new_tab()
    await tab.goto("https://example.com")
    article = await tab.query_selector("div[role='article']")
    print(article)
    # Output: <div role="article" id="main"><p>Some text</p></div>

Validating Elements in Test Assertions

Use the string output in assertions to verify element state without accessing internal properties:

submit_btn = await tab.query_selector("#submit")
assert "<button type=\"submit\" disabled>" in repr(submit_btn)

Structured Logging During Execution

Include element representations in debug logs to trace automation flow:

import logging

logging.basicConfig(level=logging.DEBUG)

async def log_elements():
    button = await tab.query_selector("button.save")
    logging.debug("Found button: %s", button)
    # Debug log shows: Found button: <button class="save" type="button">Save</button>

Summary

  • The Element.__repr__ method in zendriver/core/element.py generates compact, HTML-like debug strings by combining the tag name, attributes, and visible text.
  • Attribute normalization converts the Pythonic class_ key to standard class in the output.
  • Recursive child traversal displays nested markup without serializing the entire DOM, ensuring fast inspection.
  • Selector methods in zendriver/core/tab.py return these Element objects, making descriptive debugging available immediately after node selection.

Frequently Asked Questions

What file contains the __repr__ implementation for Zendriver elements?

The implementation resides in zendriver/core/element.py between lines 1167 and 1194. This method defines how Element instances render themselves when printed or inspected.

Does the descriptive repr serialize the entire DOM tree?

No. The implementation intentionally limits scope to the specific element and its immediate children, preventing performance overhead. It returns a compact snippet rather than a full document serialization, making it safe for logging and interactive debugging.

How does Zendriver handle the class attribute in the representation?

Python reserves the keyword class, so Zendriver stores the attribute as class_ internally. The __repr__ method detects this key and renders it as class="value" in the output string to match standard HTML syntax.

Can I use the element representation directly in test assertions?

Yes. Because __repr__ returns a deterministic string containing the tag name and attributes, you can validate element state using standard string containment checks (e.g., assert "disabled" in repr(button)), though explicit property checks remain the robust choice for production test suites.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →