Skip to content

Add rodney discover command for listing data-testid elements - #42

Open
jstockdi wants to merge 44 commits into
simonw:mainfrom
Battle-Creek-LLC:main
Open

Add rodney discover command for listing data-testid elements#42
jstockdi wants to merge 44 commits into
simonw:mainfrom
Battle-Creek-LLC:main

Conversation

@jstockdi

@jstockdi jstockdi commented Mar 9, 2026

Copy link
Copy Markdown

Add rodney discover — scan pages for testable elements

What this adds

A new rodney discover command that scans the current page for elements with a test attribute (default: data-testid) and outputs them grouped by type with suggested rodney commands. This makes it easy to explore an unfamiliar page and quickly build automation scripts.

rodney open https://example.com
rodney discover              # scan for data-testid elements
rodney discover --json       # machine-readable output
rodney discover --attr data-cy  # use a custom attribute

Example output

Page: https://example.com/dashboard

Readable:
  heading                All systems operational              rodney text '[data-testid="heading"]'
  results-table          Name, Status (2 rows)                rodney text '[data-testid="results-table"]'

Interactive:
  search                 Search...                            rodney input '[data-testid="search"]' "<text>"
  submit-btn             Submit                               rodney click '[data-testid="submit-btn"]'
  filter                 All, Active                          rodney select '[data-testid="filter"]' "<value>"

Hidden:
  hidden-el              Hidden content                       rodney text '[data-testid="hidden-el"]'

Why

When automating against an app that uses data-testid (or data-cy, data-test, etc.), the first step is usually figuring out what elements are available. Today you'd need to open DevTools or pipe rodney html through grep. rodney discover makes this a single command that also suggests the exact rodney commands to interact with each element.

This is especially useful when rodney is used by AI agents or in scripted workflows where the page structure isn't known in advance.

Implementation

  • queryDiscoverEntries(page, attrName) — runs a JS query on the page, classifies each element by tag/type (button→click, input→input, select→select, a→click, table→text, etc.), and returns structured discoverEntry results
  • formatDiscoverText(entries, attrName, pageURL) — groups entries into Readable/Interactive/Hidden and formats with suggested commands
  • cmdDiscover — wires up --json and --attr flags, delegates to the above functions

Tests

13 new tests covering:

  • Element detection across all supported types (button, input, textarea, link, select, table)
  • Hidden element visibility detection
  • Custom attribute via --attr
  • Empty page (no matches)
  • Text output grouping and suggested commands
  • JSON round-trip serialization

All 75 tests pass (62 existing + 13 new).

gthb and others added 30 commits February 17, 2026 23:37
The --show flag was documented in help.txt but rejected at runtime.
Two sequential arg-parsing loops meant the first loop called fatal()
on --show before the second loop (which handled it) could run.

Extract parseStartFlags() with a single merged loop and add 6 tests.

Fixes simonw#23

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pipe a JS expression directly via stdin instead of passing it as a
shell argument — useful for complex expressions, multi-line scripts,
and heredocs.

  echo 'document.title' | rodney js
  cat script.js | rodney js
  rodney js - < expr.js

Pass `-` as the argument to read from stdin explicitly (consistent
with `rodney file`). When no argument is given, stdin is read only if
it is a pipe; an interactive terminal still shows the usage message.

Adds four integration tests that exercise no-arg piping, the `-` flag,
multi-line / heredoc-style input, and whitespace trimming.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…hone/camera

Passes --use-fake-device-for-media-stream and --use-fake-ui-for-media-stream
to Chrome, which provides synthetic media streams instead of prompting for
real device access. Without this, headless Chrome crashes when a page calls
getUserMedia().
Adds viewport/mobile emulation via Chrome's EmulationSetDeviceMetricsOverride CDP call:

- `rodney viewport <w> <h> [--scale N] [--mobile]` — set viewport size
- `rodney viewport --reset` — restore browser defaults
- `rodney start --viewport WxH [--mobile] [--scale N]` — configure viewport at launch

Viewport settings are persisted in state.json and re-applied on each subsequent
command, matching rodney's ephemeral-process architecture.

Also fixes a pre-existing bug where `rodney start --show` would hit the unknown
flag error before reaching the headless flag parser. All start flags are now
parsed in a single pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, `rodney screenshot` always overrode the viewport to 1280x720
(scale 1), clobbering any viewport set via `rodney viewport`. Now it only
applies its default viewport when no viewport override is active or when
-w/-h are explicitly passed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scans the current page for elements with a test attribute (default:
data-testid) and outputs them grouped by type (Readable, Interactive,
Hidden) with suggested rodney commands. Supports --json for structured
output and --attr to use a custom attribute name.
Integrate PR simonw#34 (slaskis/rodney#logs) onto main. Adds a `_logger`
subprocess spawned by `rodney start --logs` that captures browser
console output to per-page NDJSON files via Runtime.consoleAPICalled.

- `rodney logs` prints buffered console entries (snapshot mode)
- `rodney logs -f` streams new entries in real time
- `rodney logs -n N` limits to last N entries
- `rodney logs --json` outputs raw NDJSON

Uses a blank-page-first strategy in cmdOpen/cmdNewPage when logs are
enabled to ensure RuntimeEnable is called before inline scripts execute.
# Conflicts:
#	main.go
#	main_test.go
# Conflicts:
#	README.md
#	main.go
# Conflicts:
#	README.md
#	help.txt
#	main.go
#	main_test.go
# Conflicts:
#	main_test.go
# Conflicts:
#	main_test.go
# Conflicts:
#	main_test.go
# Conflicts:
#	main_test.go
jstockdi and others added 14 commits April 3, 2026 15:51
# Conflicts:
#	main.go
#	main_test.go
# Conflicts:
#	main.go
#	main_test.go
# Conflicts:
#	main.go
#	main_test.go
# Conflicts:
#	main.go
#	main_test.go
launcher.New() skips rod's own LookPath() and tries to download
Chromium, even when a system browser (e.g. /usr/bin/chromium) is
already installed. Add a LookPath() fallback between the explicit
ROD_CHROME_BIN env var check and rod's default auto-download.
Two regressions made `rodney start` unusable on macOS when a regular
Chrome was already running:

1. Commit 781bd1c preferred system Chrome via launcher.LookPath(), but
   Google Chrome.app enforces single-instance per bundle on macOS. When
   the user's regular Chrome was running, the rodney-launched process
   was absorbed and exited immediately. Skip LookPath on darwin so
   rodney falls back to go-rod's auto-downloaded Chromium, which has
   its own bundle and coexists cleanly. Other platforms keep the
   LookPath behavior for /usr/bin/chromium reuse.

2. --single-process was hardcoded since c164016 as a workaround for
   Chrome's compositor hanging under gVisor (Claude's sandbox), but it
   causes frequent crashes on real sites in normal desktop Chrome.
   Replace the hardcoded flag with --single-process auto|on|off, where
   auto (the default) enables it only when isGVisor() detects gVisor
   via /proc/version. Desktop gets stable multi-process Chrome; gVisor
   environments still get the screenshot fix automatically.
All workflow actions now reference immutable commit SHAs with the
original tag preserved as a trailing comment. Required by the
Battle-Creek-LLC repocat baseline (AC-6, SR-3) to prevent silent
upstream changes via tag re-pointing.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Standard private vulnerability reporting policy. Required by repocat
baseline (CM-2).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adopts the Keep a Changelog format with an initial 0.1.0 entry summarizing
the Battle-Creek-LLC fork's divergence from upstream simonw/rodney.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove build-wheels and PyPI publish jobs from publish.yml; this fork
  doesn't own the rodney name on PyPI and the trusted publisher binding
  belongs to upstream.
- Rename module to github.com/battle-creek-llc/rodney so
  \`go install github.com/battle-creek-llc/rodney@latest\` resolves to this
  fork via the Go module proxy. (Lowercase per Go module convention to
  avoid case-escaping in the proxy.)
- Update README badges and install instructions: drop PyPI/uv sections,
  point Changelog/Tests/License/releases links at Battle-Creek-LLC,
  call out the upstream attribution.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both exec.Command calls in main.go (the _proxy and _logger helper
launches) re-invoke our own binary via os.Executable(). They use no
shell, and every argument is a literal subcommand, a locally-bound
port, the tool's own DevTools URL, or operator-supplied local config
(HTTP(S)_PROXY / state dir) — none of which is attacker-controlled.

Add inline `// nosemgrep` comments with justifications. No runtime
behavior change. Verified with `go build ./...` and `go vet ./...`.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

7 participants