Skip to content

Commit e3b32f6

Browse files
Michael McNeesMichael McNees
authored andcommitted
feat(browser): browser/evaluate connector — completes declarative action set
1 parent 8642ebb commit e3b32f6

3 files changed

Lines changed: 78 additions & 0 deletions

File tree

packages/engine/internal/connector/browser_declarative.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,37 @@ func (c *BrowserNavigateConnector) Execute(ctx context.Context, params map[strin
221221
return out, nil
222222
}
223223

224+
// BrowserEvaluateConnector implements browser/evaluate.
225+
type BrowserEvaluateConnector struct{}
226+
227+
func (c *BrowserEvaluateConnector) Execute(ctx context.Context, params map[string]any) (map[string]any, error) {
228+
expression, _ := params["expression"].(string)
229+
if strings.TrimSpace(expression) == "" {
230+
return nil, fmt.Errorf("browser/evaluate: expression is required")
231+
}
232+
session, err := extractSession(params)
233+
if err != nil {
234+
return nil, fmt.Errorf("browser/evaluate: %w", err)
235+
}
236+
// expression is embedded verbatim as a JS expression — callers are responsible for valid JS.
237+
snippet := fmt.Sprintf("actionData.result = await page.evaluate(() => { return (%s); });\n", expression)
238+
script, err := buildDeclarativeScript(snippet, session, extractTimeoutMs(params), false)
239+
if err != nil {
240+
return nil, fmt.Errorf("browser/evaluate: %w", err)
241+
}
242+
envelope, err := executeBrowserScript(ctx, script, params)
243+
if err != nil {
244+
return nil, fmt.Errorf("browser/evaluate: %w", err)
245+
}
246+
out := map[string]any{"session_state": envelope["session_state"]}
247+
if data, ok := envelope["data"].(map[string]any); ok {
248+
if v, ok := data["result"]; ok {
249+
out["result"] = v
250+
}
251+
}
252+
return out, nil
253+
}
254+
224255
// BrowserWaitConnector implements browser/wait.
225256
// Exactly one of selector, url_pattern, or duration_ms must be provided.
226257
type BrowserWaitConnector struct{}

packages/engine/internal/connector/browser_declarative_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,3 +431,49 @@ func TestBrowserWait_InvalidSession(t *testing.T) {
431431
t.Fatal("expected error for invalid session_state")
432432
}
433433
}
434+
435+
func TestBrowserEvaluate_MissingExpression(t *testing.T) {
436+
c := &BrowserEvaluateConnector{}
437+
_, err := c.Execute(context.Background(), map[string]any{})
438+
if err == nil {
439+
t.Fatal("expected error for missing expression")
440+
}
441+
if !strings.Contains(err.Error(), "expression is required") {
442+
t.Errorf("error = %q, want 'expression is required'", err)
443+
}
444+
}
445+
446+
func TestBrowserEvaluate_EmptyExpression(t *testing.T) {
447+
c := &BrowserEvaluateConnector{}
448+
_, err := c.Execute(context.Background(), map[string]any{
449+
"expression": " ",
450+
})
451+
if err == nil {
452+
t.Fatal("expected error for blank expression")
453+
}
454+
}
455+
456+
func TestBrowserEvaluate_InvalidSession(t *testing.T) {
457+
c := &BrowserEvaluateConnector{}
458+
_, err := c.Execute(context.Background(), map[string]any{
459+
"expression": "document.title",
460+
"session_state": false,
461+
})
462+
if err == nil {
463+
t.Fatal("expected error for invalid session_state")
464+
}
465+
}
466+
467+
func TestBrowserEvaluate_ScriptContainsExpression(t *testing.T) {
468+
snippet := "actionData.result = await page.evaluate(() => { return (document.title); });\n"
469+
script, err := buildDeclarativeScript(snippet, nil, 30000, false)
470+
if err != nil {
471+
t.Fatalf("buildDeclarativeScript: %v", err)
472+
}
473+
if !strings.Contains(script, "document.title") {
474+
t.Error("script should contain the expression")
475+
}
476+
if !strings.Contains(script, "page.evaluate") {
477+
t.Error("script should use page.evaluate")
478+
}
479+
}

packages/engine/internal/connector/connector.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ func NewRegistry() *Registry {
4646
r.Register("browser/extract", &BrowserExtractConnector{})
4747
r.Register("browser/screenshot", &BrowserScreenshotConnector{})
4848
r.Register("browser/wait", &BrowserWaitConnector{})
49+
r.Register("browser/evaluate", &BrowserEvaluateConnector{})
4950
r.Register("github/create_issue", &GitHubCreateIssueConnector{})
5051
r.Register("github/dispatch", &GitHubDispatchConnector{})
5152
r.Register("github/dispatch_workflow", &GitHubDispatchWorkflowConnector{})

0 commit comments

Comments
 (0)