Commit Graph
11 Commits
Author SHA1 Message Date
SGavrl a3b21bbb70 fix(cdp,js): playwright actionability stubs and objectId resolve (#178)
Playwright fails locator actions on Obscura for two avoidable reasons
that are separate from the missing layout engine. Both have trivial
fixes that unblock the actionability polling loop.

- Element.checkVisibility(opts) was undefined. Playwright >= 1.25 calls
  it before every input event and retries until its action timeout if
  the method isn't a function. Add a stub that returns true. Without a
  layout pass we can't compute it for real, but a permissive stub still
  beats the undefined-function path.

- ARIA reflection properties were missing on Element (role, ariaLabel,
  ariaSelected, ariaExpanded, ariaHidden, ariaChecked, ariaDisabled,
  ariaRoleDescription). Playwright's getByRole and getByLabel locators
  read them. Reflect through to the underlying aria-* attributes for
  both read and write.

- DOM.getBoxModel and DOM.getContentQuads ignored the objectId param.
  Playwright passes only objectId (from a prior DOM.resolveNode), and
  the handlers silently defaulted to node 0, so dispatchMouseEvent
  always clicked the wrong element. Extract a resolve_node_id helper
  that honors nodeId, backendNodeId, and objectId in that order.

- Page.captureScreenshot and Page.captureSnapshot now return a clear
  "not supported, use a real Chromium for the screenshot leg" error
  instead of the generic "Unknown Page method" fallback. Matches the
  pattern already in place for Page.printToPDF.

Partial fix for #45. The architectural blocker (no layout engine, so
multi-element click coordinates are wrong) is unchanged.
2026-05-24 20:13:43 +00:00
Ben Younes 183c444a56 fix(js,dom): add Storage global, CharacterData ChildNode methods, fix remove/isConnected (#176)
fix(dom): add missing DOM/JS shims for modern frameworks

Closes #163.

Adds missing DOM and JS shims required by modern frameworks (Svelte 5, 
Vue, Lit) and consent-management SDKs to execute without errors:

- Define the `Storage` global constructor to resolve `ReferenceError`s 
  and fix `Storage.prototype` access.
- Apply standard ChildNode methods (`before`, `after`, `replaceWith`, 
  `remove`) to `CharacterData.prototype`. This prevents `TypeError`s when 
  frameworks call these on Text or Comment nodes during hydration.
- Update `Element.prototype.isConnected` to perform a genuine parent-walk 
  rather than returning a hardcoded `true`.
- Fix `Element.prototype.remove` to properly clean up the internal ID 
  index so removed elements are no longer queryable.
- Remove outdated no-op stubs on the `Element` class that were shadowing 
  the proper polyfill implementations.
2026-05-24 17:36:19 +00:00
SGavrl 1950048138 fix(browser,cdp,js): about:blank navigation, real getBoxModel/getContentQuads, expose _wrap and self
- about: URL scheme now handled in navigate_single instead of
  hitting validate_url and failing with "Forbidden URL scheme"
- DOM.getBoxModel calls getBoundingClientRect via JS instead of
  returning hardcoded pixel coords
- DOM.getContentQuads added (was missing, needed by Playwright click)
- globalThis._wrap exposed so CDP eval code can look up nodes by id
- globalThis.self = globalThis for webpack/bundler worker detection
2026-05-18 10:11:54 +00:00
SGavrl 913e6a4865 fix(browser,cdp): correct document lifecycle ordering and add missing DOM methods
document.readyState was hardcoded to "complete" so scripts checking
readyState === 'loading' always took the wrong branch. Fixed by using a
JS global (__documentReadyState__) that Rust sets to "loading" before
any scripts execute, "interactive" before DOMContentLoaded fires, and
"complete" after load.

document.addEventListener and document.dispatchEvent on Document were
no-ops, so DOMContentLoaded listeners registered by inline scripts were
never called. Added proper listener storage and dispatch on Document.

Adds document.getElementsByName() (was missing entirely).

Page.reload is now implemented (re-navigates to the current URL),
resolving "Unknown Page method: reload" errors from Playwright.

data: URL navigation now works, fixing Playwright's goto("data:text/html,...")
pattern that previously errored with "invalid format".

Page.navigate logic extracted into do_navigate() so reload can reuse it.

Fixes #137, #146 (SPA bootstrap lifecycle ordering).
2026-05-18 09:50:23 +00:00
Alexandr KondakovandSGavrl 6dd1e4e65f Fix CDP click submit navigation parity (#69)
* Fix Runtime.evaluate awaitPromise settling

* Fix DOM event navigation side effects

* Fix CDP click-triggered navigation parity

* Strengthen CDP inline script click parity test

* Handle positions-like submit URLs in CDP parity


Co-authored-by: SGavrl <[email protected]>
2026-05-15 20:38:54 +00:00
Ben YounesandOra Studio 111150a4f8 fix(js): add elementFromPoint / elementsFromPoint stubs (#63) (#75)
document.elementFromPoint(x, y) was undefined, which caused Google
Publisher Tag, viewability libs and any code doing hit-testing to
throw on bootstrap and trigger retry loops in the surrounding
framework. This is one of the throwing APIs feeding into the wedge
described in #62.

Without a layout engine we can't return the actual topmost element,
but a non-throwing stub is strictly better than "undefined" for the
headless-scraping use case:

- coords inside the viewport return document.body (or
  document.documentElement as a fallback) so callers that just want
  a hit target stop throwing
- coords outside the viewport (negative, > innerWidth/innerHeight,
  NaN/Infinity) return null per spec
- elementsFromPoint mirrors the same shape but returns a one- or
  zero-length array
- ShadowRoot.prototype gets the same treatment for completeness

Five new unit tests in obscura-js cover function presence, in-viewport
hit, out-of-viewport coords, non-numeric input, and the array shape.

Generated by Ora Studio
Vibe coded by ousamabenyounes

Co-authored-by: Ora Studio <[email protected]>
2026-05-03 17:19:17 +02:00
Ben YounesandOra Studio d50dd0f553 fix(js): make createEvent type-aware and add initCustomEvent (#41) (#77)
document.createEvent('CustomEvent') was returning a generic Event,
so the legacy DOM Level 2 pattern

  var e = document.createEvent('CustomEvent');
  e.initCustomEvent('foo', true, false, payload);

threw "TypeError: e.initCustomEvent is not a function" because the
returned object was an Event, not a CustomEvent — and CustomEvent
didn't define initCustomEvent anyway. The Starbucks China bundle
(and a long tail of other CDN bundles using the same shim) depended
on this and aborted bootstrap.

Two changes in crates/obscura-js/js/bootstrap.js:

1. Add CustomEvent.prototype.initCustomEvent(type, bubbles, cancelable,
   detail) matching the spec.
2. Rewrite Document.prototype.createEvent so it dispatches to the
   right class based on the type string ('CustomEvent', 'MouseEvent',
   'MouseEvents', 'KeyboardEvent', 'FocusEvent', 'InputEvent',
   'UIEvent', 'WheelEvent', 'PointerEvent', 'ErrorEvent',
   'PopStateEvent', 'AnimationEvent', 'TransitionEvent', and
   case-insensitive 'Events' aliases). The HTMLDocument variant on
   the second Document class delegates to the canonical impl.

Spec note: createEvent returns the event with an empty type until
init*Event() is called — matched exactly.

Four new unit tests cover initCustomEvent presence and field setters,
class dispatch for CustomEvent / MouseEvent / MouseEvents / KeyboardEvent,
and the unknown-type fallback to Event.

Generated by Ora Studio
Vibe coded by ousamabenyounes

Co-authored-by: Ora Studio <[email protected]>
2026-05-03 17:18:30 +02:00
KuaaMUandKuaaMU 86a868bfd6 fix: implement CharacterData DOM API for jQuery DataTables compatibility (#73)
jQuery DataTables references the standard CharacterData interface which
was undefined in obscura's DOM environment, causing ReferenceError and
empty page renders.

- Add CharacterData class extending Node with data/length/substringData/
  appendData/insertData/deleteData/replaceData
- Make Text and Comment extend CharacterData instead of Node
- Update _wrap() to create proper Text/Comment instances by nodeType
- Add create_comment_node op for Document.createComment()
- Fix set_text_content to handle Comment node mutations

Fixes #72

Co-authored-by: KuaaMU <[email protected]>
2026-05-03 17:16:26 +02:00
rifuki 53a04fa905 fix(wasm): preserve binary fetch responses (#48)
* fix wasm response handling

* fix URL inputs in fetch polyfill

* test(wasm): cover binary fetch responses
2026-04-27 17:31:54 +02:00
h4ckf0r0day 99e75f1e62 fix: load balancer panics, stealth flag, shadow DOM polyfill
Fixes #1: replace unwrap() panics in run_multi_worker_serve with match on the Result.
Fixes #2: route /json round-robin via worker_port instead of hardcoded port+1.
Fixes #3: return 502 Bad Gateway when a worker is unreachable instead of silently dropping the connection.
Fixes #5: thread --stealth through start_with_options -> CdpContext -> BrowserContext::with_options so the flag actually has an effect in serve mode (was let _ before). Log message now reflects the actual capability based on the stealth cargo feature being compiled in.
Fixes #15: try/catch the parentNode assignment in the attachShadow polyfill so it doesn't throw a TypeError against the read-only Node.parentNode getter (Cloudflare Turnstile triggers this path).
2026-04-25 14:27:52 +02:00
h4ckf0r0day 8749725b45 Initial Release 2026-04-13 12:30:28 +02:00