From 9f6ed48a91d5a0f681d7c3df43da49dc40852f1d Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Mon, 18 Nov 2024 13:11:22 +0000 Subject: [PATCH] test: Navigation Bar (#213) tests: changed test group names to fit with standard group names test: writing tests for navigation bar fix: made NavigationItem visible for testing fix: Changed font size of medium indicator from 12 to 11 fix: hover color on navigation item test: added more tests for navigation bar test: Uncommented text contrast tests fix: set navigation item highlight shape to rectangle test: edited test to pass after merge test: ran test counter fix: indicator semantic labels fix: navigation bar semantic labels chore(automated): Lint commit and format test: navigation item calls onTap when an item is tapped off center chore(automated): Lint commit and format test: hardcoded offset fix: Extra verbose semantic label test: fixed debug fill props avatar --- .../components/notification_list_example.dart | 1 + lib/src/components/avatars/avatar.dart | 12 +- lib/src/components/badges/indicator.dart | 37 +- lib/src/components/components.dart | 2 +- .../navigation bar/navigation_bar.dart | 27 +- test/scripts/output/test_table.md | 11 +- test/src/components/avatar/avatar_test.dart | 8 +- .../indicator_notification_with_value.png | Bin 0 -> 3469 bytes test/src/components/badge/indicator_test.dart | 46 +- .../golden/navigation_bar_action.png | Bin 0 -> 4463 bytes .../golden/navigation_bar_current_index_0.png | Bin 0 -> 4073 bytes .../golden/navigation_bar_current_index_1.png | Bin 0 -> 4094 bytes .../golden/navigation_bar_current_index_2.png | Bin 0 -> 4093 bytes .../golden/navigation_bar_current_index_3.png | Bin 0 -> 4094 bytes .../golden/navigation_bar_default.png | Bin 0 -> 4023 bytes .../golden/navigation_bar_divider.png | Bin 0 -> 4238 bytes .../golden/navigation_bar_divider_at_0.png | Bin 0 -> 4226 bytes .../golden/navigation_bar_divider_at_1.png | Bin 0 -> 4267 bytes .../golden/navigation_bar_divider_at_2.png | Bin 0 -> 4238 bytes .../golden/navigation_bar_divider_at_3.png | Bin 0 -> 4269 bytes .../golden/navigation_bar_shrink_items.png | Bin 0 -> 4023 bytes .../golden/navigation_bar_split.png | Bin 0 -> 4083 bytes .../navigation_bar/navigation_bar_test.dart | 521 ++++++++++++++++++ test/src/components/stepper/stepper_test.dart | 12 +- .../top_app_bar/top_app_bar_test.dart | 14 +- 25 files changed, 642 insertions(+), 49 deletions(-) create mode 100644 test/src/components/badge/golden/indicator_notification_with_value.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_action.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_current_index_0.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_current_index_1.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_current_index_2.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_current_index_3.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_default.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_divider.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_divider_at_0.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_divider_at_1.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_divider_at_2.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_divider_at_3.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_shrink_items.png create mode 100644 test/src/components/navigation_bar/golden/navigation_bar_split.png create mode 100644 test/src/components/navigation_bar/navigation_bar_test.dart diff --git a/example/lib/pages/components/notification_list_example.dart b/example/lib/pages/components/notification_list_example.dart index a13ae1ad..1b203145 100644 --- a/example/lib/pages/components/notification_list_example.dart +++ b/example/lib/pages/components/notification_list_example.dart @@ -86,6 +86,7 @@ class NotificationListItemExample extends StatelessWidget { leading: ZetaNotificationBadge.avatar( avatar: ZetaAvatar.initials( initials: "JS", + semanticUpperBadgeLabel: 'Urgent', lowerBadge: ZetaAvatarBadge.icon( color: ZetaColors().surfacePositive, icon: Icons.check, diff --git a/lib/src/components/avatars/avatar.dart b/lib/src/components/avatars/avatar.dart index 7ca1443f..726c381b 100644 --- a/lib/src/components/avatars/avatar.dart +++ b/lib/src/components/avatars/avatar.dart @@ -53,9 +53,9 @@ class ZetaAvatar extends ZetaStatelessWidget { this.lowerBadge, this.upperBadge, this.borderColor, - this.semanticLabel = 'avatar', - this.semanticUpperBadgeLabel = 'upperBadge', - this.semanticLowerBadgeLabel = 'lowerBadge', + this.semanticLabel, + this.semanticUpperBadgeLabel, + this.semanticLowerBadgeLabel, this.initialTextStyle, this.label, this.labelTextStyle, @@ -149,17 +149,17 @@ class ZetaAvatar extends ZetaStatelessWidget { /// {@template zeta-widget-semantic-label} /// This label is used by accessibility frameworks (e.g. TalkBack on Android) to describe the component. /// {@endtemplate} - final String semanticLabel; + final String? semanticLabel; /// Value passed into wrapping [Semantics] widget for lower badge. /// /// {@macro zeta-widget-semantic-label} - final String semanticLowerBadgeLabel; + final String? semanticLowerBadgeLabel; /// Value passed into wrapping [Semantics] widget for upper badge. /// /// {@macro zeta-widget-semantic-label} - final String semanticUpperBadgeLabel; + final String? semanticUpperBadgeLabel; /// Text style for initials. /// diff --git a/lib/src/components/badges/indicator.dart b/lib/src/components/badges/indicator.dart index abb04172..efbb3d4e 100644 --- a/lib/src/components/badges/indicator.dart +++ b/lib/src/components/badges/indicator.dart @@ -92,6 +92,7 @@ class ZetaIndicator extends ZetaStatelessWidget { int? value, bool? inverse, Key? key, + String? semanticLabel, }) { return ZetaIndicator( key: key ?? this.key, @@ -100,6 +101,7 @@ class ZetaIndicator extends ZetaStatelessWidget { icon: icon ?? this.icon, value: value ?? this.value, inverse: inverse ?? this.inverse, + semanticLabel: semanticLabel ?? this.semanticLabel, ); } @@ -111,18 +113,21 @@ class ZetaIndicator extends ZetaStatelessWidget { final sizePixels = _getSizePixels(size, type, context); return Semantics( - value: semanticLabel ?? value?.toString() ?? '', + label: semanticLabel, + container: true, child: Container( width: sizePixels + Zeta.of(context).spacing.minimum, height: sizePixels + Zeta.of(context).spacing.minimum, - decoration: BoxDecoration( - border: Border.all( - width: ZetaBorders.medium, - color: Zeta.of(context).colors.borderSubtle, - ), - color: (inverse ? foregroundColor : Colors.transparent), - borderRadius: Zeta.of(context).radius.full, - ), + decoration: type == ZetaIndicatorType.icon + ? BoxDecoration( + border: Border.all( + width: ZetaBorders.medium, + color: Zeta.of(context).colors.borderSubtle, + ), + color: (inverse ? foregroundColor : Colors.transparent), + borderRadius: Zeta.of(context).radius.full, + ) + : null, child: Center( child: Container( width: sizePixels, @@ -155,11 +160,15 @@ class ZetaIndicator extends ZetaStatelessWidget { ); case ZetaIndicatorType.notification: return Center( - child: Text( - value.formatMaxChars(), - style: ZetaTextStyles.labelIndicator.copyWith( - color: foregroundColor, - height: size == ZetaWidgetSize.large ? 1 : (12 / 16), + child: ExcludeSemantics( + excluding: semanticLabel != null, + child: Text( + value.formatMaxChars(), + style: ZetaTextStyles.labelIndicator.copyWith( + color: foregroundColor, + fontSize: size == ZetaWidgetSize.large ? 12 : 11, + height: size == ZetaWidgetSize.large ? 1 : (0.5 / 16), + ), ), ), ); diff --git a/lib/src/components/components.dart b/lib/src/components/components.dart index 63bae3a4..af26f8cd 100644 --- a/lib/src/components/components.dart +++ b/lib/src/components/components.dart @@ -32,7 +32,7 @@ export 'in_page_banner/in_page_banner.dart'; export 'list_item/dropdown_list_item.dart'; export 'list_item/list_item.dart'; export 'list_item/notification_list_item.dart'; -export 'navigation bar/navigation_bar.dart'; +export 'navigation bar/navigation_bar.dart' hide NavigationItem; export 'navigation_rail/navigation_rail.dart'; export 'pagination/pagination.dart'; export 'password/password_input.dart'; diff --git a/lib/src/components/navigation bar/navigation_bar.dart b/lib/src/components/navigation bar/navigation_bar.dart index 5d530614..e8f16866 100644 --- a/lib/src/components/navigation bar/navigation_bar.dart +++ b/lib/src/components/navigation bar/navigation_bar.dart @@ -131,7 +131,7 @@ class ZetaNavigationBar extends ZetaStatelessWidget { final index = items.indexOf(navItem); return Expanded( flex: !shrinkItems ? 1 : 0, - child: _NavigationItem( + child: NavigationItem( selected: index == currentIndex, item: navItem, onTap: () => onTap?.call(index), @@ -186,7 +186,7 @@ class ZetaNavigationBar extends ZetaStatelessWidget { } return Container( - padding: EdgeInsets.symmetric(horizontal: Zeta.of(context).spacing.medium), + padding: EdgeInsets.symmetric(horizontal: Zeta.of(context).spacing.large), decoration: BoxDecoration( color: colors.surfacePrimary, border: Border(top: BorderSide(color: colors.borderSubtle)), @@ -210,19 +210,32 @@ class ZetaNavigationBar extends ZetaStatelessWidget { } } -class _NavigationItem extends ZetaStatelessWidget { - const _NavigationItem({ +/// A single item in a [ZetaNavigationBar]. +@visibleForTesting +@protected +class NavigationItem extends ZetaStatelessWidget { + /// Creates a new [NavigationItem]. + const NavigationItem({ + super.key, required this.selected, required this.item, required this.onTap, required this.context, }); + /// Whether the item is selected. final bool selected; + + /// The item to display. final ZetaNavigationBarItem item; + + /// Called when the item is tapped. final VoidCallback onTap; + + /// The build context of the [ZetaNavigationBar]. final BuildContext context; + /// The badge to show on the navigation item. Widget get badge { final ZetaColors colors = Zeta.of(context).colors; return Positioned( @@ -230,7 +243,7 @@ class _NavigationItem extends ZetaStatelessWidget { right: Zeta.of(context).spacing.minimum, child: DecoratedBox( decoration: BoxDecoration( - color: colors.surfacePrimary, + color: colors.surfaceDefault, borderRadius: Zeta.of(context).radius.full, ), child: item.badge?.copyWith( @@ -240,6 +253,7 @@ class _NavigationItem extends ZetaStatelessWidget { ? ZetaWidgetSize.medium : null, type: ZetaIndicatorType.notification, + semanticLabel: item.badge?.semanticLabel, ), ), ); @@ -255,9 +269,10 @@ class _NavigationItem extends ZetaStatelessWidget { child: InkResponse( borderRadius: context.rounded ? Zeta.of(context).radius.rounded : Zeta.of(context).radius.none, onTap: onTap, + hoverColor: colors.surfaceHover, + highlightShape: BoxShape.rectangle, child: Semantics( button: true, - explicitChildNodes: true, label: item.label, child: Container( padding: EdgeInsets.only( diff --git a/test/scripts/output/test_table.md b/test/scripts/output/test_table.md index 307b28b7..4c298e67 100644 --- a/test/scripts/output/test_table.md +++ b/test/scripts/output/test_table.md @@ -1,6 +1,7 @@ | Component | Accessibility | Content | Dimensions | Styling | Interaction | Golden | Performance | Unorganised | Total Tests | | -------------- | ------------- | ------- | ---------- | ------- | ----------- | ------ | ----------- | ----------- | ----------- | | Accordion | 0 | 2 | 0 | 1 | 2 | 0 | 0 | 0 | 5 | +| Avatar Rail | 1 | 2 | 2 | 1 | 2 | 1 | 1 | 0 | 10 | | Avatar | 1 | 3 | 6 | 5 | 0 | 6 | 0 | 0 | 21 | | Indicator | 0 | 7 | 0 | 0 | 0 | 5 | 0 | 0 | 12 | | Label | 0 | 8 | 0 | 0 | 0 | 7 | 0 | 0 | 15 | @@ -11,17 +12,19 @@ | Button | 0 | 10 | 0 | 2 | 1 | 8 | 0 | 0 | 21 | | Chat Item | 0 | 10 | 0 | 0 | 0 | 8 | 0 | 0 | 18 | | Checkbox | 0 | 3 | 0 | 0 | 3 | 3 | 0 | 0 | 9 | -| Chip | 0 | 1 | 0 | 0 | 5 | 0 | 0 | 0 | 6 | +| Chip | 0 | 2 | 0 | 0 | 5 | 0 | 0 | 0 | 7 | +| Status Chip | 1 | 3 | 1 | 3 | 1 | 3 | 0 | 0 | 12 | | Comms Button | 2 | 7 | 0 | 0 | 0 | 1 | 0 | 0 | 10 | | Dialpad | 0 | 2 | 0 | 1 | 2 | 3 | 0 | 0 | 8 | | Fab | 0 | 6 | 0 | 1 | 1 | 6 | 0 | 0 | 14 | | Icon | 1 | 4 | 1 | 6 | 0 | 0 | 0 | 0 | 12 | | In Page Banner | 0 | 4 | 0 | 4 | 2 | 4 | 0 | 0 | 14 | +| Navigation Bar | 5 | 7 | 3 | 4 | 2 | 6 | 0 | 0 | 27 | | Password Input | 0 | 4 | 0 | 0 | 0 | 2 | 0 | 0 | 6 | | Search Bar | 0 | 5 | 0 | 0 | 5 | 5 | 0 | 0 | 15 | | Slider | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | -| Stepper | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 30 | 30 | +| Stepper | 4 | 8 | 4 | 6 | 2 | 6 | 0 | 0 | 30 | | Stepper Input | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 2 | | Tooltip | 0 | 3 | 1 | 3 | 0 | 4 | 0 | 0 | 11 | -| Top App Bar | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 25 | 25 | -| Total Tests | 7 | 95 | 11 | 26 | 23 | 71 | 0 | 55 | 288 | +| Top App Bar | 2 | 6 | 1 | 1 | 6 | 9 | 0 | 0 | 25 | +| Total Tests | 20 | 122 | 22 | 41 | 36 | 96 | 1 | 0 | 338 | diff --git a/test/src/components/avatar/avatar_test.dart b/test/src/components/avatar/avatar_test.dart index 528d5aca..25459f90 100644 --- a/test/src/components/avatar/avatar_test.dart +++ b/test/src/components/avatar/avatar_test.dart @@ -17,7 +17,7 @@ void main() { }); group('Accessibility Tests', () { - testWidgets('ZetaAvatar meets accessibility requirements', (WidgetTester tester) async { + testWidgets('ZetaAvatar meets accessibility requirements', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( const TestApp( @@ -52,9 +52,9 @@ void main() { 'lowerBadge': 'null', 'backgroundColor': 'null', 'statusColor': 'null', - 'semanticUpperBadgeValue': '"upperBadge"', - 'semanticValue': '"avatar"', - 'semanticLowerBadgeValue': '"lowerBadge"', + 'semanticUpperBadgeValue': 'null', + 'semanticValue': 'null', + 'semanticLowerBadgeValue': 'null', 'initialTextStyle': 'null', }; debugFillPropertiesTest( diff --git a/test/src/components/badge/golden/indicator_notification_with_value.png b/test/src/components/badge/golden/indicator_notification_with_value.png new file mode 100644 index 0000000000000000000000000000000000000000..edd743bff2bd5ed3167069eb8694ad4586cc0a83 GIT binary patch literal 3469 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sL9;Z#WAE}&f7a1vqTa_8ZO!^c4vHHbP;qpcuA?XKOr;u`RSuhO$o^_ zl_PF&hGlVF%S`G?b6HzvsIe>hiSV`JQxD^Iyk$4uTv%20s}^Lw+5fMM3=9YUC%-P| z@1JKQef)fUkG_6#B1^MYY_B-s?*;GZ`XJ=qoGqHDm{J~#U9};8slz#5#R?olR zzgGHs_iYA-2Ge3ShqTQ%gS;=B%zf?)G;dZ^4Rg_#A1^O?uRg=Xz;H&F>B*&Ycb85N zo5{++Fe94f#Po}2GsU~otiRG2+|`}FvzL@@@2ggilo`S;)I@7;1r z2WZ-y`yYUY%rw5=P*e5y*?MmE-|WvT`572C96QHy;?23YhQ60A?%e&I`k|ma-{-Q) zwso<(@0l4GuAP_}z5(dTbCbdPB^iN+q_A)>Fia3s0NUu*0F)aQ91W1s#4wr>MoWg# tQgO6K7_ALQYs1mnaI`iYX0_o=`9>Z;>+98Pp8}(n!PC{xWt~$(69CsK_A~$h literal 0 HcmV?d00001 diff --git a/test/src/components/badge/indicator_test.dart b/test/src/components/badge/indicator_test.dart index 43c683a8..ba73efff 100644 --- a/test/src/components/badge/indicator_test.dart +++ b/test/src/components/badge/indicator_test.dart @@ -13,7 +13,46 @@ void main() { goldenFileComparator = TolerantComparator(goldenFile.uri); }); - group('Accessibility Tests', () {}); + group('Accessibility Tests', () { + for (int i = 0; i < 10; i++) { + testWidgets('medium notification value $i meets accessibility standards', (tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await tester.pumpWidget( + TestApp( + home: ZetaIndicator( + size: ZetaWidgetSize.medium, + value: i, + ), + ), + ); + + await expectLater(tester, meetsGuideline(androidTapTargetGuideline)); + await expectLater(tester, meetsGuideline(iOSTapTargetGuideline)); + await expectLater(tester, meetsGuideline(labeledTapTargetGuideline)); + await expectLater(tester, meetsGuideline(textContrastGuideline)); + + handle.dispose(); + }); + + testWidgets('default notification value $i meets accessibility standards', (tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await tester.pumpWidget( + TestApp( + home: ZetaIndicator( + value: i, + ), + ), + ); + + await expectLater(tester, meetsGuideline(androidTapTargetGuideline)); + await expectLater(tester, meetsGuideline(iOSTapTargetGuideline)); + await expectLater(tester, meetsGuideline(labeledTapTargetGuideline)); + await expectLater(tester, meetsGuideline(textContrastGuideline)); + + handle.dispose(); + }); + } + }); group('Content Tests', () { final debugFillProperties = { 'color': 'MaterialColor(primary value: Color(0xffff9800))', @@ -170,6 +209,11 @@ void main() { 'indicator_icon_values', ); goldenTest(goldenFile, const ZetaIndicator.notification(), 'indicator_notification_default'); + goldenTest( + goldenFile, + const ZetaIndicator.notification(value: 3, size: ZetaWidgetSize.medium), + 'indicator_notification_with_value', + ); goldenTest( goldenFile, const ZetaIndicator.notification( diff --git a/test/src/components/navigation_bar/golden/navigation_bar_action.png b/test/src/components/navigation_bar/golden/navigation_bar_action.png new file mode 100644 index 0000000000000000000000000000000000000000..4639ee1c9b7a790b5443852bfdcc824eb2818c1b GIT binary patch literal 4463 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 literal 0 HcmV?d00001 diff --git a/test/src/components/navigation_bar/golden/navigation_bar_current_index_1.png b/test/src/components/navigation_bar/golden/navigation_bar_current_index_1.png new file mode 100644 index 0000000000000000000000000000000000000000..7eb765806e83f97ae627a1565dd8af3ac1420f53 GIT binary patch literal 4094 zcmeH}drVVz6vt0_NC%+^>bl88qS<1GgCQG;2t@`%NbDA(8B7FM*@cCNl>!Pal(B4} zEQ5q8T+3r-VaR|MR;9y2OS2JWTv`&PJOs*$Qh5}V3kBNJ?&31GKUucFmfnBv@1Feb z@B2IFe9pxEQ$7_Z9gHpZ zcCY{Z;E`Z}0vg!ZvZo&FIvRnr`;IeUj6Aa_Pv4u;VEg z(w4ePz?!(0xEM$PhplV??l)_f zA>Q2_B7UbqVN7k8*YH|ea6dnxL~_YrsYF=#mm{J!$%6w{(CU!;Qhv{&%D%wdS*$wG zuy671!ZX&I(26E*e}@z2ipk}BGM65rxpNQE5nP|Bc{h?~;-{8L*LWSwd)iF_x4_$I zKN-3gUJvDeTy{)9+&(mc&xkcbCoZ8BVw9Z`Wn*4~+A0(c$}n`NHM8AIQv1};hXnU? zud6zzu2$PcSF+690NR@A5@GxHu|6?hQgmm(N2ghWqH*lm$VVZFwlNt&rk7{933oaG zCTnc&Up;d9*(8RIaTE>h`B?v|TMde~ur&P9cz|d0T5$)xbI4!)T-xbN^^UJ{Xi%gX zs;TrkwBr-+{O_s!)0Ku-2CwCD9Qd}xs+U;V@@@I%!6dt+h)#iEM(^SS;7s~)zqce@ zqUqL2Q?f6%PzOkGiwMa@-~AKD@qL7@t8`;=)X{vE0-@oB%_Y{n06C+rinXc|YtPGR z%ta#nfvveepRREP@OJU^Vx*@p*3)(yahCM5V&xup-GHKjnJFx#ZlP-yCqXy4d@%Fr zq>0FENMG4lprA94k-%2>n&a@%UGK{`M?#zW72a26Ab$-5>O5D88y?oEg8193y6wV9I zp#X(ny#Urjc9(u^>FN2PV5|A6o+-iNGP(8qn0cf>-rUqn*#z9#lfWGzaIXvsCg^Sr z8YXR#PTmRNdEl?pUf{od<7S}@l~$V8mN@H8i7K65Tvm{YAO$A1fJhOQX6{(m?NW&s zxKpl)hF`~4+JZz~wW%tFDJy5eAm=?wFn6DI_4C6kD&-l5stduK6v^_##yL|!f&L4g zW}+-3jU7A`vdUdGk7Fx~dght^ucb3sI>Uc899mfV cKe1%AdxJxL%!`)&Ld?Ms6+sW@hn*|>9TCy7Z2$lO literal 0 HcmV?d00001 diff --git a/test/src/components/navigation_bar/golden/navigation_bar_current_index_2.png b/test/src/components/navigation_bar/golden/navigation_bar_current_index_2.png new file mode 100644 index 0000000000000000000000000000000000000000..382e1066a5047855e0ad87deb7a3d7f92430e017 GIT binary patch literal 4093 zcmeH~YfO_@7{^b!j1D4brZC2J!N@Xha}6LO7ZJvo0XHNAqzn{NqEHJIxz{q80zxdt z5Acp&FvQ^o6wFI0*Fq-N_jS-=zWAd3QssBTEp2NVJtd2?jb!F+xvy}Qc9$f#fx%GuvPh0cJ`)9)y z&gM~xCal9mrpbfS6FHe#mmh@Kn0nm2@`X_39CJA`-MhW^yNVj-(bm$VhriJd9+Tbc zl_L-;L3VG|m##mN8WdH}j$3`Xqj5Mn>farh* z_INi+bm<*qth$yKgg}4=f;^weNfH&gHN$@-7 zW5L{uj8ogw9aHm&qDKx}(XpKZb;1PxHL+VOyB31{ukH+FG#A;Ir;C<#sBF|qfJ)u6 z9Y64Jr0Z`p)3!$axg!PjOWXb1y{745r}9x6R;_k|(Loc>o|lNlV#PSxdxeSv1O9JU zAIW;TAcUZ|J+i}ZpNPh#gsHc^}zt)CY& zkU$j?3nRUVO`dsn`p?L+$GnAXN<()vpCaT9tkb<`aPf!KN^IS}Mh=95NN&o>1+0Z;|vJ<2Rs zIW#*ZtQ%n=KR3Cq@LbtCj(2Oo+EVYU=M`O<&pcpC3eD1CuHOa5&d9%DJAY^{S9JHU z!>6v^PpJ{)UjOOLFp0GCCkI-mI5SYNHy6-?%$Gh8DVCF!?2rerkDJputiZ0I~yiePg~GRo&{&R;|AWSg_G zD_n-OOSMki(V==Y59a6AN}8a1fk#@*=EVDG0YnKGJuG%s8DW5@{Kh?N~Fd4E?vJA0DR+j$0h+R2?FpqjQ<4Fl$|L&g$W!tDJ}-&TK`dOFzlpNM22&)>7=7({zzxDF=s+VC?F9m^@0nmD&5mx=2*J`tYNq; zU*6!;=DJ3!G{H!f32Y=1X|~_*<-Kbe^t`!21nD{5?ajz+H%BKQm8YUj<$-*(;m}ZI z;vLk`vZlBx|G;F;!th2+lPpjd*6xWoiwa1jnwb~Hb^O*R`*a9`h)HNqof4q0!t)XF zv~8+iELPg337Ph?atk?(L@GDwINiwrQ#5IVlGdmXafq54LkPiiNfA@awo3^*Nrf_v zSa6*nKXAyg_Hp|;zL(s~8pSh|M()a~4KN<(k#UAiFZKFtfrtRY^I+ISRK=<-Z5>S~ zbJA}S+Hg>bFF7`l6x(QTh+^5xw&gpGwHb@6H@-Dqe#^MM=)rNVvA}YvS~;ar)g0b3 z+~)A@rfdL6{w(^8sI=5|8BLth>0AR;z05Xb!BRf*&`~vRY?_$Gfd*gFoAzqzKKXVX zrKPxsT-|ssi_RN(j2@ZoT9u&PTrHIpDSAV_I}S22tBvB-AXGi>Zf-y_75)|fR6oQN zNXfSwwZXg*8-nOzh5T|vb ze8ci8ZU5W`ll3U4>}uTd)&YT_fdC+vtSUJ+rZlBoF-Z%)8%AxbHUo4LX>VZqGvEM1 z1Mc6WMa+zx2&a0CuXV~)$RacNXvCs}R;&p-<>3L4>WK#^IkM$)%Mi^E^BDJi&)dTj z;L*Rxe|zMID>sKzHFE>kqSO&7i(`64HQ9dOnlk%9SHM=g{+gFNjkbq+ zb!e_&T)VZ})Wt-*QJ&bvK`m)f&gV*{C7i>~b1lie)rueqbc$jqLp?Y3kUx6!x!%QD zc)e_!P8E2pd&Z$cK7A9)${>K~T|xj@hkF;_e<;NdvXse_uQ7^iUiNu@T+mf4Hhc25 z59S)s|B3Xn literal 0 HcmV?d00001 diff --git a/test/src/components/navigation_bar/golden/navigation_bar_default.png b/test/src/components/navigation_bar/golden/navigation_bar_default.png new file mode 100644 index 0000000000000000000000000000000000000000..3f278f56d10a238ca4ce3e9671aaf7ab38c6f0e7 GIT binary patch literal 4023 zcmeH}ZA?>F7{^ZwtQCgJ6p(?GVKSGvU?y|Ix=Lj*WJ7R_ArJ+|$YoC6q}YxXXos5! z3}@mpDAZP579r3Y?9jBl2JC=wOEreKQm7!bU`wHt7TVr&cln|pr)Hm)o-Zfo$$6ff z=YM|xlT&drHp<=gO;-Sbd-U;$cmSLN0Kg{^U&A7G^s;`k{LxhYK#s+;2*y*!a5qO0Jn;8Nw;x&&E_`ode=ehMeI$wCLo z{jFVmhEUoWD%O^)i!bLLteyl9%ge#?J0{EU4jj?R-I~cTg&?DzDSd)6(z8 z!NX00y&(xazRtum}0&!Y4r+Xi%$@97YPm4rJP zs`HITJjnl(c-6CDW_G^FI6I%rwC5Qsg83!#HchH^NvC2g>$r-#N4M_Y@xg%*h4a7( zU28u-WJN*f-smY_YEI*DIB}(j-ic!TyIGS3sk@j*KdAQ=I-RFk0&Hj}GS?r594{q& zY7UFy*t@MAF6SaYT3xAuAjrPR-@Cyv-Qr*8a6YTqywIn{12*H0fCCv!CKH16#Vc-v zQuQ!F4#Tj1dfL6-4S?xEbV?aGy}ZYuOjFg`?e>Z8LQ7A#n6)@ z9(jkM9TiNieOU-VAU-patCW;@RY`Re}x7#j`AS6wUPN(x&R$+N3Q4fh?#02*lKy#p`;qdTn?x zxww(Bjt4yijdNxs1?{aeB5ntV5faIO18iUEHX;C5Jpurr{?(m673j}ID*F6!+pF#J z&mold>jc_7_ZA^B$V# zynm~SPuKte9~>TlOy_5v{aes$XuhCm{9`OL>f)}K>qXSn-p(8k-b(%PB~xEruosus zv6K3$R63+{NcUg8a1NFnEIC-hKE4hkIE>&h!vD<(sEfYOyI!ek{sv$pIx;pw7@l7C E540edXaE2J literal 0 HcmV?d00001 diff --git a/test/src/components/navigation_bar/golden/navigation_bar_divider.png b/test/src/components/navigation_bar/golden/navigation_bar_divider.png new file mode 100644 index 0000000000000000000000000000000000000000..006174fc114b83c30a0406776265a20426b0d73a GIT binary patch literal 4238 zcmeH~ZA?>F7{^a5C}>o)^KCX1HYa978f2p&U{M^5sBAGfVHB!@#RLVVVueEKm@Ssl7HCVMlzVqEi!Rw0HT&4}<>ox+Jh|um zpZ_m;&Z#dV!WJ)lcOd{^arkH3cLOlb4FG(U(|jy)IX(X<_Q5fChiwCV2~mSh9GKg} zBb~6pa!M!!z{M|o`_{!gVSh`D=lu2GDjgXs=9RXMJ`Ua-8XDt$At_^T8Yeoz zKkoXj;f#@qK)JQa2(45sk+BCQ>K++iY$bC!8Ib87l%~6g zPPf5TrHWBQW)k?Qi$2ob}6@1l{&qb zO2&^3(;9N)CsPzO^J+j0!9P3kw6E`SY3cE5$j?;KMasmIMs>R8gG`)9_bqLXpc%R` z;tl-1v8`3a51lfwEo9_yJxyY4o}TsO)49iGbgC)Ii=LIHwzW~V{I(?QaZTKnJFzmM z@|U`vq)4IGx{~N9%q|*9j~yJUQ8_$Y=RbDL6@at8xKw=O_y@S zv=>ExD(81t+kkew3n>LgWyi*IT)6?VQ93k;KdIi3tVYt zryI*Z51KtQ2u0iqBjvE>Jh7)3_tE&Hd&RtL2L(Rj6*H$*sr59o3m}rAY)y}U4kHQs zEzP_E5Pkl&3-16xhm#8cZtuTJef=N?rm}9TM<5l4ETyJCH_y2ih6Bwep8|!kipV~8z?lm2dbwiF61-ZD8=DTDL^Zhe&*l2%-?p7Ch148(jT9Um)7 z$(`vC$y|F9=LiTiWuGmWA!UyJ@Pzxl#n?Q&hC4O&AX&5K>P5m^AN-X%GXCJDq9Su| z6rKJ;oEMj`%Xb7I!Qo{ELh}FsYjF7g21|=XBGDcxwp_ma|I_vLD`4OG)*i4+XP53} xi(xl|-3)d!V7;~-1Um?J5bPkl$+N&ls$H=|Tlp)Y5$l6N_@@!u`P=s8{|%4n5EB3Z literal 0 HcmV?d00001 diff --git a/test/src/components/navigation_bar/golden/navigation_bar_divider_at_0.png b/test/src/components/navigation_bar/golden/navigation_bar_divider_at_0.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ab82e03a6d9ba83802885c8f26fd66c6124ead GIT binary patch literal 4226 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 literal 0 HcmV?d00001 diff --git a/test/src/components/navigation_bar/golden/navigation_bar_divider_at_2.png b/test/src/components/navigation_bar/golden/navigation_bar_divider_at_2.png new file mode 100644 index 0000000000000000000000000000000000000000..006174fc114b83c30a0406776265a20426b0d73a GIT binary patch literal 4238 zcmeH~ZA?>F7{^a5C}>o)^KCX1HYa978f2p&U{M^5sBAGfVHB!@#RLVVVueEKm@Ssl7HCVMlzVqEi!Rw0HT&4}<>ox+Jh|um zpZ_m;&Z#dV!WJ)lcOd{^arkH3cLOlb4FG(U(|jy)IX(X<_Q5fChiwCV2~mSh9GKg} zBb~6pa!M!!z{M|o`_{!gVSh`D=lu2GDjgXs=9RXMJ`Ua-8XDt$At_^T8Yeoz zKkoXj;f#@qK)JQa2(45sk+BCQ>K++iY$bC!8Ib87l%~6g zPPf5TrHWBQW)k?Qi$2ob}6@1l{&qb zO2&^3(;9N)CsPzO^J+j0!9P3kw6E`SY3cE5$j?;KMasmIMs>R8gG`)9_bqLXpc%R` z;tl-1v8`3a51lfwEo9_yJxyY4o}TsO)49iGbgC)Ii=LIHwzW~V{I(?QaZTKnJFzmM z@|U`vq)4IGx{~N9%q|*9j~yJUQ8_$Y=RbDL6@at8xKw=O_y@S zv=>ExD(81t+kkew3n>LgWyi*IT)6?VQ93k;KdIi3tVYt zryI*Z51KtQ2u0iqBjvE>Jh7)3_tE&Hd&RtL2L(Rj6*H$*sr59o3m}rAY)y}U4kHQs zEzP_E5Pkl&3-16xhm#8cZtuTJef=N?rm}9TM<5l4ETyJCH_y2ih6Bwep8|!kipV~8z?lm2dbwiF61-ZD8=DTDL^Zhe&*l2%-?p7Ch148(jT9Um)7 z$(`vC$y|F9=LiTiWuGmWA!UyJ@Pzxl#n?Q&hC4O&AX&5K>P5m^AN-X%GXCJDq9Su| z6rKJ;oEMj`%Xb7I!Qo{ELh}FsYjF7g21|=XBGDcxwp_ma|I_vLD`4OG)*i4+XP53} xi(xl|-3)d!V7;~-1Um?J5bPkl$+N&ls$H=|Tlp)Y5$l6N_@@!u`P=s8{|%4n5EB3Z literal 0 HcmV?d00001 diff --git a/test/src/components/navigation_bar/golden/navigation_bar_divider_at_3.png b/test/src/components/navigation_bar/golden/navigation_bar_divider_at_3.png new file mode 100644 index 0000000000000000000000000000000000000000..af3022af4d315f4d484ee13d67abdf02a38730c1 GIT binary patch literal 4269 zcmeHJZA?>F7(T6R1tZ{Oh(ZI1PWQn_W`|G#tH@+51JsEqB2`D)IFLd+DW!!HSt6u5 zzs8`H(&(ZrLyFRfl$O?5su)VEA%aDq6(|)cy~;<(^#uz{>QbgdO{e>ZXQL|1uaDcU~C>*|@E=`xC*Dt-oK}z}wvwA9C3j9eKFo zVK_Q`B;@?al?{z$0qcYz**@-{`nS9LW}azu~O9Soa90qd_X8r~_h_dS{vqr3@X-JW>VQwNwNWnq#1Tu^oW2&c16HWSkd- zb_1ZxeI)?FBGCjYFD+dtBUG~sPI`HH8TBvoS96pmvq@z(TTB8Ot&rXt6&C`)nAD@B z=Z|iKbk1^>F+a_e7xo;xStBB+^l%+9y;=Z{^tyHVhgEl5n*|+s%;_LiresSDypT#O za-N=XatO7`$_}jrmT8@LiK=Ht=Px9ZIa(YgXU=Pr&v^o{7S*zgBAYWynbr=i?N#>- zhHcp-FPKsWIi7|>GNzh8ByjZ7vvFu}XQRh?o&G{%&>_Z@!rNhuUC@`~FqoOs?AgVy zrWkX#qDVInsGt(lpedJ`+O=o;QZy4a1@Ml#<1mnY)~blCgg4c$93Lz}|Vkf3wfv_pIf8wXrYn%;ls7@x1pB ziyR6z*FeQrhZDt>mr&PrRgIA58Kx1IEh{6g3eKTUcRt{9#TFe!C^ecjtYQ)g;g~Xz z38EBLjTl-{(TU!lK>iBrnql7(NDDa!nh^rU3pNe8VD3d|#NjM!WHppot0gcU$&=WF zQN?F}KHPsh+COjB|8cvJf=X1J&H6K=e=e-83XeKit~~ZNN2#LH>7-ZdEV?t70noc6 zFj^!coak00=f?&Fax@J=VXKKAGg(dnd(y^%ZKGT+ zo?ggqZDj=j&=$AQO+Txy$45$Ho{H?FsXdK;?5)jkPje}?Z&Kq_NNocFBI%@1JUTXv ztUR`h^bsgaerYyFW`wS$L2<_MrrQxcl4>1K5n(qhy$!P;83SvOjnet}NV-E;=>foC zcwO0bEuu!6TtqNxh&A+Kt3X^hRjwV#P+2T}b+I?278{@%CWPO#4M7!#M~Rc_3GAaw z_xNqQ&rYPsk4B*Y*!?OlIkU4(SuA_Si>O_1w(4FX0U^1}kAJ1?c4 zD0XWz{AW%m;tgu=PLMB^I@AU{;}|8S{>jkn=KzaKS#sYQ@Mihf)?5ER#TZ`Tku(Cs zTE!T7(6B!X)-FOkF4r%Mb=(j~bWF-?Qr~mS=8na_pU^ zzCZ161Jm`P4-xf0A}gb&mkxI)zxsvoM)bZP1TtR)qU4joPII9D!4 Q+GYTfzD-FG#veKL55qYVWB>pF literal 0 HcmV?d00001 diff --git a/test/src/components/navigation_bar/golden/navigation_bar_shrink_items.png b/test/src/components/navigation_bar/golden/navigation_bar_shrink_items.png new file mode 100644 index 0000000000000000000000000000000000000000..3f278f56d10a238ca4ce3e9671aaf7ab38c6f0e7 GIT binary patch literal 4023 zcmeH}ZA?>F7{^ZwtQCgJ6p(?GVKSGvU?y|Ix=Lj*WJ7R_ArJ+|$YoC6q}YxXXos5! z3}@mpDAZP579r3Y?9jBl2JC=wOEreKQm7!bU`wHt7TVr&cln|pr)Hm)o-Zfo$$6ff z=YM|xlT&drHp<=gO;-Sbd-U;$cmSLN0Kg{^U&A7G^s;`k{LxhYK#s+;2*y*!a5qO0Jn;8Nw;x&&E_`ode=ehMeI$wCLo z{jFVmhEUoWD%O^)i!bLLteyl9%ge#?J0{EU4jj?R-I~cTg&?DzDSd)6(z8 z!NX00y&(xazRtum}0&!Y4r+Xi%$@97YPm4rJP zs`HITJjnl(c-6CDW_G^FI6I%rwC5Qsg83!#HchH^NvC2g>$r-#N4M_Y@xg%*h4a7( zU28u-WJN*f-smY_YEI*DIB}(j-ic!TyIGS3sk@j*KdAQ=I-RFk0&Hj}GS?r594{q& zY7UFy*t@MAF6SaYT3xAuAjrPR-@Cyv-Qr*8a6YTqywIn{12*H0fCCv!CKH16#Vc-v zQuQ!F4#Tj1dfL6-4S?xEbV?aGy}ZYuOjFg`?e>Z8LQ7A#n6)@ z9(jkM9TiNieOU-VAU-patCW;@RY`Re}x7#j`AS6wUPN(x&R$+N3Q4fh?#02*lKy#p`;qdTn?x zxww(Bjt4yijdNxs1?{aeB5ntV5faIO18iUEHX;C5Jpurr{?(m673j}ID*F6!+pF#J z&mold>jc_7_ZA^B$V# zynm~SPuKte9~>TlOy_5v{aes$XuhCm{9`OL>f)}K>qXSn-p(8k-b(%PB~xEruosus zv6K3$R63+{NcUg8a1NFnEIC-hKE4hkIE>&h!vD<(sEfYOyI!ek{sv$pIx;pw7@l7C E540edXaE2J literal 0 HcmV?d00001 diff --git a/test/src/components/navigation_bar/golden/navigation_bar_split.png b/test/src/components/navigation_bar/golden/navigation_bar_split.png new file mode 100644 index 0000000000000000000000000000000000000000..04c0963812bb4e73f86ce19b499531dfbd40d88a GIT binary patch literal 4083 zcmeHKTToL+82*#cf;xZ<43wh4jLh^Qmmi477G9%F~M zJiF7E0355sLl4Jf-_(ppT&hWRFPutsu>AVO$LHhZ;<)p%&s>g%DnC7UE1IfxafvCv z%?mj@7h>ZSy7Tar$y>+W#+#i&|9o&P_UP53kuOgAZo3`)_^U7XA%=wOmmhY2^q0Q0 zk0CXh6uCK6c>zX|Z<5PuO#K-+2qL+EF1ipO6c6)61b`&VPH%ui$6kiG&v~M+E${Tt zWtfe!9f)~zN9Ce zjB^9Y9CqX`+FlP2p*=v|x4`AjGYvflR)$at1vSo|Kv%1m21br_)ClB1b06M0m3nrb zminTvOrkBGp-^nGI9r0u~p zFXJS?PB7pR=~*@WN&O%|=UlUvI2%SczmQovzsXIs{N|sZ?|P*qKG$#$=}%Z{nKdHx z%~5rmiH+tw=$7S8FOX%LMok80Og?CCaKvmUvXrPTB)VhTQnbC9VjAfPQ#}}0peB3B9-B9nq zd5D!h??8k@y^CpBFg=Q{lkqpF#NrLPXx%H%C>Ebux-Jk@w{*2GP+|i-^BTKzLws7r z+3iiCP;zGzd^2VrHNkMwo`(kmP=*1{3PdmZo2IW7Qir;4jDC}4GE^=GW>N?xZiWHsU8YY$$&*+}E z^jLBq7tf$^%qr)eQgQe9DI_Q)PhDGk!^1)q2)<*}bSKihW=S)S|~9Z!%L#}?mp zRUt_!ffpUwlFNOz0E|Gws#j)arb4yOVJWt^2jIqQ{)1z2z#$Ggy;QYAXm;jrcx9(+ z3nsgGq7qJ5JgKwsA=)~_XFjsA0qC{c3E++1W%yOb<~rjFGA9vnl26;@r;*~Mn z39k{1FA$_HSJY2X9Zic=T#VdSdZ65($XahROR_|`l!VPaqV>EBn2K47PHY4xDsgbU zE;M&(eK|-u7Nm*@B;W?!OZ*4to e as ZetaIcon).toList(); + for (final icon in icons) { + expect(icon.icon, ZetaIcons.star); + } + }); + testWidgets('passes the correct badge content for each item', (WidgetTester tester) async { + const items1 = [ + ZetaNavigationBarItem(icon: ZetaIcons.star, label: 'Label0', badge: ZetaIndicator(value: 0)), + ZetaNavigationBarItem(icon: ZetaIcons.star, label: 'Label1', badge: ZetaIndicator(value: 1)), + ZetaNavigationBarItem(icon: ZetaIcons.star, label: 'Label2', badge: ZetaIndicator(value: 2)), + ZetaNavigationBarItem(icon: ZetaIcons.star, label: 'Label3', badge: ZetaIndicator(value: 3)), + ]; + await tester.pumpWidget( + TestApp( + home: ZetaNavigationBar( + items: items1, + ), + ), + ); + + final badgeFinder = find.byType(ZetaIndicator); + final badges = tester.widgetList(badgeFinder).map((e) => e as ZetaIndicator).toList(); + for (int i = 0; i < badges.length; i++) { + expect(badges[i].value, i); + } + }); + + testWidgets('renders the action', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaNavigationBar.action( + items: items, + action: action, + ), + ), + ); + + final buttonFinder = find.byType(ZetaButton); + expect(buttonFinder, findsOneWidget); + }); + + testWidgets('renders the divider', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaNavigationBar.divided( + items: items, + dividerIndex: 2, + ), + ), + ); + final context = getBuildContext(tester, ZetaNavigationBar); + + final dividerFinder = find.byWidgetPredicate( + (widget) => widget is Container && widget.color == Zeta.of(context).colors.borderSubtle, + ); + + expect(dividerFinder, findsOneWidget); + }); + }); + + group('Dimensions Tests', () { + testWidgets('renders the correct padding', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaNavigationBar( + items: items, + ), + ), + ); + final context = getBuildContext(tester, ZetaNavigationBar); + + final containerFinder = find.byType(Container).first; + + expect( + tester.widget(containerFinder).padding, + EdgeInsets.symmetric(horizontal: Zeta.of(context).spacing.large), + ); + }); + + testWidgets('items render the correct padding', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaNavigationBar( + items: items, + ), + ), + ); + final context = getBuildContext(tester, ZetaNavigationBar); + + final itemFinder = find.byType(NavigationItem); + if (itemFinder.evaluate().isEmpty) { + fail('No items found'); + } else if (itemFinder.evaluate().length != items.length) { + fail('Incorrect number of items found'); + } else { + for (int i = 0; i < items.length; i++) { + expect( + tester + .widget(find.descendant(of: itemFinder.at(i), matching: find.byType(Container)).first) + .padding, + EdgeInsets.only( + left: Zeta.of(context).spacing.small, + right: Zeta.of(context).spacing.small, + bottom: Zeta.of(context).spacing.small, + ), + ); + } + } + }); + + testWidgets('the divider is the correct size', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaNavigationBar.divided( + items: items, + dividerIndex: 2, + ), + ), + ); + final context = getBuildContext(tester, ZetaNavigationBar); + + final dividerFinder = find.byWidgetPredicate( + (widget) => widget is Container && widget.color == Zeta.of(context).colors.borderSubtle, + ); + + expect(dividerFinder, findsOneWidget); + + expect(dividerFinder.evaluate().first.size?.height, Zeta.of(context).spacing.xl_7); + expect(dividerFinder.evaluate().first.size?.width, 1); + }); + }); + + group('Styling Tests', () { + testWidgets('renders the correct background color', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaNavigationBar( + items: items, + ), + ), + ); + final context = getBuildContext(tester, ZetaNavigationBar); + + final containerFinder = find.byType(Container).first; + + final containerWidget = tester.widget(containerFinder); + final boxDecoration = containerWidget.decoration! as BoxDecoration; + + expect(boxDecoration.color, Zeta.of(context).colors.surfacePrimary); + }); + + testWidgets('items are the correct color', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaNavigationBar( + items: items, + ), + ), + ); + final context = getBuildContext(tester, ZetaNavigationBar); + + final itemFinder = find.byType(NavigationItem); + final icon = + tester.widget(find.descendant(of: itemFinder.first, matching: find.byType(ZetaIcon)).first); + final label = tester.widget(find.descendant(of: itemFinder.first, matching: find.text('Label0'))); + + expect(icon.color, Zeta.of(context).colors.textSubtle); + expect(label.style, Theme.of(context).textTheme.labelSmall?.copyWith(color: Zeta.of(context).colors.textSubtle)); + }); + + testWidgets('selected item is the correct color', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaNavigationBar( + items: items, + currentIndex: 0, + ), + ), + ); + final context = getBuildContext(tester, ZetaNavigationBar); + + final itemFinder = find.byType(NavigationItem); + final icon = + tester.widget(find.descendant(of: itemFinder.first, matching: find.byType(ZetaIcon)).first); + final label = tester.widget(find.descendant(of: itemFinder.first, matching: find.text('Label0'))); + + expect(icon.color, Zeta.of(context).colors.primary); + expect(label.style, Theme.of(context).textTheme.labelSmall?.copyWith(color: Zeta.of(context).colors.primary)); + }); + + testWidgets('hover background color is correct', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaNavigationBar( + items: items, + currentIndex: 0, + ), + ), + ); + final context = getBuildContext(tester, ZetaNavigationBar); + + final itemFinder = find.byType(NavigationItem).first; + + final gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(location: tester.getCenter(itemFinder)); + addTearDown(gesture.removePointer); + + await tester.pumpAndSettle(); + + final inkResponse = + tester.widget(find.descendant(of: itemFinder, matching: find.byType(InkResponse)).first); + + expect(inkResponse.hoverColor, Zeta.of(context).colors.surfaceHover); + }); + }); + + group('Interaction Tests', () { + testWidgets('calls onTap when an item is tapped', (WidgetTester tester) async { + var tappedIndex = -1; + await tester.pumpWidget( + TestApp( + home: ZetaNavigationBar( + items: items, + onTap: (index) => tappedIndex = index, + ), + ), + ); + + final itemFinder = find.byType(NavigationItem).first; + await tester.tap(itemFinder); + + expect(tappedIndex, 0); + + final lastItemFinder = find.byType(NavigationItem).last; + await tester.tap(lastItemFinder); + + expect(tappedIndex, 3); + }); + + testWidgets('calls onTap when an item is tapped off center', (WidgetTester tester) async { + var tappedIndex = -1; + await tester.pumpWidget( + TestApp( + home: ZetaNavigationBar( + items: items, + onTap: (index) => tappedIndex = index, + ), + ), + ); + + final itemFinder = find.byType(NavigationItem).first; + + await tester.tapAt(tester.getCenter(itemFinder) + const Offset(80, 0)); + expect(tappedIndex, 0); + + final lastItemFinder = find.byType(NavigationItem).last; + + await tester.tapAt(tester.getCenter(lastItemFinder) + const Offset(-80, 0)); + expect(tappedIndex, 3); + }); + + testWidgets('updates the selected item when an item is tapped', (WidgetTester tester) async { + var selectedIndex = -1; + await tester.pumpWidget( + StatefulBuilder( + builder: (context, setState) { + return TestApp( + home: ZetaNavigationBar( + items: items, + currentIndex: selectedIndex, + onTap: (val) => setState(() { + selectedIndex = val; + }), + ), + ); + }, + ), + ); + + final itemFinder = find.byType(NavigationItem).first; + await tester.tap(itemFinder); + expect(selectedIndex, 0); + + final lastItemFinder = find.byType(NavigationItem).last; + await tester.tap(lastItemFinder); + expect(selectedIndex, 3); + }); + }); + + group('Golden Tests', () { + goldenTest( + goldenFile, + ZetaNavigationBar(items: items), + 'navigation_bar_default', + ); + goldenTest( + goldenFile, + ZetaNavigationBar( + items: items, + shrinkItems: true, + ), + 'navigation_bar_shrink_items', + ); + for (int i = 0; i < items.length; i++) { + goldenTest( + goldenFile, + ZetaNavigationBar( + items: items, + currentIndex: i, + ), + 'navigation_bar_current_index_$i', + ); + + goldenTest( + goldenFile, + ZetaNavigationBar.divided( + items: items, + dividerIndex: i, + ), + 'navigation_bar_divider_at_$i', + ); + } + goldenTest( + goldenFile, + const ZetaNavigationBar.action( + items: items, + action: ZetaButton(label: 'Button'), + ), + 'navigation_bar_action', + ); + goldenTest( + goldenFile, + const ZetaNavigationBar.split( + items: items, + ), + 'navigation_bar_split', + ); + }); + + group('Performance Tests', () {}); +} diff --git a/test/src/components/stepper/stepper_test.dart b/test/src/components/stepper/stepper_test.dart index 8dd9a0bb..53d4734e 100644 --- a/test/src/components/stepper/stepper_test.dart +++ b/test/src/components/stepper/stepper_test.dart @@ -15,7 +15,7 @@ void main() { goldenFileComparator = TolerantComparator(goldenFile.uri); }); - group('ZetaStepper Accessibility Tests', () { + group('Accessibility Tests', () { testWidgets('Horizontal stepper meets accessibility requirements', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( @@ -91,7 +91,7 @@ void main() { }); }); - group('ZetaStepper Content Tests', () { + group('Content Tests', () { testWidgets('Horizontal stepper renders the correct steps', (WidgetTester tester) async { await tester.pumpWidget( TestApp( @@ -202,7 +202,7 @@ void main() { ); }); - group('ZetaStepper Dimensions Tests', () { + group('Dimensions Tests', () { testWidgets('StepIcon horiztonal has the correct size', (WidgetTester tester) async { await tester.pumpWidget( const TestApp( @@ -275,7 +275,7 @@ void main() { }); }); - group('ZetaStepper Styling Tests', () { + group('Styling Tests', () { testWidgets( 'StepIcon has the correct colour when enabled', (WidgetTester tester) async { @@ -401,7 +401,7 @@ void main() { ); }); - group('ZetaStepper Interaction Tests', () { + group('Interaction Tests', () { testWidgets('Horizontal stepper calls onStepTapped when a step is tapped', (WidgetTester tester) async { int tappedStep = -1; await tester.pumpWidget( @@ -448,7 +448,7 @@ void main() { }); }); - group('ZetaStepper Golden Tests', () { + group('Golden Tests', () { goldenTest( goldenFile, const ZetaStepper( diff --git a/test/src/components/top_app_bar/top_app_bar_test.dart b/test/src/components/top_app_bar/top_app_bar_test.dart index 8ae60e83..921ab1cb 100644 --- a/test/src/components/top_app_bar/top_app_bar_test.dart +++ b/test/src/components/top_app_bar/top_app_bar_test.dart @@ -14,7 +14,7 @@ void main() { goldenFileComparator = TolerantComparator(goldenFile.uri); }); - group('ZetaTopAppBar Accessibility Tests', () { + group('Accessibility Tests', () { testWidgets('ZetaTopAppBar meets accessibility requirements', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( @@ -87,7 +87,7 @@ void main() { }); }); - group('ZetaTopAppBar Content Tests', () { + group('Content Tests', () { final debugFillProperties = { 'titleTextStyle': 'null', 'onSearch': 'null', @@ -216,7 +216,7 @@ void main() { }); }); - group('ZetaTopAppBar Dimensions Tests', () { + group('Dimensions Tests', () { testWidgets('ZetaTopAppBar has the correct height', (WidgetTester tester) async { await tester.pumpWidget( const TestApp( @@ -231,7 +231,7 @@ void main() { }); }); - group('ZetaTopAppBar Styling Tests', () { + group('Styling Tests', () { testWidgets('ZetaTopAppBar has the correct background color', (WidgetTester tester) async { await tester.pumpWidget( const TestApp( @@ -247,7 +247,7 @@ void main() { }); }); - group('ZetaTopAppBar Interaction Tests', () { + group('Interaction Tests', () { late ZetaSearchController searchController; const searchLabel = 'Search'; const clearLabel = 'Clear'; @@ -430,7 +430,7 @@ void main() { }); }); - group('ZetaTopAppBar Golden Tests', () { + group('Golden Tests', () { goldenTest( goldenFile, const ZetaTopAppBar( @@ -553,5 +553,5 @@ void main() { ); }); - group('ZetaTopAppBar Performance Tests', () {}); + group('Performance Tests', () {}); }