Skip to content

[build-tools] Humanize Appium command summaries - #4227

Open
sjchmiela wants to merge 8 commits into
mainfrom
stanley/humanize-appium-commands
Open

[build-tools] Humanize Appium command summaries#4227
sjchmiela wants to merge 8 commits into
mainfrom
stanley/humanize-appium-commands

Conversation

@sjchmiela

@sjchmiela sjchmiela commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Why

We currently present Appium session events as HTTP methods which is not too human-readable (getWindowRect).

How

Added a GHA workflow which runs weekly and submits a pull request adding to an AppiumCommand type so TSC fails and we need to add descriptions to commands.

Test Plan

CI should pass.

Translate raw Appium command names (e.g. getWindowRect, getScreenshot)
into short human-readable summaries ("Read the screen size", "Took a
screenshot") for the session event timeline. The raw command is kept in
each event's data.command.

Unknown commands fall back to a camelCase humanizer. A generated snapshot
of @appium/base-driver's command set (added as a devDependency) backs a
coverage test so newly added Appium commands don't slip through
uncategorized.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sjchmiela
sjchmiela force-pushed the stanley/humanize-appium-commands branch from 6e5841b to 79fc04a Compare August 19, 2026 10:52
@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.73%. Comparing base (78644d2) to head (8481176).
⚠️ Report is 11 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4227      +/-   ##
==========================================
+ Coverage   63.53%   63.73%   +0.21%     
==========================================
  Files        1030     1031       +1     
  Lines       47253    47452     +199     
  Branches     9919     9978      +59     
==========================================
+ Hits        30017    30241     +224     
+ Misses      17135    17110      -25     
  Partials      101      101              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

sjchmiela and others added 4 commits August 19, 2026 18:05
- Give every upstream Appium command a curated summary; the coverage test
  now requires full coverage instead of allowing a fallback list.
- Stop humanizing unknown commands: show the raw command name when there
  is no curated summary, rather than guessing a phrasing.
- Add a weekly GitHub Actions workflow that bumps @appium/base-driver,
  regenerates the command list, and opens a PR so new commands surface
  (the coverage test then fails until each is given a summary).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ation

Drop @appium/base-driver as a devDependency. The generator script now
installs it into a temp directory on demand (like repack) and cleans up,
so nothing heavy ships with @expo/build-tools. The command list is still
committed as a generated snapshot, so tests never need the package.

The weekly workflow no longer bumps the dependency (the script always
pulls the latest supported base-driver) and requests review from
@sjchmiela on the PRs it opens.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the runtime coverage test with type-level assertions: the
generated command list is now a readonly tuple (`as const`) and
APPIUM_COMMAND_SUMMARIES uses `satisfies`, so `tsc` fails and names any
upstream command that lacks a curated summary (and any curated command
that is not a real upstream/driver-level one).

Also drop the unused `permissions:` block from the workflow — every step
authenticates with EXPO_BOT_PAT, so the default GITHUB_TOKEN is unused.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Type APPIUM_COMMAND_SUMMARIES as Record<AppiumCommand, string> so tsc
enforces full coverage directly (missing or unknown command -> error),
instead of the bespoke AssertNever checks. The generated file now exports
a `UpstreamAppiumCommand` union type rather than a runtime const array.

Also drop the changelog entry (internal, experimental feature).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sjchmiela sjchmiela added the no changelog PR that doesn't require a changelog entry label Aug 20, 2026
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sjchmiela
sjchmiela requested a review from szdziedzic August 20, 2026 12:28
Comment thread .github/workflows/update-appium-commands.yml Outdated
Comment thread .github/workflows/update-appium-commands.yml
Comment thread packages/build-tools/src/steps/utils/appiumCommandSummary.ts Outdated
@sjchmiela
sjchmiela requested a review from szdziedzic August 20, 2026 16:56
@github-actions

Copy link
Copy Markdown

⏩ The changelog entry check has been skipped since the "no changelog" label is present.

run: yarn workspace @expo/build-tools generate-appium-commands
- name: Open a pull request when the command list changed
env:
GH_TOKEN: ${{ secrets.EXPO_BOT_PAT }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Isolate dependency execution from EXPO_BOT_PAT

The generator installs the latest Appium and driver packages and then imports them, which executes npm lifecycle scripts and package module code in this job. Limiting GH_TOKEN to this step does not provide isolation: code from an earlier step can modify the same runner—for example, by installing a Git hook that executes during git commit and inherits GH_TOKEN.

Please split this into two jobs: a secretless generate job that uploads only appiumCommands.generated.ts, and a publish job on a fresh runner that downloads and commits that artifact. The publish job should not execute any code from the artifact.

];

function renderCommandType(typeName, commands) {
return `export type ${typeName} =\n${commands.map(command => ` | '${command}'`).join('\n')};`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Escape command names when generating TypeScript

command comes from the installed Appium packages and is interpolated directly into a single-quoted TypeScript literal. A command containing a quote, backslash, or newline would produce invalid or injected source.

Please serialize the value instead, for example:

commands.map(command => | ${JSON.stringify(command)})

* unchanged — we intentionally do not guess a phrasing.
*/
export function humanizeAppiumCommand(command: string): string {
return (APPIUM_COMMAND_SUMMARIES as Record<string, string>)[command] ?? command;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Only return own properties from the summary map

This indexed access also searches Object.prototype. Because command is an unconstrained string from the Appium response, values such as toString, constructor, or __proto__ return inherited functions or objects instead of falling back to the raw command. That also violates this function's declared string return type at runtime.

Please check Object.hasOwn(APPIUM_COMMAND_SUMMARIES, command) before reading the value, and add regression tests for at least toString and constructor.

env:
GH_TOKEN: ${{ secrets.EXPO_BOT_PAT }}
run: |
if git diff --quiet; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Scope change detection to the generated file

This checks the entire tracked working tree, but only appiumCommands.generated.ts is staged below. If dependency installation modifies another tracked file while the generated file is unchanged, this condition proceeds and git commit fails because nothing was staged.

Please scope the check to the generated file:

git diff --quiet -- packages/build-tools/src/steps/utils/appiumCommands.generated.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no changelog PR that doesn't require a changelog entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants