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

> Debug web elements efficiently with Zendriver's descriptive repr. Understand element tag, attributes, and text instantly for faster debugging without DOM serialization.

- Repository: [CDP Driver/zendriver](https://github.com/cdpdriver/zendriver)
- Tags: how-to-guide
- Published: 2026-02-27

---

**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`](https://github.com/cdpdriver/zendriver/blob/main/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`](https://github.com/cdpdriver/zendriver/blob/main/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`](https://github.com/cdpdriver/zendriver/blob/main/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:

```python
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:

```python
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:

```python
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:

```python
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`](https://github.com/cdpdriver/zendriver/blob/main/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`](https://github.com/cdpdriver/zendriver/blob/main/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`](https://github.com/cdpdriver/zendriver/blob/main/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.