com um clique
e2e
Drive the app in an Android emulator for manual E2E testing
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Menu
Drive the app in an Android emulator for manual E2E testing
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Baseado na classificação ocupacional SOC
De-identify NTUT HTML/XML snapshots before promoting them from tmp/html_snapshot into test fixtures. Use when working with browser snapshots, raw campus-system captures, HTML parser samples, fixture promotion, or requests to remove personal data while preserving DOM structure for tests.
Finish the migration commit on a Renovate-generated Flutter version PR — patch, minor, or major bumps. Use whenever a `renovate/flutter-*` PR appears, when the user says things like "do the flutter upgrade" or "bump flutter X to Y", or any time `mise.toml`'s `flutter = "X.Y.Z"` value changes.
| name | e2e |
| description | Drive the app in an Android emulator for manual E2E testing |
flutter run (in the background) so logs are inspectable and the running build reflects the current codeadb devices once to see what's attached:
adb and the helper scripts below work as-is.adb -s <serial> ... for raw adb, and prefix ANDROID_SERIAL=<serial> on the same command line for the helper scripts (e.g. ANDROID_SERIAL=emulator-5554 .agents/skills/e2e/scripts/screencap.sh). export ANDROID_SERIAL=<serial> only works within a single persistent shell session — it does not carry across separate shell tool calls, so don't use it as your default targeting strategy.adb … examples below assume the single-device case; in the multi-device case, add -s <serial> (or the equivalent helper-script prefix) to each one.adb shell wm sizeIf a flow needs login, look for project-local Dart test credentials in test/test_config.json under the current workspace. Do not copy credentials into this skill or into permanent notes.
Use the helper script — it captures, resizes, and writes the PNG in one call:
.agents/skills/e2e/scripts/screencap.sh # writes /tmp/screen.png
.agents/skills/e2e/scripts/screencap.sh /tmp/x.png # custom output path
Then read the PNG with the agent's image tool.
The UI accessibility tree gives exact pixel bounds and content-desc for every element. This is the primary way to find tap coordinates — do not guess from screenshots.
.agents/skills/e2e/scripts/uidump.sh # writes /tmp/ui.xml, prints element summary
.agents/skills/e2e/scripts/uidump.sh /tmp/x.xml # custom output path
The script streams uiautomator dump /dev/tty over adb exec-out and writes the full XML to the output path. It then prints a compact one-line-per-element summary of the nodes worth tapping or reading: any node with non-empty text or content-desc, or with any of clickable / scrollable / selected / focused / password set to true. Each line shows bounds, the short class name, text="..." and/or desc="..." when present, and the list of true states. Long values are whitespace-collapsed and truncated to ~120 chars.
Use the printed summary as the primary input for choosing tap coordinates — it covers the vast majority of cases. Fall back to searching /tmp/ui.xml directly (e.g. with grep) when you need parent/child structure or attributes the summary doesn't include (resource-id, package, checked, enabled, etc.).
Flutter widgets with Semantics labels appear as content-desc. The bounds format is [left,top][right,bottom] in pixels. Tap the center: x = (left+right)/2, y = (top+bottom)/2.
adb shell input tap <x> <y>adb shell input swipe <x1> <y1> <x2> <y2> <duration_ms>adb shell input keyevent <code> (BACK=4, HOME=3, ENTER=66)adb shell input text '<text>'input text runs through the device's shell, so any $, #, backticks, or unquoted whitespace in the value get expanded or word-split there — even after the host shell has already substituted $PASSWORD. Failures look like a too-short string in the field.
# Wrong — host expands $PASSWORD, then the device shell re-parses the value
adb shell input text "$PASSWORD"
# Right — single-quote on the device side so the device shell treats the value literally
# (assumes the value contains no single quotes; if it does, replace each ' with '\'' or use a different quoting strategy)
adb shell "input text '$PASSWORD'"
Tapping a non-empty field places the cursor somewhere inside the existing text — usually but not always at the end. The next input text appends rather than replaces. Move the cursor explicitly, backspace, then re-dump the XML to confirm the field is empty before typing:
adb shell input tap <x> <y>
adb shell input keyevent 123 # 123 = MOVE_END (cursor to end of field)
for i in $(seq 1 50); do adb shell input keyevent 67; done # 67 = DEL/backspace
.agents/skills/e2e/scripts/uidump.sh # verify the field is empty
Password fields hide their contents, so the only way to verify what was typed is the bullet count — count it against the expected length before submitting.
keyevent 4 (BACK) is context-dependent: it dismisses the keyboard if open, then closes the topmost picker/dialog, then pops the current route, then exits to the launcher from the root route. Don't chain BACK presses blindly — verify the resulting state (UI dump or screenshot) between presses.Swiping on a TabBarView body switches tabs. Swiping on a SingleChildScrollView/HorizontalScrollView scrolls it. The uiautomator dump shows scrollable="true" on scrollable containers — use those bounds for swipe coordinates.
uiautomator to get element boundscontent-desc or position in the treeBounds in the XML are exact pixels — that's where tap coordinates come from. Re-dump after each navigation since bounds change between screens.
XML vs screenshot for verification. Default to a fresh UI dump — it's cheaper and exact. Reach for a screenshot only when the change is genuinely visual:
Don't be misled by unrelated dialogs. In debug builds, async failures (e.g. Google Fonts network errors) can pop a Flutter error dialog on top of an otherwise-successful flow — the underlying state may have updated correctly behind it. Read the dialog text before treating it as a failure of the current step.
Stop when the goal is achieved. Don't keep tapping to tidy up UI state (closing menus, navigating back to a home screen) unless the user asked for that — extra taps risk breaking the verified end state.