Skip to content

feat(snap): surface render FlutterErrors + prefer navigate adapter#21

Merged
anilcancakir merged 4 commits into
masterfrom
feat/snap-surface-render-errors
Jun 22, 2026
Merged

feat(snap): surface render FlutterErrors + prefer navigate adapter#21
anilcancakir merged 4 commits into
masterfrom
feat/snap-surface-render-errors

Conversation

@anilcancakir

Copy link
Copy Markdown
Contributor

Two dusk observability fixes that together make silently-broken UI impossible to miss during agent-driven E2E. Both surfaced while debugging a Magic/wind app where a button rendered but ignored taps (a flex-1/Expanded placed under Semantics/WAnchor threw a build-time ParentDataWidget error, invisible in the snapshot).

Changes

  1. ext.dusk.snap surfaces captured render FlutterErrors (feat(snap))

    • A widget that throws at build time can render partially yet stay invisible in the semantics tree; an action against it silently no-ops with zero signal. The snapshot payload now adds renderErrors: {count, recent: [{type, message}], hint} (from the existing FlutterError.onError buffer, omitted when clean), and dusk:snap prints a ⚠ N render error(s) banner. Full detail stays in ext.dusk.exceptions.
    • Test: test/src/extensions/ext_snapshot_render_errors_test.dart.
  2. ext.dusk.navigate prefers the consumer navigate adapter over Navigator.pushNamed (fix(navigate))

    • On a Router-only stack (go_router / auto_route) Navigator.onGenerateRoute is null, so Navigator.pushNamed raised an asynchronous "no corresponding route" FlutterError on every navigate — uncatchable by the handler's try/catch, and now doubly visible as a false positive via the new renderErrors block. Navigate now dispatches through DuskPlugin.navigateAdapter first (e.g. MagicRoute.to) when registered, the correct path for these apps, and only falls back to Navigator.pushNamed when no adapter is wired.

Verification

  • flutter test --exclude-tags=integration: 789 green; navigation tests 32 green.
  • dart analyze clean, dart format no diff. CHANGELOG updated under [Unreleased].

Author: Anılcan Çakır anilcan.cakir@gmail.com

A widget that throws at build time (a ParentDataWidget misuse such as a wind
flex-1 / Expanded placed under a Semantics/WAnchor instead of directly inside a
Flex, or an overflow) can render partially yet stay invisible in the semantics
tree. An action against it then silently no-ops with zero signal to the agent
driving dusk, which makes the root cause effectively unobservable from snapshots
alone.

ext.dusk.snap now adds a `renderErrors` block (count + recent {type, message} +
hint) drawn from the existing FlutterError.onError capture buffer, omitted when
clean. dusk:snap prints a `⚠ N render error(s)` banner above the tree. The full
messages + stacks remain available via dusk:exceptions. This makes a silently
broken screen impossible to miss without remembering to query exceptions
separately. Adds ext_snapshot_render_errors_test; updates the dusk_snap MCP
descriptor + CHANGELOG.
…shNamed

On a Router-only stack (go_router / auto_route) Navigator.onGenerateRoute is
null, so ext.dusk.navigate's Navigator.pushNamed raised an asynchronous "no
corresponding route" FlutterError on every navigate. The failure is async, so
the handler's try/catch could not suppress it; it landed in the FlutterError
buffer and now shows up as a false positive in the new renderErrors snapshot
block.

ext.dusk.navigate now dispatches through DuskPlugin.navigateAdapter first when
registered (MagicRoute.to for Magic apps) -- the correct path for Router-based
apps -- and only falls back to Navigator.pushNamed when no adapter is wired.
Eliminates the spurious capture. Navigation tests green (32); full suite 789.
Copilot AI review requested due to automatic review settings June 20, 2026 01:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds stronger observability around silently broken UIs by (1) embedding captured non-fatal Flutter render/build errors into ext.dusk.snap responses and (2) routing ext.dusk.navigate through a consumer-provided navigate adapter first (with Navigator/SystemNavigator fallback), reducing spurious async FlutterErrors on Router-based apps.

Changes:

  • Extend ext.dusk.snap payload with optional renderErrors summary (count + recent messages + hint) sourced from the existing FlutterError capture buffer; add a new widget test covering the behavior.
  • Update ext.dusk.navigate to prefer DuskPlugin.navigateAdapter before Navigator.pushNamed, keeping the existing SystemNavigator.routeInformationUpdated fallback.
  • Update CLI/MCP docs and changelog to describe the new snapshot error surfacing and the navigation dispatch change.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/src/extensions/ext_snapshot_render_errors_test.dart New widget test verifying duskSnapBuild() omits/includes the renderErrors block as appropriate.
lib/src/extensions/ext_snapshot.dart Adds renderErrors block to snapshot payload when captured FlutterErrors exist.
lib/src/extensions/ext_navigation.dart Prefers DuskPlugin.navigateAdapter before Navigator.pushNamed, retaining route-information broadcast fallback.
lib/src/dusk_artisan_provider.dart Updates MCP tool description to mention the new renderErrors block.
lib/src/commands/dusk_snap_command.dart Prints a banner + recent render/build errors before emitting the snapshot.
CHANGELOG.md Documents both behavior changes under [Unreleased].

Comment thread lib/src/commands/dusk_snap_command.dart
Comment thread lib/src/extensions/ext_snapshot.dart Outdated
Comment thread lib/src/extensions/ext_snapshot.dart Outdated
@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.90909% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
lib/src/extensions/ext_navigation.dart 71.42% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

…ion)

- Document the new snap renderErrors block + CLI banner in doc/commands/dusk-snap.md,
  doc/mcp/tool-reference.md, and llms.txt (Golden Rule 1 doc-sync gate).
- Replace the em-dashes introduced by this PR (CHANGELOG + 3 ext_navigation.dart
  comments) with comma/semicolon/period per the no-dash rule.
- Add a navigate regression test that proves adapter-is-preferred-over-Navigator:
  with both a registered adapter and a pushable named route present, the adapter
  receives the route and the Navigator target never mounts. Guards the reorder.
Address PR #21 review (Copilot):
- The render-error banner now goes to stderr via ctx.output.error, so stdout
  stays the pure snapshot payload (the repo's documented stdout=payload /
  stderr=diagnostics convention). warning() also writes stdout in this Output
  impl, so error() is the correct stderr channel.
- The renderErrors hint and the dusk:snap banner now cite both dusk:exceptions
  (CLI) and dusk_exceptions (MCP) so non-CLI consumers are not confused.
- Add a command-level test for the renderErrors branch (snapshot stays clean,
  banner surfaced). Docs (dusk-snap.md) + CHANGELOG updated for the stderr move.
@anilcancakir anilcancakir merged commit 8a1a1af into master Jun 22, 2026
2 checks passed
@anilcancakir anilcancakir deleted the feat/snap-surface-render-errors branch June 22, 2026 10:41
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