feat(snap): surface render FlutterErrors + prefer navigate adapter#21
Merged
Conversation
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.
There was a problem hiding this comment.
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.snappayload with optionalrenderErrorssummary (count + recent messages + hint) sourced from the existing FlutterError capture buffer; add a new widget test covering the behavior. - Update
ext.dusk.navigateto preferDuskPlugin.navigateAdapterbeforeNavigator.pushNamed, keeping the existingSystemNavigator.routeInformationUpdatedfallback. - 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]. |
Codecov Report❌ Patch coverage is
📢 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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/Expandedplaced underSemantics/WAnchorthrew a build-timeParentDataWidgeterror, invisible in the snapshot).Changes
ext.dusk.snapsurfaces captured render FlutterErrors (feat(snap))renderErrors: {count, recent: [{type, message}], hint}(from the existingFlutterError.onErrorbuffer, omitted when clean), anddusk:snapprints a⚠ N render error(s)banner. Full detail stays inext.dusk.exceptions.test/src/extensions/ext_snapshot_render_errors_test.dart.ext.dusk.navigateprefers the consumer navigate adapter overNavigator.pushNamed(fix(navigate))Navigator.onGenerateRouteis null, soNavigator.pushNamedraised an asynchronous "no corresponding route"FlutterErroron every navigate — uncatchable by the handler's try/catch, and now doubly visible as a false positive via the newrenderErrorsblock. Navigate now dispatches throughDuskPlugin.navigateAdapterfirst (e.g.MagicRoute.to) when registered, the correct path for these apps, and only falls back toNavigator.pushNamedwhen no adapter is wired.Verification
flutter test --exclude-tags=integration: 789 green; navigation tests 32 green.dart analyzeclean,dart formatno diff. CHANGELOG updated under[Unreleased].Author: Anılcan Çakır anilcan.cakir@gmail.com