Skip to content

Conversation

@seanmcguire12
Copy link
Member

@seanmcguire12 seanmcguire12 commented Dec 19, 2025

why

  • to add more coverage for the functions that captureHybridSnapshot() depends on

what changed

  • added helpers/mockCDPSession.ts so that we can re use the mocked CDP session across tests
  • updated the existing snapshot-cbor.test.ts to use the shared CDP session mock
    added snapshot-dom-session-builders.test.ts which holds tests for the following:
  • hydrateDomTree()
    • checks that truncated nodes trigger DOM.describeNode
    • checks that CBOR failures retry and eventually populate children
    • checks that exhausting every depth attempt raises StagehandDomProcessError
  • getDomTreeWithFallback()
    • checks that DOM.getDocument retries when CBOR errors occur (including depth sequencing)
    • checks that non-CBOR failures are propagated up
    • checks that that a full run of CBOR failures results in StagehandDomProcessError
  • buildSessionDomIndex()
    • checks that absolute xpaths, scrollability flags, per-document roots, and iframe content-document mappings are recorded correctly across nested DOM/shadow/doc structures
  • domMapsForSession()
    • checks that owner lookups remap into the iframe’s content document (producing frame-relative tag/xpath/scrollable maps)
    • checks that failing owner lookups gracefully fall back to the root document without crashing

test plan

  • this is it

Summary by cubic

Add unit tests for DOM session builder functions used by captureHybridSnapshot and introduce a reusable MockCDPSession helper. Tests cover CBOR retry logic, DOM hydration, error propagation, iframe/content-document indexing, scrollability, and frame‑relative maps with fallback behavior.

  • hydrateDomTree: expands truncated nodes via DOM.describeNode, retries on CBOR errors, errors after max attempts

  • getDomTreeWithFallback: retries DOM.getDocument with depth sequencing on CBOR errors, propagates non-CBOR errors, errors after all attempts

  • buildSessionDomIndex: records absolute xpaths, scrollability, per-document roots, and iframe content-document links

  • domMapsForSession: builds frame‑relative tag/xpath/scrollable maps, remaps via frame owner, falls back to root on owner lookup failure

  • Refactors

    • Replaced inline CDP stub with shared helpers/mockCDPSession and updated snapshot-cbor.test.ts to use it

Written for commit adec18d. Summary will update automatically on new commits.

@changeset-bot
Copy link

changeset-bot bot commented Dec 19, 2025

⚠️ No Changeset found

Latest commit: adec18d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 19, 2025

Greptile Summary

This PR adds comprehensive test coverage for DOM snapshot builder functions used by captureHybridSnapshot(). The changes include:

  • New mock helper (mockCDPSession.ts): Extracted from existing test code for reusability across test suites
  • Updated existing tests (snapshot-cbor.test.ts): Refactored to use the shared MockCDPSession instead of inline StubSession
  • New test suite (snapshot-dom-session-builders.test.ts): Covers four critical functions with 8 test cases verifying:
    • CBOR stack error handling with exponential depth retries
    • DOM tree hydration for truncated nodes
    • Frame owner lookup with graceful fallback behavior
    • XPath calculation for nested DOM/iframe structures
    • Scrollability flag tracking across document boundaries

All tests are well-structured with proper handler mocks for the CDP session. The test coverage addresses edge cases like CBOR stack limit failures and owner lookup errors, which are important for robustness in complex DOM traversals.

Confidence Score: 5/5

  • This PR is safe to merge with high confidence - it adds test coverage without modifying production code.
  • The PR introduces only test files and test helper code with no changes to production logic. The test suite is comprehensive, covering normal paths, error conditions, and edge cases like CBOR failures and frame owner lookup fallbacks. All mock handlers are properly provided for the test scenarios. The refactoring of snapshot-cbor.test.ts maintains exact functional equivalence while improving code reusability. No breaking changes or regressions are introduced.
  • No files require special attention

Important Files Changed

Filename Overview
packages/core/tests/helpers/mockCDPSession.ts New mock CDP session class extracted from snapshot-cbor.test.ts for test reusability. Properly implements CDPSessionLike interface with session tracking and call history inspection via callsFor() method. No issues found.
packages/core/tests/snapshot-cbor.test.ts Updated to use new MockCDPSession instead of inline StubSession. Changes are functionally equivalent - all tests maintain same behavior and assertions. Improves maintainability by sharing mock implementation.
packages/core/tests/snapshot-dom-session-builders.test.ts Comprehensive new test suite covering four DOM snapshot functions: hydrateDomTree, getDomTreeWithFallback, buildSessionDomIndex, and domMapsForSession. Tests verify CBOR error handling, depth retries, iframe traversal, and frame owner lookup fallbacks. All test cases are properly constructed with required handler mocks.

Sequence Diagram

sequenceDiagram
    participant Test as Test Code
    participant Session as MockCDPSession
    participant Handler as Handler Functions

    Test->>Session: new MockCDPSession({handlers})
    Test->>Session: hydrateDomTree(session, root, pierce)
    Session->>Session: Check if node needs expansion
    Session->>Handler: send("DOM.describeNode", {depth, ...})
    Handler-->>Session: Return expanded node
    Session-->>Test: Return hydrated tree

    Test->>Session: getDomTreeWithFallback(session, pierce)
    loop Retry with reduced depths
        Session->>Handler: send("DOM.getDocument", {depth, ...})
        alt CBOR Error
            Handler-->>Session: Error: "CBOR: stack limit exceeded"
            Session->>Session: Try next depth
        else Success
            Handler-->>Session: Return DOM tree
            Session->>Session: hydrateDomTree if needed
            Session-->>Test: Return root node
        end
    end

    Test->>Session: buildSessionDomIndex(session, pierce)
    Session->>Handler: send("DOM.enable")
    Session->>Session: getDomTreeWithFallback()
    Session->>Handler: send("DOM.describeNode") [if needed]
    Handler-->>Session: Return tree with metadata
    Session-->>Test: Return SessionDomIndex

    Test->>Session: domMapsForSession(session, frameId, pierce, encode, attemptOwnerLookup)
    Session->>Handler: send("DOM.enable")
    Session->>Session: getDomTreeWithFallback()
    alt attemptOwnerLookup enabled
        Session->>Handler: send("DOM.getFrameOwner")
        alt Success
            Handler-->>Session: Return ownerBackendId
            Session->>Session: Find iframe's contentDocument
        else Failure
            Handler-->>Session: Throw error
            Session->>Session: Fall back to root document
        end
    end
    Session->>Session: Traverse startNode and build maps
    Session-->>Test: Return {tagNameMap, xpathMap, scrollableMap}
Loading

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Architecture diagram
sequenceDiagram
    participant Test as Test Suite
    participant Builder as DOM Builder Logic
    participant MockCDP as NEW: MockCDPSession

    Note over Test,MockCDP: Scenario 1: CBOR Error Recovery (getDomTreeWithFallback)
    
    Test->>Builder: getDomTreeWithFallback()
    loop Depth Retry Strategy
        Builder->>MockCDP: send("DOM.getDocument", { depth: N })
        alt NEW: CBOR/Stack Limit Error
            MockCDP-->>Builder: Throw Error
            Builder->>Builder: Catch & Reduce Depth (e.g. -1 -> 256)
        else Success
            MockCDP-->>Builder: Return Root Node
        end
    end

    Note over Test,MockCDP: Scenario 2: Hydrating Truncated Nodes (hydrateDomTree)

    Builder->>Builder: Scan tree for truncated nodes
    opt Node has childNodeCount > children.length
        Builder->>MockCDP: send("DOM.describeNode", { nodeId })
        MockCDP-->>Builder: Return full node data
        Builder->>Builder: Populate missing children
    end

    Note over Test,MockCDP: Scenario 3: Frame Relative Mapping (domMapsForSession)

    Test->>Builder: domMapsForSession(frameId)
    Builder->>MockCDP: send("DOM.getFrameOwner", { frameId })
    
    alt Owner Found (Iframe)
        MockCDP-->>Builder: { backendNodeId }
        Builder->>Builder: NEW: Remap XPaths relative to Iframe Content Doc
    else Owner Lookup Failed (Fallback)
        MockCDP-->>Builder: Throw Error
        Builder->>Builder: NEW: Fallback to Root Document context
    end
    
    Builder-->>Test: Return { xpathMap, tagMap, scrollableMap }
Loading

import { StagehandDomProcessError } from "../lib/v3/types/public/sdkErrors";
import { MockCDPSession } from "./helpers/mockCDPSession";

let nextNodeId = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to reset this in a beforeEach? Not sure.

@seanmcguire12 seanmcguire12 merged commit ead1d14 into main Dec 20, 2025
45 of 47 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants