Skip to content

[v4]: more page route stubs for locator functions#1882

Open
seanmcguire12 wants to merge 3 commits intomainfrom
seanmcguire/stg-1646-add-locator-stubs-to-page-route-post
Open

[v4]: more page route stubs for locator functions#1882
seanmcguire12 wants to merge 3 commits intomainfrom
seanmcguire/stg-1646-add-locator-stubs-to-page-route-post

Conversation

@seanmcguire12
Copy link
Member

@seanmcguire12 seanmcguire12 commented Mar 24, 2026

why

  • to add page routes for more of the locator functions

what changed

  • added the following route stubs:
    • /fill
    • /highlight
    • /selectOption
    • /setInputFiles
  • each of the above optionally returns a selector object if returnSelector: true
  • aligned existing /click, /hover, and /dragAndDrop routes to default returnSelector to false

screenshot:

Screenshot 2026-03-24 at 1 25 11 PM

test plan


Summary by cubic

Adds v4 page route stubs for locator actions: /v4/page/fill, /v4/page/highlight, /v4/page/selectOption, and /v4/page/setInputFiles. Addresses STG-1646 and updates OpenAPI and schemas; routes return placeholder results with optional selector output.

  • New Features

    • Added POST endpoints: /v4/page/fill, /v4/page/highlight, /v4/page/selectOption, /v4/page/setInputFiles (wired into router and fully documented in OpenAPI).
  • Refactors

    • Default returnSelector is now false for /click, /hover, and /dragAndDrop.
    • ResultSelector is now required in result schemas.

Written for commit f62f42e. Summary will update on new commits. Review in cubic

@changeset-bot
Copy link

changeset-bot bot commented Mar 24, 2026

⚠️ No Changeset found

Latest commit: f62f42e

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

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.

1 issue found across 7 files

Confidence score: 4/5

  • This PR appears safe to merge overall, with only a low-to-moderate risk note rather than a clear functional defect.
  • The main concern is in packages/server-v4/src/routes/v4/page/highlight.ts: missing unit tests for the new /page/highlight behavior (including returnSelector) could allow regressions to slip through unnoticed.
  • Given the issue’s moderate confidence and non-blocking nature, this is best treated as follow-up test hardening rather than a merge blocker.
  • Pay close attention to packages/server-v4/src/routes/v4/page/highlight.ts - new endpoint behavior needs test coverage to prevent silent regressions.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/server-v4/src/routes/v4/page/highlight.ts">

<violation number="1" location="packages/server-v4/src/routes/v4/page/highlight.ts:15">
P2: Add unit tests covering the new /page/highlight route (including returnSelector behavior) so this new endpoint doesn’t regress silently.

(Based on your team's feedback about adding unit tests for new behavior.) [FEEDBACK_USED]</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Client
    participant Router as Fastify Router
    participant Schema as Zod / OpenAPI Schema
    participant Handler as Page Action Handler
    participant Exec as Action Execution (Stub)

    Note over Client,Exec: NEW & UPDATED Locator Action Flow

    Client->>Router: POST /v4/page/{action}
    Note right of Client: action = fill, highlight, selectOption, setInputFiles, etc.

    Router->>Schema: Validate Request Body
    Note over Schema: CHANGED: returnSelector defaults to 'false'<br/>for click, hover, dragAndDrop, and new actions.
    
    alt Validation Fails
        Schema-->>Router: 400 Bad Request
        Router-->>Client: Error Response
    else Validation Success
        Schema-->>Router: Validated Params
    end

    Router->>Handler: NEW: createPageActionHandler(method)
    
    Handler->>Exec: execute()
    Note over Exec: NEW: Returns stubbed results<br/>(e.g., PageFillResult, PageHighlightResult)
    
    Exec-->>Handler: Stubbed Result Object
    
    Handler->>Schema: Parse & Validate Result
    Note over Schema: NEW: ResultSelector is now required in result schemas
    Schema-->>Handler: Validated Action Object
    
    Handler-->>Router: Action Response
    Router-->>Client: 200 OK (PageActionResponse)
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


const highlightRoute: RouteOptions = {
method: "POST",
url: "/page/highlight",
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 24, 2026

Choose a reason for hiding this comment

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

P2: Add unit tests covering the new /page/highlight route (including returnSelector behavior) so this new endpoint doesn’t regress silently.

(Based on your team's feedback about adding unit tests for new behavior.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/server-v4/src/routes/v4/page/highlight.ts, line 15:

<comment>Add unit tests covering the new /page/highlight route (including returnSelector behavior) so this new endpoint doesn’t regress silently.

(Based on your team's feedback about adding unit tests for new behavior.) </comment>

<file context>
@@ -0,0 +1,38 @@
+
+const highlightRoute: RouteOptions = {
+  method: "POST",
+  url: "/page/highlight",
+  schema: {
+    operationId: "PageHighlight",
</file context>
Fix with Cubic

export const PageHoverParamsSchema = PageWithPageIdSchema.extend({
selector: SelectorSchema,
returnSelector: z.boolean().optional(),
returnSelector: z.boolean().default(false).optional(),
Copy link
Member

Choose a reason for hiding this comment

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

Why not just always return the selector?

Copy link
Member Author

Choose a reason for hiding this comment

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

populating the selector schema can be expensive, so the user should be able to decide whether they want it


export const PageFillParamsSchema = PageWithPageIdSchema.extend({
selector: SelectorSchema,
value: z.string(),
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
value: z.string(),
value: z.union([z.string(), z.number(), z.boolean(), ...]),

Shouldnt this support more types? form input fields can be checkboxes, radio selectors, select dropdowns, datepickers, etc.

Copy link
Member Author

Choose a reason for hiding this comment

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


export const PageHighlightParamsSchema = PageWithPageIdSchema.extend({
selector: SelectorSchema,
color: z.string().optional(),
Copy link
Member

Choose a reason for hiding this comment

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

How do we control the color lol? Doesn't this just mean "select this text on the page with the cursor?

Or are we actually modifying the CSS to color the element somehow?
If it's the latter I wouldnt expose just color, I would expose an endpoint to apply arbitrary CSS to any element and let the user decide how to color (e.g. background-color, color, opacity, etc.).

Copy link
Member Author

Choose a reason for hiding this comment

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

the latter. open to exposing an applyCSS route though


export const PageSelectOptionParamsSchema = PageWithPageIdSchema.extend({
selector: SelectorSchema,
values: z.array(z.string()),
Copy link
Member

@pirate pirate Mar 25, 2026

Choose a reason for hiding this comment

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

Suggested change
values: z.array(z.string()),
values: z.array(z.string()).description('Values or labels for the <option>s you want to select'),

Agents very often will try to pass the text label (what they see on the page via screenshot) and not the actual value attr, so we need to support both and fallback to substring/fuzzy matching. Select option text is often truncated, slightly occluded, or contains weird characters/whitespace that make exact matches hard.

Keep in mind this endpoint also needs to support aria-based selectors that are custom HTML and not <select> elements (which are super common on modern sites). Returning a single selector doesn't always make sense, a multi-select might be built out of 8 sibling dom elements for example. https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-selected

Copy link
Member Author

Choose a reason for hiding this comment

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

  • can add the description. for clarity, the existing locator.selectOption() does support labels & values.
  • we can try to do fuzzy matching when this route actually gets implemented
  • this route is modeled after the existing locator.selectOption() function, & therefore does not support non-select elements. the single selector that is returned will point to the outer <select> element

.meta({ id: "PageSelectOptionParams" });

export const PageSetInputFilesParamsSchema = PageWithPageIdSchema.extend({
selector: SelectorSchema,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
selector: SelectorSchema,
selector: SelectorSchema.optional(),

selector should be optional imo, you should be able to set default upload files for a page, then any click on an <input type="file"> should autopopulate the files and close the file selector popup.

export const PageFillResultSchema = z
.object({
selector: ResultSelectorSchema,
value: z.string(),
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
value: z.string(),
value: z.union([z.string(), ...]),

Needs more types for more <input> types.

export const PageHighlightResultSchema = z
.object({
selector: ResultSelectorSchema,
highlighted: z.boolean(),
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
highlighted: z.boolean(),

Route should just return an error if highlight CSS applying fails.

Comment on lines +936 to +937
selector: ResultSelectorSchema,
selected: z.array(z.string()),
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
selector: ResultSelectorSchema,
selected: z.array(z.string()),
selector: ResultSelectorSchema,
selected: z.array(z.string()),
isMultiSelect: z.boolean(),

we should clearly indicate when they try to select multiple options but the select field only supports one / vice versa


export const PageSetInputFilesResultSchema = z
.object({
selector: ResultSelectorSchema,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
selector: ResultSelectorSchema,
selector: ResultSelectorSchema.optional(),

Copy link
Member Author

Choose a reason for hiding this comment

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

to reduce union types, i want to always return the ResultSelectorSchema shape, but it is just {} if the user didn't set returnSelector: true

Copy link
Member

@pirate pirate left a comment

Choose a reason for hiding this comment

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

Lots of small comments but the biggest items are:

  • I think we should replace highlight with a generic applyCss endpoint, because highlighting should not only support color
  • I dont think we need returnSelector on every route, we should just always return the selector but omit any expensive fields
  • fill needs to support more types (slider, radio, checkbox, date, time, color, number, etc.), ideally we should merge SelectOption into fill imo so it supports truly all fields

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.

2 participants