Summary
BrowserPage can act on a selector (click, type, hover, focus) but cannot read anything back. Playwright's state-query methods are all absent, so assertions have to reach through page.mainFrame.document and work on the DOM directly, which defeats the point of the page abstraction.
These are small, self-contained additions and the underlying data is already available — this is a thin adapter over the frame's document rather than new capability.
Reproduction
import { Browser } from 'very-happy-dom'
const page = new Browser().newPage()
page.content = '<body><h1>Hello</h1><input id="n" value="Ada"><input type="checkbox" id="c" checked><button disabled>Go</button></body>'
console.log(typeof page.textContent) // undefined
console.log(typeof page.innerText) // undefined
console.log(typeof page.innerHTML) // undefined
console.log(typeof page.inputValue) // undefined
console.log(typeof page.getAttribute) // undefined
console.log(typeof page.isVisible) // undefined
console.log(typeof page.isHidden) // undefined
console.log(typeof page.isChecked) // undefined
console.log(typeof page.isEnabled) // undefined
console.log(typeof page.isDisabled) // undefined
console.log(typeof page.isEditable) // undefined
console.log(typeof page.title) // undefined
// The values are all reachable, just not through the page:
const doc = page.mainFrame.document
console.log(doc.querySelector('h1').textContent) // Hello
console.log(doc.querySelector('#n').value) // Ada
console.log(doc.querySelector('#c').checked) // trueConfirmed against main at 5fae54d4 with Bun 1.4.3.
Current implementation
BrowserPage has content and url getters and nothing else that reads page state. Every action method resolves its selector, mutates, and returns void.
Expected behavior
Selector-taking query methods on BrowserPage, each resolving against the main frame's document:
| Method | Returns |
|---|---|
textContent(selector) | string | null — the element's textContent |
innerText(selector) | string — rendered text |
innerHTML(selector) | string |
inputValue(selector) | string — for input, textarea, select |
getAttribute(selector, name) | string | null |
isVisible(selector) | boolean |
isHidden(selector) | boolean |
isChecked(selector) | boolean |
isEnabled(selector) | boolean |
isDisabled(selector) | boolean |
isEditable(selector) | boolean |
title() | string — the document title |
Two details worth deciding explicitly:
- In Playwright these are
async. Matching that keeps signatures portable even though nothing here needs to await. isVisiblehas no layout engine to consult. A reasonable definition is: the element is in the document and neither it nor an ancestor hasdisplay: none,visibility: hiddenor thehiddenattribute. That should be documented, since it will not match a real browser for zero-size or off-screen elements.
For the non-existent-selector case, Playwright's own split is worth following: isVisible returns false, while textContent and friends throw.
Related: #1591 — these same methods belong on Locator, and sharing one resolve-and-read implementation between the two would avoid divergence.