Final 1.0.0 QA: pixel + performance regression suites + live dusk validation#96
Conversation
24 tests asserting documented Tailwind v3 px/hex output via getRect/getSize + renderObject decoration color (no golden files). Confirms wind renders every characterized spacing/sizing/radius/ring/border/typography/color token exactly; F05/F11 divergences asserted at documented values.
…uite 24 in-process interaction tests: tap callbacks, hover via mouse gesture, focus/ disabled, breakpoint flips via tester.view, animate-* via 16ms pump (no pumpAndSettle), WPopover/WSelect overlay open/close.
Asserts the cache hit path is >=3x faster than cold (ratio gate, ~26x actual), plus report-only PERF: lines for cache totals and large-tree pump time.
CHANGELOG Quality entry for the new pixel/interaction/performance regression suites + live dusk validation (no regressions found). Document the disabled- WAnchor-shadowed-by-nested-WDiv hover edge in tailwind-divergence.md.
Both reviewers flagged the weak isNot(72.0) assertion; assert text-7xl falls back to the baseline default size (proving the F11 no-op) instead of only ruling out Tailwind's 72px.
📝 WalkthroughWalkthroughPR adds documentation updates and eight new test files covering interaction behavior (hover, focus, disabled states, animations, overlays, callbacks), responsive breakpoints, parser performance benchmarks, and pixel-exact rendering validation for colors, spacing, typography, and borders. ChangesWind UI Test Coverage Expansion
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
Adds final 1.0.0 QA regression coverage to the Wind package by introducing new pixel-precision, interaction, and performance test suites, plus documentation/sign-off updates, without modifying lib/ runtime code.
Changes:
- Added new
test/pixel/coverage validating exact rendered geometry, typography, and colors via render-tree inspection (no golden files). - Added new
test/interaction/coverage for taps, hover/focus/disabled state behavior, responsive breakpoints, and overlay open/close flows. - Added new
test/performance/coverage gating parser cache warm-vs-cold speedup ratio and reporting large-tree pump timings; updated docs (tailwind divergence + changelog).
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/pixel/typography_pixel_test.dart | New pixel tests for rendered font sizes and text color. |
| test/pixel/spacing_sizing_pixel_test.dart | New pixel tests for padding/margin/gap and sizing/max-width behavior. |
| test/pixel/radius_ring_border_pixel_test.dart | New pixel tests for border radius, border widths, and ring spread widths. |
| test/pixel/color_pixel_test.dart | New pixel tests for background colors including dark-mode resolution. |
| test/performance/parser_perf_test.dart | New perf gate for parser cache speedup ratio + report-only large-tree pump timing. |
| test/interaction/tap_callbacks_test.dart | New interaction tests covering tap callbacks across common widgets. |
| test/interaction/responsive_breakpoints_test.dart | New interaction tests for breakpoint gating and active breakpoint resolution. |
| test/interaction/hover_focus_disabled_test.dart | New interaction tests for hover/focus/disabled and manual active: state resolution. |
| test/interaction/animation_overlay_test.dart | New interaction tests for animation wrappers and overlay widgets (popover/select). |
| skills/wind-ui/references/tailwind-divergence.md | Documents an additional state-shadowing edge case (disabled ancestor vs inner hover). |
| CHANGELOG.md | Adds a 1.0.0 QA gate entry describing the new regression suites and validation. |
| /// Reads the `BoxDecoration` from the first `RenderDecoratedBox` the WDiv emits. | ||
| BoxDecoration _decorationOf(WidgetTester tester) { | ||
| final render = tester.renderObject<RenderDecoratedBox>( | ||
| find.byType(DecoratedBox).first, | ||
| ); | ||
| return render.decoration as BoxDecoration; |
| /// Reads the `BoxDecoration` from the first `RenderDecoratedBox` the WDiv emits. | ||
| BoxDecoration _decorationOf(WidgetTester tester) { | ||
| final render = tester.renderObject<RenderDecoratedBox>( | ||
| find.byType(DecoratedBox).first, | ||
| ); | ||
| return render.decoration as BoxDecoration; |
| // w-1/2 wraps in FractionallySizedBox(widthFactor: 0.5). | ||
| expect(find.byType(FractionallySizedBox), findsOneWidget); | ||
| final fsb = tester.widget<FractionallySizedBox>( | ||
| find.byType(FractionallySizedBox), | ||
| ); |
| // 2. Cold bench: clear the cache before each iteration. | ||
| final coldWatch = Stopwatch()..start(); | ||
| for (var i = 0; i < _kBenchIterations; i++) { | ||
| WindParser.clearCache(); | ||
| WindParser.parse(_kBenchClassName, capturedCtx); | ||
| } | ||
| coldWatch.stop(); | ||
| final coldTotal = coldWatch.elapsedMicroseconds; | ||
|
|
||
| // 3. Verify the cache received exactly one entry after the last miss. | ||
| expect(WindParser.cacheSize, 1, | ||
| reason: 'cold bench must leave one cache entry after the last miss'); | ||
|
|
||
| // 4. Warm bench: prime the cache once, then hit it [_kBenchIterations] | ||
| // times without clearing between iterations. | ||
| WindParser.clearCache(); | ||
| WindParser.parse(_kBenchClassName, capturedCtx); // prime | ||
| final cacheSizeAfterPrime = WindParser.cacheSize; | ||
|
|
||
| final warmWatch = Stopwatch()..start(); | ||
| for (var i = 0; i < _kBenchIterations; i++) { | ||
| WindParser.parse(_kBenchClassName, capturedCtx); | ||
| } | ||
| warmWatch.stop(); | ||
| final warmTotal = warmWatch.elapsedMicroseconds; |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
test/interaction/animation_overlay_test.dart (1)
7-14: ⚡ Quick winConsider extracting
wrapWithThemeto a shared test helper.The
wrapWithThemehelper is duplicated identically across four test files (animation_overlay_test.dart,hover_focus_disabled_test.dart,responsive_breakpoints_test.dart, andtap_callbacks_test.dart). Extracting it to a shared location (e.g.,test/helpers/test_helpers.dart) would eliminate duplication and provide a single source of truth for test widget wrapping.♻️ Proposed refactor
Create
test/helpers/test_helpers.dart:import 'package:flutter/material.dart'; import 'package:fluttersdk_wind/fluttersdk_wind.dart'; /// Wraps [child] in a MaterialApp + WindTheme + Scaffold so className-styled /// widgets resolve their styling context. Widget wrapWithTheme(Widget child) { return MaterialApp( home: WindTheme( data: WindThemeData(), child: Scaffold(body: child), ), ); }Then update all four test files to import and use it:
import '../helpers/test_helpers.dart';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/interaction/animation_overlay_test.dart` around lines 7 - 14, The helper function wrapWithTheme is duplicated across four tests (animation_overlay_test.dart, hover_focus_disabled_test.dart, responsive_breakpoints_test.dart, tap_callbacks_test.dart); extract it into a shared test helper file (e.g., test/helpers/test_helpers.dart) that exports the same MaterialApp+WindTheme+Scaffold wrapper, then replace the local definitions in each of the four test files with a single import (e.g., import '../helpers/test_helpers.dart';) so all tests call the centralized wrapWithTheme function.test/performance/parser_perf_test.dart (1)
63-64: 💤 Low valueComment and assertion mismatch on "at least 3x" speedup.
The comments state the cache "must deliver at least a 3x speedup" (lines 63-64, 122), which implies
ratio >= 3. However, the assertion at line 125 useslessThan(coldTotal ~/ 3), which enforceswarmTotal < coldTotal / 3, i.e.,ratio > 3(strictly greater than 3x).For exactly 3× speedup, the test would fail. Consider either:
- Update comments to say "more than 3x" to match the code, OR
- Change the assertion to
lessThanOrEqualTo(coldTotal ~/ 3)to accept exactly 3xIn practice, the measured ~26× speedup makes this mismatch inconsequential, but aligning the comment with the code improves clarity.
Proposed fix: align comment with code
- // 7. Ratio gate: warm must be at least 3x faster than cold. + // 7. Ratio gate: warm must be more than 3x faster than cold.Or align code with comment:
expect( warmTotal, - lessThan(coldTotal ~/ 3), + lessThanOrEqualTo(coldTotal ~/ 3), reason: 'warm cache must be at least 3x faster than cold 'Also applies to: 122-128
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/performance/parser_perf_test.dart` around lines 63 - 64, The comment asserts the cache "must deliver at least a 3x speedup" but the test uses a strict check warmTotal < coldTotal / 3 (lessThan(coldTotal ~/ 3)), which rejects exactly 3×; update the assertion that references warmTotal and coldTotal (the lessThan(coldTotal ~/ 3) check) to use lessThanOrEqualTo(coldTotal ~/ 3) so it accepts exactly 3×, and make the same change for the duplicate assertion block around the other reference (lines mentioned in the review).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@test/interaction/animation_overlay_test.dart`:
- Around line 7-14: The helper function wrapWithTheme is duplicated across four
tests (animation_overlay_test.dart, hover_focus_disabled_test.dart,
responsive_breakpoints_test.dart, tap_callbacks_test.dart); extract it into a
shared test helper file (e.g., test/helpers/test_helpers.dart) that exports the
same MaterialApp+WindTheme+Scaffold wrapper, then replace the local definitions
in each of the four test files with a single import (e.g., import
'../helpers/test_helpers.dart';) so all tests call the centralized wrapWithTheme
function.
In `@test/performance/parser_perf_test.dart`:
- Around line 63-64: The comment asserts the cache "must deliver at least a 3x
speedup" but the test uses a strict check warmTotal < coldTotal / 3
(lessThan(coldTotal ~/ 3)), which rejects exactly 3×; update the assertion that
references warmTotal and coldTotal (the lessThan(coldTotal ~/ 3) check) to use
lessThanOrEqualTo(coldTotal ~/ 3) so it accepts exactly 3×, and make the same
change for the duplicate assertion block around the other reference (lines
mentioned in the review).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e893af2b-3e63-4d45-99af-8146e97a9c71
📒 Files selected for processing (11)
CHANGELOG.mdskills/wind-ui/references/tailwind-divergence.mdtest/interaction/animation_overlay_test.darttest/interaction/hover_focus_disabled_test.darttest/interaction/responsive_breakpoints_test.darttest/interaction/tap_callbacks_test.darttest/performance/parser_perf_test.darttest/pixel/color_pixel_test.darttest/pixel/radius_ring_border_pixel_test.darttest/pixel/spacing_sizing_pixel_test.darttest/pixel/typography_pixel_test.dart
| BoxDecoration _decorationOf(WidgetTester tester) { | ||
| final render = tester.renderObject<RenderDecoratedBox>( | ||
| find.byType(DecoratedBox).first, | ||
| ); | ||
| return render.decoration as BoxDecoration; |
| /// Reads the `BoxDecoration` from the first `RenderDecoratedBox` the WDiv emits. | ||
| BoxDecoration _decorationOf(WidgetTester tester) { | ||
| final render = tester.renderObject<RenderDecoratedBox>( | ||
| find.byType(DecoratedBox).first, | ||
| ); | ||
| return render.decoration as BoxDecoration; |
… in cold/warm bench Address Copilot review on PR #96: - _decorationOf in color/radius_ring_border pixel tests now scopes find.byType(DecoratedBox) to descendants of the WDiv under test, so an app-shell DecoratedBox can never shadow the asserted decoration. - w-1/2 FractionallySizedBox assertion scoped to the half-keyed WDiv. - parser_perf cold bench moves clearCache() outside the measured window and times only parse() per iteration; warm bench mirrors the per-iteration start/stop so the speedup ratio compares like with like.
Final 1.0.0 QA gate — pixel-perfect + performance regression suites + live dusk validation
Last gate before tagging 1.0.0. Stood up a fresh consumer app driven by
fluttersdk_dusk, exercised every feature, and added the two coverage dimensions the prior QA pass lacked. Zero behavioral regressions found → nolib/changes.New permanent suites (raise the suite 1253 → 1303)
test/pixel/(24 tests) — px-exact geometry (getRect/getSize/getTopLeft, epsilon 0.5) + exact color viarenderObjectdecoration. Asserts documented Tailwind v3 values:p-4=16,px-3=12,w-10=40,max-w-prose=512,rounded-lg=8,text-4xl=36,bg-blue-500=#3B82F6, dark-mode resolution, etc. No golden files.test/interaction/(24 tests) — tap callbacks, hover (mouse gesture), focus/disabled, responsive breakpoints (tester.view), animations (16ms pump, neverpumpAndSettle), WPopover/WSelect overlay open/close.test/performance/— parser cache hit/miss speedup ratio gate (≥3×; ~26× measured) + report-only large-tree pump timing. Ratio not absolute-µs (CI-safe).Live dusk validation
Fresh
/tmp/wind_final_qaapp booted on Chrome; all 11 gallery routes navigated + screenshotted;dusk:snap --includeEnrichersconfirmed the livewind:enricher 7-field block (className/breakpoint/brightness/platform/states/bgColor); manual visual compare of card/alerts/badges/buttons/form/widget-roster — all faithful. (Evidence + report under the gitignored plan dir.)Docs
### Qualityentry for the final-QA sign-off.WAnchordoesn't suppresshover:on a nestedWDiv's ownhover:— WDiv auto-wraps in a non-disabled anchor) intailwind-divergence.md. P3 follow-up, not a 1.0.0 blocker.Verification
dart analyze0 issues ·dart formatno diff ·flutter test1303 pass · coverage 90.4% ·flutter pub publish --dry-run0 warnings · pana 160/160 (is:wasm-ready)./ac:plan→ executed via/ac:execute(complex, auto); deep-review + oracle both APPROVED.Verdict: production-ready for 1.0.0.
Summary by CodeRabbit
Tests
Documentation