From 0e2d8be214c499cb547fb49da3791a606ec839b7 Mon Sep 17 00:00:00 2001 From: Luke Walton Date: Mon, 24 Jun 2024 11:01:27 +0100 Subject: [PATCH] chore: organise existing tests (#108) test: Organise tests folder, and increase code coverage and add goldens for existing tests ci: add coverage to pr action --- .github/workflows/code-quality.yml | 9 +- .../lib/pages/components/button_example.dart | 22 +- example/test/badge_test.dart | 24 -- example/test/button_test.dart | 36 --- example/test/checkbox_test.dart | 74 ----- example/test/color_test.dart | 61 ---- example/test/dialpad_test.dart | 116 ------- example/test/fab_test.dart | 46 --- example/test/in_page_banner_test.dart | 88 ------ example/test/password_input_test.dart | 60 ---- example/test/priority_pill_test.dart | 19 -- example/test/status_label_test.dart | 54 ---- example/test/tag_test.dart | 40 --- example/test/test_components.dart | 60 ---- example/test/typography_test.dart | 66 ---- lib/src/components/badges/indicator.dart | 23 +- lib/src/components/badges/status_label.dart | 2 +- lib/src/components/buttons/button.dart | 15 +- lib/src/components/checkbox/checkbox.dart | 52 ++-- lib/src/components/dial_pad/dial_pad.dart | 8 +- lib/src/components/fabs/fab.dart | 69 ++--- .../in_page_banner/in_page_banner.dart | 10 +- .../components/password/password_input.dart | 8 +- .../src/components/badge/golden/badge.png | Bin 3651 -> 3646 bytes .../components/badge/golden/badge_dark.png | Bin 0 -> 3653 bytes .../components/badge/golden/badge_default.png | Bin 3658 -> 3610 bytes .../badge/golden/badge_negative.png | Bin 0 -> 3682 bytes .../components/badge/golden/badge_neutral.png | Bin 0 -> 3617 bytes .../badge/golden/badge_positive.png | Bin 0 -> 3681 bytes .../components/badge/golden/badge_warning.png | Bin 0 -> 3646 bytes .../badge/golden/indicator_default.png | Bin 0 -> 4004 bytes .../badge/golden/indicator_icon_default.png | Bin 0 -> 4112 bytes .../badge/golden/indicator_icon_values.png | Bin 0 -> 3895 bytes .../golden/indicator_notification_default.png | Bin 0 -> 4004 bytes .../golden/indicator_notification_values.png | Bin 0 -> 3600 bytes .../components/badge/golden/label_dark.png | Bin 0 -> 3653 bytes .../components/badge/golden/label_default.png | Bin 0 -> 3610 bytes .../badge/golden/label_negative.png | Bin 0 -> 3682 bytes .../components/badge/golden/label_neutral.png | Bin 0 -> 3617 bytes .../badge/golden/label_positive.png | Bin 0 -> 3681 bytes .../components/badge/golden/label_sharp.png | Bin 3651 -> 3454 bytes .../components/badge/golden/label_warning.png | Bin 0 -> 3646 bytes .../badge/golden/priority_pill_default.png | Bin 0 -> 4487 bytes .../badge/golden/priority_pill_high.png | Bin 0 -> 3673 bytes .../badge/golden/priority_pill_low.png | Bin 0 -> 3869 bytes .../badge/golden/priority_pill_medium.png | Bin 0 -> 4071 bytes .../badge/golden/status_label_custom.png | Bin 0 -> 4555 bytes .../badge/golden/status_label_default.png | Bin 0 -> 4514 bytes test/src/components/badge/golden/tag_left.png | Bin 0 -> 3634 bytes .../src/components/badge/golden/tag_right.png | Bin 0 -> 3607 bytes test/src/components/badge/indicator_test.dart | 175 +++++++++++ test/src/components/badge/label_test.dart | 111 +++++++ .../components/badge/priority_pill_test.dart | 129 ++++++++ .../components/badge/status_label_test.dart | 62 ++++ test/src/components/badge/tag_test.dart | 57 ++++ test/src/components/button/button_test.dart | 280 +++++++++++++++++ .../button/golden/button_disabled.png | Bin 0 -> 4266 bytes .../button/golden/button_negative.png | Bin 0 -> 3720 bytes .../button/golden/button_outline.png | Bin 0 -> 3849 bytes .../button/golden/button_outline_subtle.png | Bin 0 -> 3555 bytes .../button/golden/button_positive.png | Bin 0 -> 3927 bytes .../button/golden/button_primary.png | Bin 0 -> 3720 bytes .../button/golden/button_secondary.png | Bin 0 -> 3865 bytes .../components/button/golden/button_text.png | Bin 3647 -> 3501 bytes .../components/checkbox/checkbox_test.dart | 143 +++++++++ .../checkbox/golden/checkbox_disabled.png | Bin 0 -> 3539 bytes .../checkbox/golden/checkbox_enabled.png | Bin 0 -> 3597 bytes test/src/components/dialpad/dialpad_test.dart | 285 ++++++++++++++++++ .../dialpad/golden/dialpad_disabled.png | Bin 0 -> 12517 bytes .../dialpad/golden/dialpad_enabled.png | Bin 0 -> 12517 bytes .../dialpad/golden/dialpadbutton.png | Bin 0 -> 4743 bytes test/src/components/fabs/fab_test.dart | 160 ++++++++++ .../components/fabs/golden/FAB_default.png | Bin 0 -> 4766 bytes .../components/fabs/golden/FAB_inverse.png | Bin 0 -> 4358 bytes .../components/fabs/golden/FAB_secondary.png | Bin 0 -> 3598 bytes .../golden/in_page_banner_buttons.png | Bin 0 -> 4390 bytes .../golden/in_page_banner_default.png | Bin 0 -> 3918 bytes .../golden/in_page_banner_negative.png | Bin 0 -> 3949 bytes .../golden/in_page_banner_positive.png | Bin 0 -> 3839 bytes .../in_page_banner/in_page_banner_test.dart | 126 ++++++++ .../password/golden/password_default.png | Bin 0 -> 3639 bytes .../password/golden/password_error.png | Bin 0 -> 3845 bytes .../password/password_input_test.dart | 97 ++++++ .../components/tooltip/golden/arrow_down.png | Bin 3651 -> 3648 bytes .../components/tooltip/golden/arrow_left.png | Bin 3651 -> 3658 bytes .../components/tooltip/golden/arrow_right.png | Bin 3647 -> 3642 bytes .../components/tooltip/golden/arrow_up.png | Bin 3658 -> 3655 bytes test/src/components/tooltip/tooltip_test.dart | 39 +-- test/src/theme/color_swatch_test.dart | 19 ++ .../test => test/src/utils}/rounded_test.dart | 71 +++-- test/test_utils/test_app.dart | 52 +++- test/test_utils/utils.dart | 14 + 92 files changed, 1880 insertions(+), 902 deletions(-) delete mode 100644 example/test/badge_test.dart delete mode 100644 example/test/button_test.dart delete mode 100644 example/test/checkbox_test.dart delete mode 100644 example/test/color_test.dart delete mode 100644 example/test/dialpad_test.dart delete mode 100644 example/test/fab_test.dart delete mode 100644 example/test/in_page_banner_test.dart delete mode 100644 example/test/password_input_test.dart delete mode 100644 example/test/priority_pill_test.dart delete mode 100644 example/test/status_label_test.dart delete mode 100644 example/test/tag_test.dart delete mode 100644 example/test/test_components.dart delete mode 100644 example/test/typography_test.dart rename golden/arrow_left.png => test/src/components/badge/golden/badge.png (80%) create mode 100644 test/src/components/badge/golden/badge_dark.png rename golden/arrow_up.png => test/src/components/badge/golden/badge_default.png (80%) create mode 100644 test/src/components/badge/golden/badge_negative.png create mode 100644 test/src/components/badge/golden/badge_neutral.png create mode 100644 test/src/components/badge/golden/badge_positive.png create mode 100644 test/src/components/badge/golden/badge_warning.png create mode 100644 test/src/components/badge/golden/indicator_default.png create mode 100644 test/src/components/badge/golden/indicator_icon_default.png create mode 100644 test/src/components/badge/golden/indicator_icon_values.png create mode 100644 test/src/components/badge/golden/indicator_notification_default.png create mode 100644 test/src/components/badge/golden/indicator_notification_values.png create mode 100644 test/src/components/badge/golden/label_dark.png create mode 100644 test/src/components/badge/golden/label_default.png create mode 100644 test/src/components/badge/golden/label_negative.png create mode 100644 test/src/components/badge/golden/label_neutral.png create mode 100644 test/src/components/badge/golden/label_positive.png rename golden/arrow_down.png => test/src/components/badge/golden/label_sharp.png (80%) create mode 100644 test/src/components/badge/golden/label_warning.png create mode 100644 test/src/components/badge/golden/priority_pill_default.png create mode 100644 test/src/components/badge/golden/priority_pill_high.png create mode 100644 test/src/components/badge/golden/priority_pill_low.png create mode 100644 test/src/components/badge/golden/priority_pill_medium.png create mode 100644 test/src/components/badge/golden/status_label_custom.png create mode 100644 test/src/components/badge/golden/status_label_default.png create mode 100644 test/src/components/badge/golden/tag_left.png create mode 100644 test/src/components/badge/golden/tag_right.png create mode 100644 test/src/components/badge/indicator_test.dart create mode 100644 test/src/components/badge/label_test.dart create mode 100644 test/src/components/badge/priority_pill_test.dart create mode 100644 test/src/components/badge/status_label_test.dart create mode 100644 test/src/components/badge/tag_test.dart create mode 100644 test/src/components/button/button_test.dart create mode 100644 test/src/components/button/golden/button_disabled.png create mode 100644 test/src/components/button/golden/button_negative.png create mode 100644 test/src/components/button/golden/button_outline.png create mode 100644 test/src/components/button/golden/button_outline_subtle.png create mode 100644 test/src/components/button/golden/button_positive.png create mode 100644 test/src/components/button/golden/button_primary.png create mode 100644 test/src/components/button/golden/button_secondary.png rename golden/arrow_right.png => test/src/components/button/golden/button_text.png (79%) create mode 100644 test/src/components/checkbox/checkbox_test.dart create mode 100644 test/src/components/checkbox/golden/checkbox_disabled.png create mode 100644 test/src/components/checkbox/golden/checkbox_enabled.png create mode 100644 test/src/components/dialpad/dialpad_test.dart create mode 100644 test/src/components/dialpad/golden/dialpad_disabled.png create mode 100644 test/src/components/dialpad/golden/dialpad_enabled.png create mode 100644 test/src/components/dialpad/golden/dialpadbutton.png create mode 100644 test/src/components/fabs/fab_test.dart create mode 100644 test/src/components/fabs/golden/FAB_default.png create mode 100644 test/src/components/fabs/golden/FAB_inverse.png create mode 100644 test/src/components/fabs/golden/FAB_secondary.png create mode 100644 test/src/components/in_page_banner/golden/in_page_banner_buttons.png create mode 100644 test/src/components/in_page_banner/golden/in_page_banner_default.png create mode 100644 test/src/components/in_page_banner/golden/in_page_banner_negative.png create mode 100644 test/src/components/in_page_banner/golden/in_page_banner_positive.png create mode 100644 test/src/components/in_page_banner/in_page_banner_test.dart create mode 100644 test/src/components/password/golden/password_default.png create mode 100644 test/src/components/password/golden/password_error.png create mode 100644 test/src/components/password/password_input_test.dart rename {example/test => test/src/utils}/rounded_test.dart (73%) create mode 100644 test/test_utils/utils.dart diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 4f6c5762..75d6f554 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -38,25 +38,26 @@ jobs: # Saves output to either success or failure variables. if [ "$failed" == "true" ]; then echo "FAILURE=true" >> $GITHUB_OUTPUT + exit 1 fi - name: Run tests id: test run: | - cd example - # Allows code to run after an error. set -e # Runs flutter test; saves output and if it fails. - out=$(flutter test) || failed='true' + out=$(flutter test --coverage) || failed='true' echo "$out" # Saves output to either success or failure variables. if [ "$failed" == "true" ]; then echo "FAILURE=true" >> $GITHUB_OUTPUT + exit 1 fi + - name: Check for modified files id: git-check run: echo "modified=$(if [ -n "$(git status --porcelain)" ]; then echo "true"; else echo "false"; fi)" >> $GITHUB_ENV @@ -68,8 +69,8 @@ jobs: git add -A git commit -m '[automated commit] lint format and import sort' git push - - name: Print outputs + if: always() env: GH_TOKEN: ${{ github.token }} run: | diff --git a/example/lib/pages/components/button_example.dart b/example/lib/pages/components/button_example.dart index fdea7179..48748d9f 100644 --- a/example/lib/pages/components/button_example.dart +++ b/example/lib/pages/components/button_example.dart @@ -29,7 +29,7 @@ class _ButtonExampleState extends State { void setFab(int index) => setState(() => fab = fabs[index]); - List fabs = []; + List fabs = []; @override Widget build(BuildContext context) { if (fabs.isEmpty) { @@ -38,12 +38,13 @@ class _ButtonExampleState extends State { scrollController: _scrollController, label: 'Small Circle Primary', size: ZetaFabSize.small, + initiallyExpanded: false, shape: ZetaWidgetBorder.full, type: ZetaFabType.primary, - onPressed: () => setFab(0), ), ZetaFAB( scrollController: _scrollController, + initiallyExpanded: false, label: 'Small Rounded Primary', size: ZetaFabSize.small, shape: ZetaWidgetBorder.rounded, @@ -55,6 +56,7 @@ class _ButtonExampleState extends State { label: 'Small Sharp Primary', size: ZetaFabSize.small, shape: ZetaWidgetBorder.sharp, + initiallyExpanded: false, type: ZetaFabType.inverse, onPressed: () => setFab(2), ), @@ -64,6 +66,7 @@ class _ButtonExampleState extends State { size: ZetaFabSize.large, shape: ZetaWidgetBorder.full, type: ZetaFabType.secondary, + initiallyExpanded: false, onPressed: () => setFab(3), ), ZetaFAB( @@ -71,6 +74,7 @@ class _ButtonExampleState extends State { label: 'Large Rounded Secondary', size: ZetaFabSize.large, shape: ZetaWidgetBorder.rounded, + initiallyExpanded: false, type: ZetaFabType.inverse, onPressed: () => setFab(4), ), @@ -80,14 +84,24 @@ class _ButtonExampleState extends State { size: ZetaFabSize.large, shape: ZetaWidgetBorder.sharp, type: ZetaFabType.primary, + initiallyExpanded: false, onPressed: () => setFab(5), ), ]; } - + final ZetaFAB theFab = (fab as ZetaFAB?) ?? (fabs.first); return ExampleScaffold( name: 'Button', - floatingActionButton: fab ?? fabs.first, + floatingActionButton: ZetaFAB( + initiallyExpanded: true, + icon: theFab.icon, + label: theFab.label, + scrollController: _scrollController, + size: theFab.size, + type: theFab.type, + shape: theFab.shape, + onPressed: theFab.onPressed, + ), child: SingleChildScrollView( controller: _scrollController, child: Row( diff --git a/example/test/badge_test.dart b/example/test/badge_test.dart deleted file mode 100644 index 9f54174b..00000000 --- a/example/test/badge_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -import 'test_components.dart'; - -void main() { - testWidgets('Initializes with correct parameters', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidget( - widget: ZetaLabel( - label: 'Test Label', - status: ZetaWidgetStatus.warning, - ), - ), - ); - - final zetaBadgeFinder = find.byType(ZetaLabel); - final ZetaLabel badge = tester.firstWidget(zetaBadgeFinder); - - expect(badge.rounded, null); - expect(badge.label, 'Test Label'); - expect(badge.status, ZetaWidgetStatus.warning); - }); -} diff --git a/example/test/button_test.dart b/example/test/button_test.dart deleted file mode 100644 index cbd6ed03..00000000 --- a/example/test/button_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -import 'test_components.dart'; - -void main() { - group('ZetaButton Tests', () { - testWidgets('Initializes with correct Label', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidget( - widget: ZetaButton( - onPressed: () {}, - label: 'Test Button', - ), - ), - ); - - expect(find.text('Test Button'), findsOneWidget); - }); - }); - - testWidgets('Triggers callback on tap', (WidgetTester tester) async { - bool callbackTriggered = false; - await tester.pumpWidget( - TestWidget( - widget: ZetaButton( - onPressed: () => callbackTriggered = true, - label: 'Test Button', - )), - ); - await tester.tap(find.byType(ZetaButton)); - await tester.pump(); - - expect(callbackTriggered, isTrue); - }); -} diff --git a/example/test/checkbox_test.dart b/example/test/checkbox_test.dart deleted file mode 100644 index 178f3bea..00000000 --- a/example/test/checkbox_test.dart +++ /dev/null @@ -1,74 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -import 'test_components.dart'; - -void main() { - group('ZetaCheckbox Tests', () { - testWidgets('Initializes with correct parameters', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidget( - widget: ZetaCheckbox( - value: true, - onChanged: (value) {}, - label: 'Test Checkbox', - ), - ), - ); - - final checkboxFinder = find.byType(ZetaCheckbox); - final ZetaCheckbox checkbox = tester.firstWidget(checkboxFinder); - - expect(checkbox.value, true); - expect(checkbox.rounded, null); - expect(checkbox.label, 'Test Checkbox'); - }); - - testWidgets('ZetaCheckbox changes state on tap', (WidgetTester tester) async { - bool? checkboxValue = true; - - await tester.pumpWidget( - TestWidget( - removeBody: true, - widget: ZetaCheckbox( - value: checkboxValue, - onChanged: (value) { - checkboxValue = value; - }, - ), - ), - ); - - await tester.tap(find.byType(ZetaCheckbox)); - await tester.pump(); - - expect(checkboxValue, false); - }); - }); -} - -class TestWidgetCB extends StatelessWidget { - final Widget widget; - - const TestWidgetCB({Key? key, required this.widget}); - - @override - Widget build(BuildContext context) { - return ZetaProvider( - builder: (context, theme, __) { - return Builder(builder: (context) { - return MaterialApp( - theme: ThemeData( - fontFamily: theme.fontFamily, - textTheme: zetaTextTheme, - ), - home: Scaffold( - body: widget, - ), - ); - }); - }, - ); - } -} diff --git a/example/test/color_test.dart b/example/test/color_test.dart deleted file mode 100644 index d33b0765..00000000 --- a/example/test/color_test.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -void main() { - testWidgets('Dark mode value', (tester) async { - final ZetaColors light = ZetaColors(); - final ZetaColors dark = ZetaColors(brightness: Brightness.dark); - - expect(light.primary.shade10, dark.primary.shade100); - expect(light.primary.shade20, dark.primary.shade90); - expect(light.primary.shade30, dark.primary.shade80); - expect(light.primary.shade40, dark.primary.shade70); - expect(light.primary.shade50, dark.primary.shade60); - }); - - testWidgets('AAA mode value', (tester) async { - final ZetaColors aa = ZetaColors(); - final ZetaColors aaa = ZetaColors(brightness: Brightness.dark, contrast: ZetaContrast.aaa); - - expect(aa.primary.value, aa.primary.shade60.value); - expect(aaa.primary.value, aaa.primary.shade80.value); - }); - - testWidgets('Scheme generator', (tester) async { - final blueSwatch = ZetaColorSwatch.fromColor(ZetaColorBase.blue); - final greySwatch = ZetaColorSwatch.fromColor(ZetaColorBase.cool); - final blackSwatch = ZetaColorSwatch.fromColor(ZetaColorBase.black); - - expect(blueSwatch.shade10 != blueSwatch.shade20, true); - expect(blueSwatch.shade20 != blueSwatch.shade30, true); - expect(blueSwatch.shade30 != blueSwatch.shade40, true); - expect(blueSwatch.shade40 != blueSwatch.shade50, true); - expect(blueSwatch.shade50 != blueSwatch.shade60, true); - expect(blueSwatch.shade60 != blueSwatch.shade70, true); - expect(blueSwatch.shade70 != blueSwatch.shade80, true); - expect(blueSwatch.shade80 != blueSwatch.shade90, true); - expect(blueSwatch.shade90 != blueSwatch.shade100, true); - - expect(greySwatch.shade10 != greySwatch.shade20, true); - expect(greySwatch.shade20 != greySwatch.shade30, true); - expect(greySwatch.shade30 != greySwatch.shade40, true); - expect(greySwatch.shade40 != greySwatch.shade50, true); - expect(greySwatch.shade50 != greySwatch.shade60, true); - expect(greySwatch.shade60 != greySwatch.shade70, true); - expect(greySwatch.shade70 != greySwatch.shade80, true); - expect(greySwatch.shade80 != greySwatch.shade90, true); - expect(greySwatch.shade90 != greySwatch.shade100, true); - - expect(blackSwatch.shade10 != blackSwatch.shade20, true); - expect(blackSwatch.shade20 != blackSwatch.shade30, true); - expect(blackSwatch.shade30 != blackSwatch.shade40, true); - expect(blackSwatch.shade40 != blackSwatch.shade50, true); - expect(blackSwatch.shade50 != blackSwatch.shade60, true); - expect(blackSwatch.shade60 != blackSwatch.shade70, true); - expect(blackSwatch.shade70 != blackSwatch.shade80, true); - expect(blackSwatch.shade80 != blackSwatch.shade90, true); - expect(blackSwatch.shade90 != blackSwatch.shade100, true); - }); -} diff --git a/example/test/dialpad_test.dart b/example/test/dialpad_test.dart deleted file mode 100644 index e0d5869e..00000000 --- a/example/test/dialpad_test.dart +++ /dev/null @@ -1,116 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -import 'test_components.dart'; - -void main() { - group('ZetaDialPad Tests', () { - testWidgets('Initializes with correct parameters', (WidgetTester tester) async { - String number = '', text = ''; - - Future debounceWait() => tester.binding.delayed(const Duration(milliseconds: 500)); - - await tester.pumpWidget( - TestWidget( - screenSize: Size(1000, 1000), - widget: ZetaDialPad( - onNumber: (value) => number += value, - onText: (value) => text += value, - ), - ), - ); - final dialPadFinder = find.byType(ZetaDialPad); - final buttonFinder = find.byType(ZetaDialPadButton); - - final oneFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '1'); - final twoFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '2'); - final threeFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '3'); - final starFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '*'); - final hashFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '#'); - - final ZetaDialPad dialPad = tester.firstWidget(dialPadFinder); - final List dialPadButtons = tester.widgetList(buttonFinder).toList(); - - final ZetaDialPadButton one = tester.firstWidget(oneFinder); - final ZetaDialPadButton two = tester.firstWidget(twoFinder); - final ZetaDialPadButton three = tester.firstWidget(threeFinder); - - /// Dial Pad built correctly. - expect(dialPad.buttonsPerRow, 3); - expect(dialPadButtons.length, 12); - - /// Dial Pad buttons built correctly. - expect(one.primary, '1'); - expect(one.secondary, ''); - expect(two.primary, '2'); - expect(two.secondary, 'ABC'); - expect(three.primary, '3'); - expect(three.secondary, 'DEF'); - - /// Tap button with only number. - await tester.tap(oneFinder); - await tester.pump(); - expect(number, '1'); - - /// Tap button with number and text. - await tester.tap(twoFinder); - await tester.pump(); - await debounceWait(); - expect(number, '12'); - expect(text, 'A'); - - /// Tap different button. - await tester.tap(threeFinder); - await tester.pump(); - await debounceWait(); - expect(number, '123'); - expect(text, 'AD'); - - /// Tap text button twice. - await tester.tap(twoFinder); - await tester.tap(twoFinder); - await tester.pump(); - await debounceWait(); - expect(text, 'ADB'); - - /// Tap text button thrice. - await tester.tap(twoFinder); - await tester.tap(twoFinder); - await tester.tap(twoFinder); - await tester.pump(); - await debounceWait(); - expect(text, 'ADBC'); - - /// Tap different text buttons to ensure debounce is cancelled. - await tester.tap(twoFinder); - await tester.tap(threeFinder); - await tester.tap(twoFinder); - await tester.pump(); - await debounceWait(); - expect(text, 'ADBCADA'); - - /// Tap text button more times than there is options to ensure it loops around correctly. - await tester.tap(threeFinder); - await tester.tap(threeFinder); - await tester.tap(threeFinder); - await tester.tap(threeFinder); - await tester.tap(threeFinder); - await tester.tap(threeFinder); - await tester.tap(oneFinder); - await tester.pump(); - expect(text, 'ADBCADAF'); - number = ''; - - /// Tap buttons with symbols - await tester.ensureVisible(starFinder); - await tester.tap(starFinder); - await tester.tap(hashFinder); - await tester.pump(); - expect(number, '*#'); - - /// Allow all timers to end in text debounce - await debounceWait(); - }); - }); -} diff --git a/example/test/fab_test.dart b/example/test/fab_test.dart deleted file mode 100644 index 63bebbc0..00000000 --- a/example/test/fab_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -import 'test_components.dart'; - -void main() { - group('ZetaFAB Tests', () { - testWidgets('Initializes with correct', (WidgetTester tester) async { - final scrollController = ScrollController(); - await tester.pumpWidget(TestWidget( - widget: ZetaFAB( - scrollController: scrollController, - label: 'Label', - ))); - - expect(find.byType(ZetaFAB), findsOneWidget); - }); - - testWidgets('OnPressed callback', (WidgetTester tester) async { - bool isPressed = false; - final scrollController = ScrollController(); - - await tester.pumpWidget(TestWidget( - widget: ZetaFAB( - scrollController: scrollController, - label: 'Label', - onPressed: () => isPressed = true, - ))); - - await tester.tap(find.byType(ZetaFAB)); - await tester.pumpAndSettle(); - expect(isPressed, isTrue); - }); - }); - - testWidgets('Icon Test', (WidgetTester tester) async { - final scrollController = ScrollController(); - await tester.pumpWidget(TestWidget( - widget: ZetaFAB( - scrollController: scrollController, - label: 'Label', - ))); - expect(find.byIcon(ZetaIcons.add_round), findsOneWidget); - }); -} diff --git a/example/test/in_page_banner_test.dart b/example/test/in_page_banner_test.dart deleted file mode 100644 index bf28f160..00000000 --- a/example/test/in_page_banner_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; -import 'package:flutter/material.dart'; - -import 'test_components.dart'; - -void main() { - group('ZetaInPageBanner Tests', () { - testWidgets('ZetaInPageBanner creation', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidget( - widget: ZetaInPageBanner( - content: Text('Test'), - )), - ); - - expect(find.byType(ZetaInPageBanner), findsOneWidget); - }); - }); - - testWidgets('ZetaInPageBanner displays content text', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidget( - widget: ZetaInPageBanner( - content: Text('Test'), - )), - ); - - expect(find.text('Test'), findsOneWidget); - }); - - testWidgets('ZetaInPageBanner shows/hides \'close icon\' correctly', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidget( - widget: ZetaInPageBanner( - content: Text('Test'), - onClose: () {}, - )), - ); - expect(find.byIcon(ZetaIcons.close_round), findsOneWidget); - - await tester.pumpWidget( - TestWidget( - widget: ZetaInPageBanner( - content: Text('Test'), - )), - ); - expect(find.byIcon(ZetaIcons.close_sharp), findsNothing); - }); - - testWidgets('ZetaInPageBanner button callbacks work', (WidgetTester tester) async { - bool onPressed = false; - final key = GlobalKey(); - await tester.pumpWidget( - TestWidget( - widget: ZetaInPageBanner( - content: Text('Test'), - actions: [ - ZetaButton( - label: 'Test button', - onPressed: () => onPressed = true, - key: key, - ), - ], - ), - ), - ); - - await tester.tap(find.byKey(key)); - await tester.pumpAndSettle(); - expect(onPressed, isTrue); - }); - - testWidgets('ZetaInPageBanner \'close\' icon tap test', (WidgetTester tester) async { - bool closeIconIsTapped = false; - await tester.pumpWidget( - TestWidget( - widget: ZetaInPageBanner( - onClose: () => closeIconIsTapped = true, - content: Text('Test'), - )), - ); - final closeIcon = find.byIcon(ZetaIcons.close_round); - await tester.tap(closeIcon); - await tester.pump(); - expect(closeIconIsTapped, isTrue); - }); -} diff --git a/example/test/password_input_test.dart b/example/test/password_input_test.dart deleted file mode 100644 index e6335a79..00000000 --- a/example/test/password_input_test.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -import 'test_components.dart'; - -void main() { - testWidgets('ZetaPasswordInput initializes correctly', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidget( - widget: ZetaPasswordInput(), - ), - ); - expect(find.byType(ZetaPasswordInput), findsOneWidget); - }); - - testWidgets('Test password visibility', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidget( - widget: ZetaPasswordInput(), - ), - ); - final obscureIconOff = find.byIcon(ZetaIcons.visibility_off_round); - expect(obscureIconOff, findsOneWidget); - await tester.tap(obscureIconOff); - await tester.pump(); - - final obscureIconOn = find.byIcon(ZetaIcons.visibility_round); - expect(obscureIconOn, findsOneWidget); - }); - - testWidgets('Test error message visibility', (WidgetTester tester) async { - String? testValidator(String? value) { - final regExp = RegExp(r'\d'); - if (value != null && regExp.hasMatch(value)) return 'Error'; - return null; - } - - final controller = TextEditingController(); - controller.text = 'password123'; - final formKey = GlobalKey(); - - await tester.pumpWidget( - TestWidget( - widget: Form( - key: formKey, - child: ZetaPasswordInput( - controller: controller, - validator: testValidator, - ), - ), - ), - ); - formKey.currentState?.validate(); - await tester.pump(); - - // There will be two matches for the error text as the form field itself contains a hidden one. - expect(find.text('Error'), findsExactly(2)); - }); -} diff --git a/example/test/priority_pill_test.dart b/example/test/priority_pill_test.dart deleted file mode 100644 index 32f6acad..00000000 --- a/example/test/priority_pill_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -import 'test_components.dart'; - -void main() { - testWidgets('Initializes with correct label and index', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidget( - widget: ZetaPriorityPill( - label: 'High', - index: '2', - ), - ), - ); - expect(find.text('High'), findsOneWidget); - expect(find.text('2'), findsOneWidget); - }); -} diff --git a/example/test/status_label_test.dart b/example/test/status_label_test.dart deleted file mode 100644 index b1908792..00000000 --- a/example/test/status_label_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; -import 'package:flutter/material.dart'; - -void main() { - group('ZetaStatusLabel Tests', () { - testWidgets('Initializes with correct properties', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidgetStatusLabel( - widget: ZetaStatusLabel(label: 'Test Label'), - ), - ); - expect(find.text('Test Label'), findsOneWidget); - }); - }); - - testWidgets('Initializes with correct label and custom icon', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidgetStatusLabel( - widget: ZetaStatusLabel( - label: 'Custom Icon', - customIcon: Icons.person, - ), - ), - ); - expect(find.text('Custom Icon'), findsOneWidget); - expect(find.byIcon(Icons.person), findsOneWidget); - }); -} - -class TestWidgetStatusLabel extends StatelessWidget { - final Widget widget; - - const TestWidgetStatusLabel({Key? key, required this.widget}); - - @override - Widget build(BuildContext context) { - return ZetaProvider( - builder: (context, theme, __) { - return Builder(builder: (context) { - return MaterialApp( - theme: ThemeData( - fontFamily: theme.fontFamily, - textTheme: zetaTextTheme, - ), - home: Scaffold( - body: widget, - ), - ); - }); - }, - ); - } -} diff --git a/example/test/tag_test.dart b/example/test/tag_test.dart deleted file mode 100644 index 6925b94c..00000000 --- a/example/test/tag_test.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -import 'test_components.dart'; - -void main() { - group('ZetaCheckbox Tests', () { - testWidgets('Initializes with correct parameters', (WidgetTester tester) async { - await tester.pumpWidget( - TestWidget( - widget: ZetaTag.right( - label: 'Tag', - ), - ), - ); - - expect(find.text('Tag'), findsOneWidget); - }); - - testWidgets('ZetaTag handles direction correctly', (WidgetTester tester) async { - const widgetLeft = TestWidget( - widget: ZetaTag( - label: 'Tag', - direction: ZetaTagDirection.left, - )); - - const widgetRight = TestWidget( - widget: ZetaTag( - label: 'Tag', - direction: ZetaTagDirection.right, - )); - - await tester.pumpWidget(widgetLeft); - expect(find.byType(ZetaTag), findsOneWidget); - - await tester.pumpWidget(widgetRight); - expect(find.byType(ZetaTag), findsOneWidget); - }); - }); -} diff --git a/example/test/test_components.dart b/example/test/test_components.dart deleted file mode 100644 index ef4c9b7f..00000000 --- a/example/test/test_components.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -class TestWidget extends StatelessWidget { - final Size? screenSize; - final Widget widget; - final ThemeMode? themeMode; - final bool removeBody; - final bool? rounded; - - const TestWidget({ - required this.widget, - this.screenSize, - super.key, - this.themeMode, - this.removeBody = false, - this.rounded, - }); - - @override - Widget build(BuildContext context) { - final size = screenSize ?? const Size(1280, 720); - - return ZetaProvider( - initialThemeMode: themeMode ?? ThemeMode.system, - initialThemeData: ZetaThemeData(rounded: rounded ?? true), - builder: (context, theme, __) { - return Builder( - builder: (context) { - return MaterialApp( - debugShowCheckedModeBanner: false, - theme: ThemeData( - fontFamily: theme.fontFamily, - colorScheme: theme.colorsLight.toScheme(), - textTheme: zetaTextTheme, - ), - darkTheme: ThemeData( - fontFamily: theme.fontFamily, - colorScheme: theme.colorsDark.toScheme(), - textTheme: zetaTextTheme, - ), - home: Scaffold( - body: removeBody - ? widget - : SizedBox( - width: size.width, - height: size.height, - child: MediaQuery( - data: MediaQueryData(size: Size(size.width, size.height)), - child: SingleChildScrollView(child: widget), - ), - ), - ), - ); - }, - ); - }, - ); - } -} diff --git a/example/test/typography_test.dart b/example/test/typography_test.dart deleted file mode 100644 index 7132248e..00000000 --- a/example/test/typography_test.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_example/pages/theme/typography_example.dart'; - -import 'package:zeta_flutter/zeta_flutter.dart'; - -import 'test_components.dart'; - -void main() { - const Key key1 = Key('1'); - const Key key2 = Key('2'); - const Key key3 = Key('3'); - const Key key4 = Key('4'); - - testWidgets('Text tokens', (tester) async { - await tester.pumpWidget( - TestWidget( - widget: Builder( - builder: (context) { - return Column( - children: [ - const Text(exampleText, key: key1), - Text(exampleText, style: ZetaTextStyles.bodyMedium, key: key2), - Text(exampleText, style: ZetaTextStyles.displayLarge, key: key3), - Text( - exampleText, - style: TextStyle(fontSize: 52, fontWeight: FontWeight.w300, height: 60 / 52), - key: key4, - ), - ], - ); - }, - ), - ), - ); - - final Finder zetaText1 = find.byKey(key1); - final Finder zetaText2 = find.byKey(key2); - final Finder zetaText3 = find.byKey(key3); - final Finder zetaText4 = find.byKey(key4); - - final InlineSpan text1 = - (find.descendant(of: zetaText1, matching: find.byType(RichText)).evaluate().first.widget as RichText).text; - final InlineSpan text2 = - (find.descendant(of: zetaText2, matching: find.byType(RichText)).evaluate().first.widget as RichText).text; - final InlineSpan text3 = - (find.descendant(of: zetaText3, matching: find.byType(RichText)).evaluate().first.widget as RichText).text; - final InlineSpan text4 = - (find.descendant(of: zetaText4, matching: find.byType(RichText)).evaluate().first.widget as RichText).text; - - /// Test default in [Text] widget is [ZetaTextStyles.bodyMedium]. - expect(text1.style, text2.style); - - /// Test that [ZetaTextStyles.displayLarge] has not changed. - expect(text3.style, text4.style); - - /// Test font size of [ZetaTextStyles.bodyMedium] is correct - expect(text1.style!.fontSize, 16); - - /// Test line height of [ZetaTextStyles.bodyMedium] is correct - expect(text1.style!.height, 24 / 16); - - /// Test font weight of [ZetaTextStyles.bodyMedium] is correct - expect(text1.style!.fontWeight, FontWeight.w400); - }); -} diff --git a/lib/src/components/badges/indicator.dart b/lib/src/components/badges/indicator.dart index 93286d81..5ca26932 100644 --- a/lib/src/components/badges/indicator.dart +++ b/lib/src/components/badges/indicator.dart @@ -14,10 +14,11 @@ enum ZetaIndicatorType { /// ZetaIndicator. /// /// Indicators are used to show the status of a user or any messages/notifications they might have. -class ZetaIndicator extends StatelessWidget { +class ZetaIndicator extends ZetaStatelessWidget { /// Constructor for [ZetaIndicator]. const ZetaIndicator({ super.key, + super.rounded, this.type = ZetaIndicatorType.notification, this.size = ZetaWidgetSize.large, this.icon, @@ -29,6 +30,7 @@ class ZetaIndicator extends StatelessWidget { /// Constructor for [ZetaIndicator] of type [ZetaIndicatorType.icon]. const ZetaIndicator.icon({ super.key, + super.rounded, this.size = ZetaWidgetSize.large, this.inverse = false, this.icon, @@ -39,12 +41,13 @@ class ZetaIndicator extends StatelessWidget { /// Constructor for [ZetaIndicator] of type [ZetaIndicatorType.notification]. const ZetaIndicator.notification({ super.key, + super.rounded, this.size = ZetaWidgetSize.large, this.inverse = false, - this.icon, this.value, this.color, - }) : type = ZetaIndicatorType.notification; + }) : type = ZetaIndicatorType.notification, + icon = null; /// The type of the [ZetaIndicator] - icon or notification. /// @@ -75,8 +78,10 @@ class ZetaIndicator extends StatelessWidget { IconData? icon, int? value, bool? inverse, + Key? key, }) { return ZetaIndicator( + key: key ?? this.key, type: type ?? this.type, size: size ?? this.size, icon: icon ?? this.icon, @@ -151,14 +156,8 @@ class ZetaIndicator extends StatelessWidget { } double _getIconSize(ZetaWidgetSize size) { - switch (size) { - case ZetaWidgetSize.large: - return ZetaSpacing.medium; - case ZetaWidgetSize.medium: - return ZetaSpacing.small; - case ZetaWidgetSize.small: - return ZetaSpacing.none; - } + if (size == ZetaWidgetSize.large) return ZetaSpacing.medium; + return ZetaSpacing.small; } @override @@ -169,7 +168,7 @@ class ZetaIndicator extends StatelessWidget { ..add(DiagnosticsProperty('size', size)) ..add(DiagnosticsProperty('value', value)) ..add(DiagnosticsProperty('icon', icon)) - ..add(DiagnosticsProperty('inverseBorder', inverse)) + ..add(DiagnosticsProperty('inverse', inverse)) ..add(ColorProperty('color', color)); } } diff --git a/lib/src/components/badges/status_label.dart b/lib/src/components/badges/status_label.dart index e89138e2..346f7137 100644 --- a/lib/src/components/badges/status_label.dart +++ b/lib/src/components/badges/status_label.dart @@ -64,6 +64,6 @@ class ZetaStatusLabel extends ZetaStatelessWidget { ..add(StringProperty('label', label)) ..add(DiagnosticsProperty('rounded', rounded)) ..add(DiagnosticsProperty('customIcon', customIcon)) - ..add(EnumProperty('severity', status)); + ..add(EnumProperty('status', status)); } } diff --git a/lib/src/components/buttons/button.dart b/lib/src/components/buttons/button.dart index 2a4aac53..45c553c8 100644 --- a/lib/src/components/buttons/button.dart +++ b/lib/src/components/buttons/button.dart @@ -15,6 +15,7 @@ class ZetaButton extends StatelessWidget { this.leadingIcon, this.trailingIcon, super.key, + this.focusNode, }); /// Constructs [ZetaButton] with Primary theme. @@ -26,6 +27,7 @@ class ZetaButton extends StatelessWidget { this.leadingIcon, this.trailingIcon, super.key, + this.focusNode, }) : type = ZetaButtonType.primary; /// Constructs [ZetaButton] with Secondary theme. @@ -37,6 +39,7 @@ class ZetaButton extends StatelessWidget { this.leadingIcon, this.trailingIcon, super.key, + this.focusNode, }) : type = ZetaButtonType.secondary; /// Constructs [ZetaButton] with Positive theme. @@ -48,6 +51,7 @@ class ZetaButton extends StatelessWidget { this.leadingIcon, this.trailingIcon, super.key, + this.focusNode, }) : type = ZetaButtonType.positive; /// Constructs [ZetaButton] with Negative theme. @@ -59,6 +63,7 @@ class ZetaButton extends StatelessWidget { this.leadingIcon, this.trailingIcon, super.key, + this.focusNode, }) : type = ZetaButtonType.negative; /// Constructs [ZetaButton] with Outline theme. @@ -70,6 +75,7 @@ class ZetaButton extends StatelessWidget { this.leadingIcon, this.trailingIcon, super.key, + this.focusNode, }) : type = ZetaButtonType.outline; /// Constructs [ZetaButton] with Outline Subtle theme. @@ -81,6 +87,7 @@ class ZetaButton extends StatelessWidget { this.leadingIcon, this.trailingIcon, super.key, + this.focusNode, }) : type = ZetaButtonType.outlineSubtle; /// Constructs [ZetaButton] with text theme. @@ -92,6 +99,7 @@ class ZetaButton extends StatelessWidget { this.leadingIcon, this.trailingIcon, super.key, + this.focusNode, }) : type = ZetaButtonType.text; /// Button label @@ -118,6 +126,9 @@ class ZetaButton extends StatelessWidget { /// Trailing icon of button. Goes behind button. final IconData? trailingIcon; + /// {@macro flutter.widgets.Focus.focusNode} + final FocusNode? focusNode; + /// Creates a clone. ZetaButton copyWith({ String? label, @@ -147,6 +158,7 @@ class ZetaButton extends StatelessWidget { return ConstrainedBox( constraints: BoxConstraints(minHeight: _minConstraints, minWidth: _minConstraints), child: FilledButton( + focusNode: focusNode, onPressed: onPressed, style: buttonStyle( colors, @@ -234,6 +246,7 @@ class ZetaButton extends StatelessWidget { ..add(EnumProperty('borderType', borderType)) ..add(EnumProperty('size', size)) ..add(DiagnosticsProperty('leadingIcon', leadingIcon)) - ..add(DiagnosticsProperty('trailingIcon', trailingIcon)); + ..add(DiagnosticsProperty('trailingIcon', trailingIcon)) + ..add(DiagnosticsProperty('focusNode', focusNode)); } } diff --git a/lib/src/components/checkbox/checkbox.dart b/lib/src/components/checkbox/checkbox.dart index 113839c7..d77e71a2 100644 --- a/lib/src/components/checkbox/checkbox.dart +++ b/lib/src/components/checkbox/checkbox.dart @@ -14,11 +14,12 @@ import '../../../zeta_flutter.dart'; class ZetaCheckbox extends FormField { /// Constructs a [ZetaCheckbox]. ZetaCheckbox({ - required this.value, + this.value = false, this.label, this.onChanged, this.rounded, this.useIndeterminate = false, + this.focusNode, super.validator, super.autovalidateMode, super.restorationId, @@ -27,7 +28,7 @@ class ZetaCheckbox extends FormField { initialValue: value, enabled: onChanged != null, builder: (field) { - return _Checkbox( + return ZetaInternalCheckbox( label: label, onChanged: (changedValue) { field.didChange(changedValue); @@ -38,6 +39,7 @@ class ZetaCheckbox extends FormField { value: value, error: !field.isValid, disabled: onChanged == null, + focusNode: focusNode, ); }, ); @@ -61,17 +63,21 @@ class ZetaCheckbox extends FormField { /// The label displayed next to the checkbox final String? label; + /// {@macro flutter.widgets.Focus.focusNode} + final FocusNode? focusNode; + @override ZetaCheckboxFormFieldState createState() => ZetaCheckboxFormFieldState(); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add(DiagnosticsProperty('isChecked', value)) + ..add(DiagnosticsProperty('value', value)) ..add(StringProperty('label', label)) ..add(DiagnosticsProperty('useIndeterminate', useIndeterminate)) ..add(DiagnosticsProperty('rounded', rounded)) - ..add(ObjectFlagProperty?>.has('onChanged', onChanged)); + ..add(ObjectFlagProperty?>.has('onChanged', onChanged)) + ..add(DiagnosticsProperty('focusNode', focusNode)); } } @@ -81,14 +87,20 @@ class ZetaCheckboxFormFieldState extends FormFieldState { ZetaCheckbox get widget => super.widget as ZetaCheckbox; } -class _Checkbox extends ZetaStatefulWidget { - const _Checkbox({ +/// Internal checkbox. Not for external use. +@visibleForTesting +@protected +class ZetaInternalCheckbox extends ZetaStatefulWidget { + /// Constructs a [ZetaInternalCheckbox]. + const ZetaInternalCheckbox({ + super.key, required this.onChanged, this.disabled = false, this.value = false, this.label, this.useIndeterminate = false, this.error = false, + this.focusNode, super.rounded, }); @@ -106,13 +118,17 @@ class _Checkbox extends ZetaStatefulWidget { /// Defaults to false. final bool useIndeterminate; + /// Whether field is value. final bool error; /// {@macro zeta-widget-disabled} final bool disabled; + /// {@macro flutter.widgets.Focus.focusNode} + final FocusNode? focusNode; + @override - State<_Checkbox> createState() => _CheckboxState(); + State createState() => _CheckboxState(); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -122,12 +138,13 @@ class _Checkbox extends ZetaStatefulWidget { ..add(DiagnosticsProperty('rounded', rounded)) ..add(DiagnosticsProperty('useIndeterminate', useIndeterminate)) ..add(DiagnosticsProperty('error', error)) - ..add(DiagnosticsProperty('enabled', disabled)) - ..add(ObjectFlagProperty>.has('onChanged', onChanged)); + ..add(DiagnosticsProperty('disabled', disabled)) + ..add(ObjectFlagProperty>.has('onChanged', onChanged)) + ..add(DiagnosticsProperty('focusNode', focusNode)); } } -class _CheckboxState extends State<_Checkbox> { +class _CheckboxState extends State { bool get _checked => widget.value; bool _isFocused = false; @@ -153,12 +170,14 @@ class _CheckboxState extends State<_Checkbox> { child: Semantics( mixed: widget.useIndeterminate, enabled: !widget.disabled, + focusable: true, child: MouseRegion( cursor: !widget.disabled ? SystemMouseCursors.click : SystemMouseCursors.forbidden, onEnter: (event) => _setHovered(true), onExit: (event) => _setHovered(false), child: !widget.disabled ? FocusableActionDetector( + focusNode: widget.focusNode, onFocusChange: (bool focus) => setState(() => _isFocused = focus), child: _buildContent(context), ) @@ -225,7 +244,7 @@ class _CheckboxState extends State<_Checkbox> { Color _getBackground(Zeta theme) { final ZetaColorSwatch color = widget.error ? theme.colors.error : theme.colors.primary; if (widget.disabled) return theme.colors.surfaceDisabled; - if (!_checked) return Colors.transparent; + if (!_checked) return theme.colors.surfacePrimary; if (_isHovered) return theme.colors.borderHover; return color; @@ -241,15 +260,4 @@ class _CheckboxState extends State<_Checkbox> { return theme.colors.cool.shade70; } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('value', widget.value)) - ..add(ObjectFlagProperty>.has('onChanged', widget.onChanged)) - ..add(DiagnosticsProperty('rounded', widget.rounded)) - ..add(StringProperty('label', widget.label)) - ..add(DiagnosticsProperty('useIndeterminate', widget.useIndeterminate)); - } } diff --git a/lib/src/components/dial_pad/dial_pad.dart b/lib/src/components/dial_pad/dial_pad.dart index 7bbdc32d..bd85c779 100644 --- a/lib/src/components/dial_pad/dial_pad.dart +++ b/lib/src/components/dial_pad/dial_pad.dart @@ -61,7 +61,7 @@ class ZetaDialPad extends StatefulWidget { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add(ObjectFlagProperty?>.has('onInput', onNumber)) + ..add(ObjectFlagProperty?>.has('onNumber', onNumber)) ..add(IntProperty('buttonsPerRow', buttonsPerRow)) ..add(DiagnosticsProperty>('buttonValues', buttonValues)) ..add(ObjectFlagProperty?>.has('onText', onText)); @@ -148,7 +148,7 @@ class ZetaDialPadButton extends StatelessWidget { super.key, required this.primary, this.secondary = '', - required this.onTap, + this.onTap, this.topPadding = 3, }); @@ -175,8 +175,8 @@ class ZetaDialPadButton extends StatelessWidget { super.debugFillProperties(properties); properties ..add(ObjectFlagProperty>.has('onTap', onTap)) - ..add(StringProperty('letters', secondary)) - ..add(StringProperty('number', primary)) + ..add(StringProperty('secondary', secondary)) + ..add(StringProperty('primary', primary)) ..add(DoubleProperty('topPadding', topPadding)); } diff --git a/lib/src/components/fabs/fab.dart b/lib/src/components/fabs/fab.dart index f3c6b08d..f091510c 100644 --- a/lib/src/components/fabs/fab.dart +++ b/lib/src/components/fabs/fab.dart @@ -36,7 +36,8 @@ class ZetaFAB extends StatefulWidget { this.size = ZetaFabSize.small, this.shape = ZetaWidgetBorder.full, this.icon = ZetaIcons.add_round, - this.initiallyExpanded = false, + this.initiallyExpanded, + this.focusNode, super.key, }); @@ -78,7 +79,10 @@ class ZetaFAB extends StatefulWidget { /// Whether the FAB starts as expanded. /// /// If [scrollController] or [label] are null, this is the permanent state of the FAB. - final bool initiallyExpanded; + final bool? initiallyExpanded; + + /// {@macro flutter.widgets.Focus.focusNode} + final FocusNode? focusNode; @override State createState() => _ZetaFABState(); @@ -87,61 +91,36 @@ class ZetaFAB extends StatefulWidget { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add(EnumProperty('buttonType', type)) - ..add(EnumProperty('buttonSize', size)) - ..add(EnumProperty('buttonShape', shape)) + ..add(EnumProperty('type', type)) + ..add(EnumProperty('size', size)) + ..add(EnumProperty('shape', shape)) ..add(ObjectFlagProperty.has('onPressed', onPressed)) ..add(DiagnosticsProperty('scrollController', scrollController)) - ..add(StringProperty('buttonLabel', label)) - ..add(DiagnosticsProperty('buttonIcon', icon)) - ..add(DiagnosticsProperty('initiallyExpanded', initiallyExpanded)); + ..add(StringProperty('label', label)) + ..add(DiagnosticsProperty('icon', icon)) + ..add(DiagnosticsProperty('initiallyExpanded', initiallyExpanded)) + ..add(DiagnosticsProperty('focusNode', focusNode)); } } class _ZetaFABState extends State { - bool __isExpanded = false; - bool get _isExpanded => __isExpanded; - set _isExpanded(bool value) { - if (value && widget.label != null || !value) __isExpanded = value; - } - - @override - void initState() { - super.initState(); - _isExpanded = (widget.initiallyExpanded && widget.label != null) || false; - widget.scrollController?.addListener(_scrollListener); - } - - void _scrollListener() { - final expanded = widget.scrollController?.position.userScrollDirection == ScrollDirection.reverse; - if (_isExpanded != expanded) { - setState(() => _isExpanded = expanded); - } - } - - @override - void dispose() { - widget.scrollController?.removeListener(_scrollListener); - super.dispose(); - } - @override Widget build(BuildContext context) { + final bool isExpanded = (widget.initiallyExpanded != null ? widget.initiallyExpanded! : widget.label != null); final colors = widget.type.colors(context); final backgroundColor = widget.type == ZetaFabType.inverse ? colors.shade80 : colors.shade60; - return ElevatedButton( + return FilledButton( onPressed: widget.onPressed, - style: ElevatedButton.styleFrom( - padding: EdgeInsets.zero, - shape: widget.shape.buttonShape(isExpanded: _isExpanded, size: widget.size), - backgroundColor: backgroundColor, - foregroundColor: backgroundColor.onColor, - ).copyWith( - overlayColor: WidgetStateProperty.resolveWith((Set states) { + focusNode: widget.focusNode, + style: ButtonStyle( + padding: const WidgetStatePropertyAll(EdgeInsets.zero), + shape: WidgetStatePropertyAll(widget.shape.buttonShape(isExpanded: isExpanded, size: widget.size)), + backgroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.disabled)) return Zeta.of(context).colors.surfaceDisabled; if (states.contains(WidgetState.hovered)) return colors.hover; if (states.contains(WidgetState.pressed)) return colors.selected; - return null; + return backgroundColor; }), side: WidgetStateProperty.resolveWith( (Set states) { @@ -156,14 +135,14 @@ class _ZetaFABState extends State { child: AnimatedContainer( duration: ZetaAnimationLength.normal, child: Padding( - padding: _isExpanded + padding: isExpanded ? const EdgeInsets.symmetric(horizontal: ZetaSpacingBase.x3_5, vertical: ZetaSpacing.medium) : EdgeInsets.all(widget.size.padding), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(widget.icon, size: widget.size.iconSize), - if (_isExpanded && widget.label != null) + if (isExpanded && widget.label != null) Row( mainAxisSize: MainAxisSize.min, children: [Text(widget.label!, style: ZetaTextStyles.labelLarge)], diff --git a/lib/src/components/in_page_banner/in_page_banner.dart b/lib/src/components/in_page_banner/in_page_banner.dart index cd48dc0f..39173d05 100644 --- a/lib/src/components/in_page_banner/in_page_banner.dart +++ b/lib/src/components/in_page_banner/in_page_banner.dart @@ -113,14 +113,8 @@ class ZetaInPageBanner extends ZetaStatelessWidget { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add( - ObjectFlagProperty.has( - 'onCloseFunction', - onClose, - ), - ) - ..add(DiagnosticsProperty('rounded', rounded)) - ..add(EnumProperty('severity', status)) + ..add(ObjectFlagProperty.has('onClose', onClose)) + ..add(EnumProperty('status', status)) ..add(StringProperty('title', title)) ..add(DiagnosticsProperty('customIcon', customIcon)); } diff --git a/lib/src/components/password/password_input.dart b/lib/src/components/password/password_input.dart index 775c94f1..88adbde0 100644 --- a/lib/src/components/password/password_input.dart +++ b/lib/src/components/password/password_input.dart @@ -67,14 +67,8 @@ class ZetaPasswordInput extends ZetaFormField { ..add(StringProperty('hintText', hintText)) ..add(StringProperty('label', label)) ..add(StringProperty('footerText', hintText)) - ..add( - ObjectFlagProperty.has( - 'validator', - validator, - ), - ) + ..add(ObjectFlagProperty.has('validator', validator)) ..add(EnumProperty('size', size)) - ..add(DiagnosticsProperty('rounded', rounded)) ..add(StringProperty('placeholder', placeholder)) ..add(ObjectFlagProperty.has('onSubmit', onSubmit)) ..add(StringProperty('errorText', errorText)); diff --git a/golden/arrow_left.png b/test/src/components/badge/golden/badge.png similarity index 80% rename from golden/arrow_left.png rename to test/src/components/badge/golden/badge.png index 7f66b33e576aa16865bf29dd67ae890685f00760..5b6326c1fa40cd7f3fd59ba49c12f311bc29cb78 100644 GIT binary patch delta 566 zcmX>svrlG%WBm(H7srr_IdAXmUmaE|bKv9o;=P$qLxpn!rJTH0os_yAEydO3mf8KU z<=V3ay8qeBIkWg%PArudu;>Vp2<((Py7!lf#gyB{&G*#ztiN9Iqwf4?%Q>6(RG$01 z=GyD8Re5nUca~*7`}TF_-Q9;73%`6hv+}d?bG9KY#u6ZvJWW znpJJT{yDQ+{_L7<)8?@-G`Qcn7PEWH7apCr+ux_v?c4Q51f=11@$X~K>~*`gn(zMp zt+2^?_08Se?^XOwZV%hMyZ`I$XyfYd=JV6jo_#s_Hgc_5eEsY1zl)#upS54IqwVjz zo9}CHRMuqs+5GI!w|RGGM&+;iskJ^F3=F@w+g9`cfA)B8xBZ!L^M7}Ku&kedf9C1% z_c{CiJ)OJr&(mkG<1LC)_WiBFVdQ&MBb@0JIJs_5c6? delta 591 zcmdldb694AWBprC7srr_IdAXo?+ZzlX?U2gwr%%Z7Hw`Z9giJs;wEvO-VW1GOilPP zJGT0(SP#>82X&oR*=^pA+p`m$QjRzAo~xel+2-j?{mJou`<|UWV|oA4i>n_$T0DIC z*!}UpfA=b?KIF*A$<6yC@y~en?AebGUHe&B`~208O|_M;3KNg)f$?)^(_W0xH z%&#w-)h>B^|M!HNuScf`_cJmakka*!tN3vEo=9=SUUmipW^Klz4}X3lc%ME!J+1kS zp_-o|fh~-Qg@GX<*3Rneqo+ldda=8{Tzf6veN>|RsD+)?tfRjSk5znna?--;=&#E^ z_TT?+c&)mgfuW-Q|6DBxJGy;oy|Mz|r zUlU!P=Woi+0CdHA<|o(Y-hTXhH^|0_`A;PtF*7h^=o|$~27Hu?V_;C&yk}>1a?SU* zy(^zHFfgPgSRRv50;<*6W5@pF*}MCUk18jW7k_+o^yA6;o163Z-aA;sz;NcIG`rxv zJ9`x!?p?fFUGBdXBHG!0fsvu1hk=oS!Kiz2`0?Za_k4Jn9vys^>2d#k{$+ANNzs5Ft&0~~I?rHCr@BRI|`ti$y8k-9%DlCr1 zoH_FB*|QxRO6y|o@3dN%6F;v?hJoSQn|NkWpvvxP6W?6Oyq#+kvmm3`nfU60xtaTa SHDmz&#^CAd=d#Wzp$PzD&K=MI diff --git a/test/src/components/badge/golden/badge_dark.png b/test/src/components/badge/golden/badge_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..1e514a9b35c1468713c0c0764e9bc04a326a4235 GIT binary patch literal 3653 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sOi0@i(^Q|oVT~_^F-2R8Xlfc%T10{WMdRmthbt?$1Cn(C6zZpJ7D=a zUJJ)dOPBYako9n!sI|aFU_z5`3eUF0OD-NEYq<9dA3cBh?2Fk~^UIdcC^y|~%-L_kFWpTd7J^HQ$uGYiwUjZB>icbNQ~4q5&d$Ft-fklk~&BwrCQMo$4?(f4p#s-_a=jZjTzHathj+vn$ zI3ab`vX>A4ia)-0_wL6xA0JxWsQ>(L@sD_m^1|Ghy=7%F`wQ!Gaw=K485$;U2S%33 zcc5brynK+KPr93l_uZ&UV$#59D2;{^8AZovvKdV_qsfM(+IBR{jAoh9EHj#Ah-{n> dgW}>p!~KGuH6LP@)&jeN44$rjF6*2UngH}3obCVs literal 0 HcmV?d00001 diff --git a/golden/arrow_up.png b/test/src/components/badge/golden/badge_default.png similarity index 80% rename from golden/arrow_up.png rename to test/src/components/badge/golden/badge_default.png index da590cb580efa4b72348a2bd02f04952cae12241..8f60d7c5148b4a8b3df55cac2513446ba3bcaa27 100644 GIT binary patch delta 499 zcmVgv$oQ*dzC zC*a=AwLXDPPCfvaF2$j1okKe~NDEROYy=yq_;+v!-4Y@1zj&|Lc7J|%_c^%X-W+#Z z%d#vFZqMAkIrI2v=H$t+A@&but{u)C-k90jUwaJz0GnXz=zqIq`S!E5XRxNLAI^M! zXJ-3_wU+<@@PD^`_v^JMu(n4(%>4NM+A9D6*aSPj-hckWmG@^}+&lXNJo{tj(nX#> znYpxk_VY6{5AV$^f1UmOt8dS|{Kh#p1+U@R)0s;zUEHSMf1dg6r_ple6C+ z0091tos;9|FGPHC=X@Vzj~~rkzIt)z|9m>LbB+(eFv#-ume5=Zn{H z-e@`Rrib@tZe2gU?YBPw02H>@9smFUYz~vK0UwjP0TqAQ*}Xh-a(sH>t1Ih`S<9{K zYcE*e?kj6A003YUY`^yI+7tLMc-{K|0D!>u$6u~JfwjH)!OVegfdBvqY%R;OJh(k` z_vXywqnVQ@YfqxGe=u|HaOUvF%-;UmYXAV)1Y66pENhPd001_Ff58F(05Spu0077c p5C8xmBS5pD0+b7rU;{c9^Ec-jWBEmb1jhgX002ovPDHLkV1lTn{tf^D delta 602 zcmV-g0;T<$9LgM!L4Wi~L_t(|obBDQZk1&K$Km%huI(nl$$^3cNw2|z#w)P|3?^O) zq!dW&uHJ%C;2zk7GPvQ|4s5NH3?wAqG4%JHlRnSZ$-De=zLRfp_U`)jPcX`A7@?yz`FTt?g0R-mj{pb$HRmD_kW8J0G6>a_kREY*2jnO@$g{({kI_i zFoggCV3H5x<3Azn&wKZ;RUmy4O?u^^J zx8|M$ur>q;z(l|Q`N!D%;qKfsSV2dRpN{Xo`F8FZ0BgY`SO60}{rPb239Kl017JD< z0x;3>n>TY$V1Grq8vxS@5P*qJPfzEbz>0D=0HzZl002P7iwFTefsKugv9q%?`TSzB z7-O**=Vxb^;`|t6ynOj`oGo#F8OwhD7rh67j}ssOpTOr=u8d!P`*rRaD{c4d-SN-c zw-@ri|Ig=tk$V96IFDcf000>Q0ssJH1PA~CkP#pN0F$Nx5r6R>5C9T4Z{8eVT)jH^ z{6)VgaMktzTowWZfW*P$gQd=2^os&lZ4ba@;SnqV03ahk004l@;_Th|`P?G_*1?xw zZO=V{754XE$8%2rSPQ-Z0hnlWb93$qtSEN_U^)Q;Fwyq4YjaOvMY$UQ(+LoOiSB-X zXYL8CD0c&3Iy1ik0a(Jb7thC&qr>s)`1LqBIhlJ7GuqnP8aKADk9&J}#_io(bI$=- o8v+CX0LXX*3$sB2vkMl?zi1qy3(I)Sj{pDw07*qoM6N<$g4%!@o&W#< diff --git a/test/src/components/badge/golden/badge_negative.png b/test/src/components/badge/golden/badge_negative.png new file mode 100644 index 0000000000000000000000000000000000000000..045c3ab3e42e6a47835df933d1ef93188c5aa441 GIT binary patch literal 3682 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq{?5)5S5QV$Rz;`&UmbWjOxvz3uh*@RMsgJVZowHYn=+Qe<%rNQwT- zx^>$Yw_@+L>(=s`nu>^ByrLv@Lu8Vv%FK%aFP83^RpvkYq0o1?z4Kq}iMw6-!>;}O z;mCR4i>5vM{PWLretSv#y_HFSzC8_p{M~yxdw1gPhtA2*H~aVQzF$$RbHDWXm0|{l z2nO%f@8{2{|NqE4_TVNbS$S|=mFr45JU|>*C zc3@y==wV=FU@#&exH+}#_q&aCm0zE=7VqZsu}GJC-Y+}9>d=$4>N0;@MurAfgWGja z_N_GkAiv@7iNC@Apx`<4uIBC4mF5N;W&34hch9RVdL_xgpwnE!>%-}i3ZWAjypfkEuRr5d~W{i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sOhw)i(^Q|oVT}q^P*El8Xlfsm#q54{cTHEBC##=Y&t8_fYiF(fy?wjoR)4L! zbKk%D?uG~(DfZu|KmK@9aOU~v-1W>12l!^h#@_d80$|9J4|(W4P-!)D8Gi0Jw1p8jX{-n~G+ z+5Gw!Ka+btetCJ>aQ0cVdHeV5kqHkEmp(84{lkU#HYNW)d?=8Sm#^OuxAywu1ReP; z$_xxPR~|hsx2yZ{Z}-RBudhqXe|Y-&`Qz*1>+Np-dAT|L@t?D^d!HYdc)Wamy=1$) zyY%_}Hopt^*jV4L*teto^5x5gb#?zvmi>BlwEN>%^ZRu>zP;mTU|`LcV`gBGWMpDs zNMYe%V3;5Xj06X_24Hv-5}f(>-|_jE|NhwM_`mb#y`+tA zWq^e}DXT_iM!3>xb`eEIXd` zF+=8!{_)3?4;#*}mgQh*@Xt5%o%{&s5Fxp0a@|P0Z$?!T6X&C$G#W}|6cwY%W;EH1 vCL5A!*U>C9nq@|_%xIP&vN1lSi;JJqr(X3j^cLK@&j19Tu6{1-oD!M^ literal 0 HcmV?d00001 diff --git a/test/src/components/badge/golden/badge_positive.png b/test/src/components/badge/golden/badge_positive.png new file mode 100644 index 0000000000000000000000000000000000000000..711c83083b0b3a93d19c5023835ab4e4f99572ea GIT binary patch literal 3681 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq{?P)5S5QV$Rz;hO4KRG93T-e{Zbu*6x#{58ImBSoJ&uo;;bdCCs}y zz&T&>4XeeH3pb<-vNwty|F-(cC51_xt({IWo`$}N-+aN1cUee zKLv%~{{1|^{NBNqdr|eJIW;w9Hruz@d=+6}`1gF;`M5t-uXugl?7nT^mtX&@?v*41 zgHFTL)wB286hHi0%YJ-a?(OY0&F%GelGfX8?T`OFp8Qg5={P$>{?tJ~Y!+Xxp{9e1`@9+G_&#U*_)z*AHclP5u?ff%a1sNEg zZ7q8L@o>6cPEASKI{xeC@9#_g4!{1)V!!3L_3!R}`dR<^;ok$(=l9J1{yyjDpYZp! zR`=?DZbdS-_L!ZblWeaCPzD4;9ZZTwIyXz_5W~TH5BDZw`Gu{rJqWpM|NPkL~#V;^39p9WwVe z+xf{@S^3G^TV5+$<7dmx(7?LEWcJy#;C^7b5o@kL$V9rsiTC2DN@5biXef<_5*g*k zXtEhiHlxXgq$+nb%Zz53(JV8XWr%E{5B=ieGyl>2?)AxgN-i=0fv2mV%Q~loCIGd; Bs>1*P literal 0 HcmV?d00001 diff --git a/test/src/components/badge/golden/badge_warning.png b/test/src/components/badge/golden/badge_warning.png new file mode 100644 index 0000000000000000000000000000000000000000..5b6326c1fa40cd7f3fd59ba49c12f311bc29cb78 GIT binary patch literal 3646 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sOg2Li(^Q|oVR!OuMR7fIq>m(@!rg*p~5+VQchm0PD-f-0xhA*}dfpkIvie@6+n`?fN1DQh&Sn_c3Sox?Nk%cYps@ z*yOzW=I-tHD*h(7hi%^7|MhmXarJle`RQrTzMOm;xz;Sc{`L3Y#n1cC+ArDB_V?Y* z_q8`FYqI@pe)i|vyt^}_^4HW_9}WhF-`j1g`TswAJh$8aOt|^KJ3m;~&%ZzObol$6 zegB@$-TCL~v)Az!#VPy#)_tx_OWXJF!yB3Eq|eto?f$))zVpY+_0sG0*F8LH?EY+a z?HiyS74NrB{`^mR`9Hf2yMM+pF#OoQ=Lz%!`&u;VU(lyMFU%X_0SorSHnTLra|j7(bw^%tqbj(q_(OCVnuB7nqR{^?R~Ku5utqIhXqtC4?TFaq_T*dZ9I}@kwLwMW3Lo ztmf431KU=!f+PIDD845vycY0l+`{A1(T3deA^H^Q=9@FwnZ;Uar#NX3si~Yhi_=wNs4Pk zPP0f*#}nd1PTa^);x7-8fUKoO^u|O7|E$8m*2F=-XI2zlcB|)@AN6ix-3k>&QS2g@ zV}Iz!*_;U%+H6K<)DhvHqSHvLI!GOY;V*PAiDkpzt!}X-ZY^^i*KPF{qQCV>X+nWu zsdu`pMrxa*9V`YTY$dkSJA}o&O$K20LD2|X<#YyNeD7eq-=nUs`&MtQBW75VdB330 zwG}1xAk5Bs!EyKGUx<3KDhlpXI@Q*eALHS{=*y4q&qj}rqbOd;Zq;(TI_%;k6`**FHjS;WnQ@T04<}vPxqG9C=SeMS@q7dvQH9{#YLYgTy{9qlY^tzk3NR3 zI~X?%YxV)E+ zorP4fJ=yF7ZEeQn_||-{Yb@KFXPa^8XGMEBQ~8T^KLG$4&l7o~&uB7rMdmv(3vOoJ zzLU_zL>&&uYramc%x+=9<9|4FYlV0KXLBP&3+%dE8Zuv zt$RAQT#qFPC#jU@q%ISzb&Z(JW))(T%1&u!FNL9kEAa}xd2r?v0C*>IoHQN=gMsb! z5lXGrm4>o(O7$iIq%0a>pAYi|!0GM}Po%I79x_+sE?;x0X%8;X1WE2aa(6 zDY$oUHstXWylsjVWc!tmflGP>vUG{4@gpAq`fpDwr>|wIh*cF_h>OeT&~-8iDQ3yB zwUdT&E%Wzn25Wu`gIjt@CL+jJGqh+&Xmnne7 zyykWg*A>zr+vaW;jjF4YhbRkGCZ)GEz8M{q-wd_J1(So3#G1}BXqU#YUJ*yj@%)4# zmS!x1YklFg+n*bUWY(7@uB`^R%s?5Vr;Hr0eEFL=kS~kMvZjO&_FyeO_$7T0#70^HC#sDxevQ{ zz21yxL5WChg!7eaujYz2FTn_kj#f*@rw3sTE!x2>FbWYHy)(uC)hsL#z zFV@;vO*m$h(L61T$wcxHAbcW4D@3WTPo_(TT&pY#mt);7-&mZ<^E;M4{4ZEH?SGsW z9zLJ+tRF9N!Xq7)^2PDG)=}pwx?{k)IyGohwhyfA!NRDENXRm2sbaHro^nR73FGUG zp}F$cX!b#&@$h8lrHL4>sez9IK%3Bayna+fWELTYZD^~uZ#?U+3RTotvM2Q+(ai`$ z^sZ9BL;B6P2(lU7x~}sOToP$JNTCkxY`|FQjreZ|@V4n1NQaWNW`|SBlGsQ!;Wq>a z>7zM1VV1zj^r~K8CaY zx2WH?m%D@9kEd3YdVPvx7MDi{i8-&EA_C+4dd0nvys+sr*+m4H4F)CfWcS<>srfF# z1&C2a(Q1UFSSpRiDl6;L&sC~_IgP;KC;Ntnl-${!O?nG}t3F7#+<6BnW#U(d?)SZr zNFJvL5DytVjo_IKo~h_j1dkee)X<}b9yR>Gsi96n>&Nh)l>GHO@~;P}Uy_r%lCIqP E2g}EZh5!Hn literal 0 HcmV?d00001 diff --git a/test/src/components/badge/golden/indicator_icon_values.png b/test/src/components/badge/golden/indicator_icon_values.png new file mode 100644 index 0000000000000000000000000000000000000000..9e930cb5527142a8bd102064e1d31dac99290a45 GIT binary patch literal 3895 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefr0O#r;B4q#hkZy9lPVwB^w?-pZzoKQre{@nc24;-Y#-E;(DhvJV3lG zSTKg`mw3!hp*K$dyQ3Fg@GX4k)v6bp>AWzgW9_wLo@y`8)SN6dRN*q)s`-Vl^ZHin z5BomkdgNI6(u&;`R!&tKAYCppMUnunRDm9y;*mC^Y-sI=G?j~$-vN{ zpH!;u093mAH~Z%Lx5v`+EWRIkX<1&DAGSKw2Pgxme8= zPgC#J)f*cd>+jz%FI<1!v#rzp=J~&Ucjoi?dG!v;%nS_ttFLa-IeqnS^Uvr14#rqU zoIPK^d)EG#Si91X-Os~5pMI}XoR~keIQ{#xlbfqQ?qFaza5$&5qGC_X&kyp(#-9(z z=bxSbzbyOTzwYNiEynBX4dVZwy7uQ4yLw~M!=201%G2laax*a4+_`q0&+lB#p2AAo z{q^q)=GpBvHCEsF@nY|7pebKouH7B@Y4>-t&&QqyfBxG&duQF>XEvq(I@ygaf&RL1 zb64@@tJ3wm{_Zrt8(F>QW{svZBLhSKvbB%TdN%y|cxvtWy)Vz*vi`^fR9v~{ed+9X zN7J`Ge>q!ye)8P({V@6Nod{_AU=Et8M6s{Fd~_4*gU5U9OjwfXyx zHDRlNUJEz>e0Tld_X~d9GcS97TmRmyt68S$-{iR6SQr@OM5AAS{dQNL>))HHseWtU z*KT-x=3Q1?{nIDLYt_%cJ6lz4Eh)snP+_uWT54ok+P_~9j~4?Ifw6J^zTNY->*;^~ z_FMh>n|*%{RmJVyG3$DqRi)k5-NxtbtN$_f@&JQ$%{#Uen{^>kqH+&O%gVdvuyFDll_*BH$Prm8-326sFxA&YZj<{0q!0Y(X9Nag3JV7V!vsNKs&a4xNlT6jjt0nRVi?T`qb0*=sW@6A qjMj#uwc%)OI9eMHhuZL`_$2MiQ~pm6vIVyD89ZJ6T-G@yGywo2`2z+3 literal 0 HcmV?d00001 diff --git a/test/src/components/badge/golden/indicator_notification_default.png b/test/src/components/badge/golden/indicator_notification_default.png new file mode 100644 index 0000000000000000000000000000000000000000..1c0aa6a8035b9c2b4321df57861b01b7c7eb34ec GIT binary patch literal 4004 zcmeHK>ra|j7(bw^%tqbj(q_(OCVnuB7nqR{^?R~Ku5utqIhXqtC4?TFaq_T*dZ9I}@kwLwMW3Lo ztmf431KU=!f+PIDD845vycY0l+`{A1(T3deA^H^Q=9@FwnZ;Uar#NX3si~Yhi_=wNs4Pk zPP0f*#}nd1PTa^);x7-8fUKoO^u|O7|E$8m*2F=-XI2zlcB|)@AN6ix-3k>&QS2g@ zV}Iz!*_;U%+H6K<)DhvHqSHvLI!GOY;V*PAiDkpzt!}X-ZY^^i*KPF{qQCV>X+nWu zsdu`pMrxa*9V`YTY$dkSJA}o&O$K20LD2|X<#YyNeD7eq-=nUs`&MtQBW75VdB330 zwG}1xAk5Bs!EyKGUx<3KDhlpXI@Q*eALHS{=*y4q&qj}rqbOd;Zq;(TI_%;k6`**FHjS;WnQ@T04<}vPxqG9C=SeMS@q7dvQH9{#YLYgTy{9qlY^tzk3NR3 zI~X?%YxV)E+ zorP4fJ=yF7ZEeQn_||-{Yb@KFXPa^8XGMEBQ~8T^KLG$4&l7o~&uB7rMdmv(3vOoJ zzLU_zL>&&uYramc%x+=9<9|4Fi1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sA-p{i(^Q|oVRyRubP%B(eN<+ZR~8G&F2)9nED+GE_hn-9GocY-#4d3 ziI>N^rQ-$1A)PyG&i>DipByHzLt#o@VPWj%{_m1Dm!`7|NjX*bPrF@zC2Zsf#Jc~ zT%FUK=G5=8u$wEcp1#>C`h3orH*epaIr#6Mj9kTUV8~Te|K}0_TK0c({VE{U!vOS| z5fcjo!wC+cu!6F~sNiUTj3$QBj4)ai1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sOi0@i(^Q|oVT~_^F-2R8Xlfc%T10{WMdRmthbt?$1Cn(C6zZpJ7D=a zUJJ)dOPBYako9n!sI|aFU_z5`3eUF0OD-NEYq<9dA3cBh?2Fk~^UIdcC^y|~%-L_kFWpTd7J^HQ$uGYiwUjZB>icbNQ~4q5&d$Ft-fklk~&BwrCQMo$4?(f4p#s-_a=jZjTzHathj+vn$ zI3ab`vX>A4ia)-0_wL6xA0JxWsQ>(L@sD_m^1|Ghy=7%F`wQ!Gaw=K485$;U2S%33 zcc5brynK+KPr93l_uZ&UV$#59D2;{^8AZovvKdV_qsfM(+IBR{jAoh9EHj#Ah-{n> dgW}>p!~KGuH6LP@)&jeN44$rjF6*2UngH}3obCVs literal 0 HcmV?d00001 diff --git a/test/src/components/badge/golden/label_default.png b/test/src/components/badge/golden/label_default.png new file mode 100644 index 0000000000000000000000000000000000000000..8f60d7c5148b4a8b3df55cac2513446ba3bcaa27 GIT binary patch literal 3610 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sOgBOi(^Q|oVRxjv+tD39RHY~q-B^ebwS7)izQ8bey?6#co1Ara9#bu zy|Y{G8vXq27^dqTU6?)B+1kQ`J4iN%MS8`L@&b;#LW=MASFFEYR$o{C-EzmndotzG zr#I>F=bgW^*Yfj^jAu_yZczNjpSDi+oXou$H*d#R^D;2ZPI&!dck0h?o42NKShiaJ zTuohi+V9q_(-{~()Nil-{(7tWhHdWlXa4;7drO;v;RcKK{(JTR4o&@@9(Tw3H?z&} zP@cRpImhHCCI8`}iLj8=K$%{k-zr ztIPRm_kO*2^St|d!MzO2_siP9r{%@k?|r-7o`FGR+jTi$c;@giGBGfuuy8OiOb}FH zU~q720E$Wy5WIPFuT61LP1VEI+OK;fPp^HQtsim!op!c914Dvv&i-%jZVCU;uekf0 zfuZ5Rx8w2aY#X=k{dw?AV}2t814oYT=}k5}Y>U4?JM(z)%*pE6{);x%8x+4Sc=qAg znS1|kWrG3>6#Uu!K&O~B*B=DB(1?kJf#C#)00V=9vIEfA9tOry!O;L2O$?(MVYFlz uEfq&=gwfh?v^E^A4M%Ikp;sGzHh(Ua{L{6Gi1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq{?5)5S5QV$Rz;`&UmbWjOxvz3uh*@RMsgJVZowHYn=+Qe<%rNQwT- zx^>$Yw_@+L>(=s`nu>^ByrLv@Lu8Vv%FK%aFP83^RpvkYq0o1?z4Kq}iMw6-!>;}O z;mCR4i>5vM{PWLretSv#y_HFSzC8_p{M~yxdw1gPhtA2*H~aVQzF$$RbHDWXm0|{l z2nO%f@8{2{|NqE4_TVNbS$S|=mFr45JU|>*C zc3@y==wV=FU@#&exH+}#_q&aCm0zE=7VqZsu}GJC-Y+}9>d=$4>N0;@MurAfgWGja z_N_GkAiv@7iNC@Apx`<4uIBC4mF5N;W&34hch9RVdL_xgpwnE!>%-}i3ZWAjypfkEuRr5d~W{i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sOhw)i(^Q|oVT}q^P*El8Xlfsm#q54{cTHEBC##=Y&t8_fYiF(fy?wjoR)4L! zbKk%D?uG~(DfZu|KmK@9aOU~v-1W>12l!^h#@_d80$|9J4|(W4P-!)D8Gi0Jw1p8jX{-n~G+ z+5Gw!Ka+btetCJ>aQ0cVdHeV5kqHkEmp(84{lkU#HYNW)d?=8Sm#^OuxAywu1ReP; z$_xxPR~|hsx2yZ{Z}-RBudhqXe|Y-&`Qz*1>+Np-dAT|L@t?D^d!HYdc)Wamy=1$) zyY%_}Hopt^*jV4L*teto^5x5gb#?zvmi>BlwEN>%^ZRu>zP;mTU|`LcV`gBGWMpDs zNMYe%V3;5Xj06X_24Hv-5}f(>-|_jE|NhwM_`mb#y`+tA zWq^e}DXT_iM!3>xb`eEIXd` zF+=8!{_)3?4;#*}mgQh*@Xt5%o%{&s5Fxp0a@|P0Z$?!T6X&C$G#W}|6cwY%W;EH1 vCL5A!*U>C9nq@|_%xIP&vN1lSi;JJqr(X3j^cLK@&j19Tu6{1-oD!M^ literal 0 HcmV?d00001 diff --git a/test/src/components/badge/golden/label_positive.png b/test/src/components/badge/golden/label_positive.png new file mode 100644 index 0000000000000000000000000000000000000000..711c83083b0b3a93d19c5023835ab4e4f99572ea GIT binary patch literal 3681 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq{?P)5S5QV$Rz;hO4KRG93T-e{Zbu*6x#{58ImBSoJ&uo;;bdCCs}y zz&T&>4XeeH3pb<-vNwty|F-(cC51_xt({IWo`$}N-+aN1cUee zKLv%~{{1|^{NBNqdr|eJIW;w9Hruz@d=+6}`1gF;`M5t-uXugl?7nT^mtX&@?v*41 zgHFTL)wB286hHi0%YJ-a?(OY0&F%GelGfX8?T`OFp8Qg5={P$>{?tJ~Y!+Xxp{9e1`@9+G_&#U*_)z*AHclP5u?ff%a1sNEg zZ7q8L@o>6cPEASKI{xeC@9#_g4!{1)V!!3L_3!R}`dR<^;ok$(=l9J1{yyjDpYZp! zR`=?DZbdS-_L!ZblWeaCPzD4;9ZZTwIyXz_5W~TH5BDZw`Gu{rJqWpM|NPkL~#V;^39p9WwVe z+xf{@S^3G^TV5+$<7dmx(7?LEWcJy#;C^7b5o@kL$V9rsiTC2DN@5biXef<_5*g*k zXtEhiHlxXgq$+nb%Zz53(JV8XWr%E{5B=ieGyl>2?)AxgN-i=0fv2mV%Q~loCIGd; Bs>1*P literal 0 HcmV?d00001 diff --git a/golden/arrow_down.png b/test/src/components/badge/golden/label_sharp.png similarity index 80% rename from golden/arrow_down.png rename to test/src/components/badge/golden/label_sharp.png index aa99574828a6aa4e8b76f44e1cb35ae22cefdb9e..ebfea1a74779972819cfc98d0e133fede230b8cf 100644 GIT binary patch delta 318 zcmV-E0m1&m9R3=RL4PPoL_t(|obB2%Y7}uChT&f%5fv4?2#U3Zr3Y{i;SoH97FM>N zAe9I4204X9uoML&L>vpd*z6GUF1XKA4u599>E>nj;O*UI8TQ_b*E5?pyIuhR!2j;X zt_J`B0Q*CL0001)!^;~C-v0c9Co}gR zuGkbj!^Qc`(e3No^!>}s*H7y<0RX^N{SzRsKCXL_{q}k0{-f(V|Lc6_aK(%G%*^|z ze}89NFF(vYe!l(r;u+RP%i2w6r!yy;b(;VH;Hvxu3zJa;H!sZL<0r8V2n0Tf z1`DLPt6#w=@EzEMGPuFo4s5NfQHGX;-%ER*XT2vk|D3$bFZbM>)#1CNqXDo`PoF;< zkDly~mwT_q{{H^#Ih+9pn#^rHqYkS<-ygqvlz%(lX0)H&k?|=R=w!XhPdj<>i z!On?B3wfFk<>3;NW2P z1QyEK1C~sH0001)bF&8ke2UiA*2cAK*N%PtYPA|;wHilJ0eFwkE?gMD{PyeY8K1PxuQtcqH*Y@5cb|p(|1s|mz-i_YER%r( zBY)ll0>B5kdiCn~{Nlx9U+=|y0E{6(0Qf*V4|h&Lk!`9c=$CZuC-uv0T+jqzPJ9pzn0Gvi1!2;k|?%%mP?%n=>WQY#{ zPC|eHaBTmL5b*)PNu8TL0D#lw-@ze105~cC0RaF2G9JMK001%q1ONcY2oL}OAhWIl gx(bs(0_+y^5BhYSD>+{u?f?J)07*qoM6N<$g0d_j`2YX_ diff --git a/test/src/components/badge/golden/label_warning.png b/test/src/components/badge/golden/label_warning.png new file mode 100644 index 0000000000000000000000000000000000000000..5b6326c1fa40cd7f3fd59ba49c12f311bc29cb78 GIT binary patch literal 3646 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 G2~7YPbe$^z literal 0 HcmV?d00001 diff --git a/test/src/components/badge/golden/priority_pill_low.png b/test/src/components/badge/golden/priority_pill_low.png new file mode 100644 index 0000000000000000000000000000000000000000..ebdc35f8cee5e380aac8e36be8d18bf2698b4ba3 GIT binary patch literal 3869 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefr0P1r;B4q#hkZy@1MR`Dtr9n_gd@cIYEs#mpnU_q^TXeaMqQk1+0P{ zFAIYtD#9jctl7U{fx!m8MZ(fUS*1j~b-TkR+)&g0bUa2q@?g?g`EYmM7>(rE z@5W_cE9TV4?eU+_9=|WU`)HD3dS&6qOEwj6!i!)0xM*4P=*FLCN95CUb93`{e0sIB z@b>Mr@3Ze2n(zN>TYT}>ubcji3=DA>Z{1}4bR^#Y%v=7t)VhyfCWhDUsQzvG`M}xv zv*)hgU*ycs!oU!A{4~>(*Zcooyz}?N-{MbSRu)(7Dg8WcXZic(&(FQK-;~JC#K5rn zu}?$I*AM*9HrxL>R@r;!`$g;L#^!Z7E8BtgtWK{@d-kIE{JDMZ-{yZm0VK~~d_FJs zRv-hzfvl+Nk4vYEz5jo0pYi>gJ>Mo>Kht=7e}P~BcbgACfBv@rZ)j|6p1VJ-?q8?= zxnH+#waIcbFvQ$2leMXPk}5wZeplw_nDV31=U#qXI@@eM=LBbe`I*hf`_Hi7t9jcd z1B|+uAJ_Qh{{OvnY}!s%28K2BzRv&ia^uoo*{WwRE^T9AXt=uh-;0k=T@NolK0o4? z7z4wGs%gKpKL_j2iF+mkmOf5@bYhL+mjIimCC=nv$`yH ze!gw4x$Z+128M*t++A-T>3)72{chIxyY=7a)O~EV{P|~P<%=8Z&%gY5 z^11)nGiRQ4o1HDs-~>ToVIEYudBZ`~Td#^ZA4M`Rpg&)%K?4`@cW- zw&h`9h_Fp(N=bW`-7Y_?*8ZNoy8nEu<;U0G-cig^O%T#>2`hUW{^yAjgt+(GXy{*5y1{%rrEGPEc{+piuY`Op6yt;2sl8Ya# zJf6NW;>CbP!!WbAHFn#Z01V;OYoY((fGXq2MzdRE#shr>t zU|>*C2HM-u!vKtUqfx=p02xgTqZwheWEd?KM{9)9+HkZs9IXvUYr`Q{8-CV*_U3SZ U+xDySz%DL>r>mdKI;Vst0611Fb^rhX literal 0 HcmV?d00001 diff --git a/test/src/components/badge/golden/priority_pill_medium.png b/test/src/components/badge/golden/priority_pill_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..c56cd408ade3a3166ef2e475ef9f4c52684557e4 GIT binary patch literal 4071 zcmeHK`BT$J6yIwg$D5dtIfTIwIK!UaykRt<(FyRPy!j(q&N@7R?T|52}{UQ6yzI{8p@9k$l`#!VP zpGJqFElyeh0MHTPA+Z1$Is;&E#moeHSk%gV*rCX=VL_mM++hTzK%av3c>rO4| zvv5nDp-HHn_4^jKM4O3F!kzferUX>H)>x5|%Ny?Vjh-uPaXtM1(+3CCmKLu^7 zE>ZF-b_#%sOXA5I zc1A<92cvFc*|FQu38j^_Hoq!38_(7a3_^&kBZV4r=oxfR~=>J$*^z3Suw0CBw;kvto zd(IFADvr;3p$cSGtzl1Nq^W65Px95jQ$ zWa?VCk?JJn=yDhO6dDFe^A?TH7tQf`vSk@QpRR1RMS4X|Wg)@X{^bc;`nq_fN7Eck zUd_=+AJsR}Pt?OZXK#2b0($VNhnsh?uUBtR)k&i=9mQb*+`L3q7)LdiKv%9M7Y=i2 z`|%xv1`x#;DWs=#}42x4tujUeFg zIlq8!%{gM51Cakk;`~vFoiiq2Gwuo;ew2jkoFqI6b|LOSS_zv5k2G*u#Ua`)eyCFVcwd3lu|2)Ft)_KdN^7yD@9gB)5GUBi2XtAKmr zH19nvWD9VM`~u-Kt5lYHJkI}b2#kl<5yfDy^OROSkX(XrTJYv#Zr}OtWDQHbF&FLs zhc9H&@TxJ&(+d#_I>zHJ$e99s@ms#}_8&Wvch%8&2u!9<1ei?UPH&`bPBk_|=X*lt z(+Pi3IlL_XONkuWENsO8Q1;3JfFh0^`p&OyP8{`qS`tn1#P85J89zX%9-P F{1>QCmfQdU literal 0 HcmV?d00001 diff --git a/test/src/components/badge/golden/status_label_custom.png b/test/src/components/badge/golden/status_label_custom.png new file mode 100644 index 0000000000000000000000000000000000000000..7e5e24dad2966b316bc86fd68e067d8750210382 GIT binary patch literal 4555 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 literal 0 HcmV?d00001 diff --git a/test/src/components/badge/golden/tag_left.png b/test/src/components/badge/golden/tag_left.png new file mode 100644 index 0000000000000000000000000000000000000000..4ac7894a6e5c3c066c0ac40c5d1f234eb2c9cb83 GIT binary patch literal 3634 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sOgTUi(^Q|oVRx!^MunS8Xndk>r1X`-?UIY(bqrvnx*H>3(5+P1v&oa zIsr@78ZFj)ezJM}({%oxS>dyO+T4A^fBM}si@wuFajWj@T~D63ytto{f#LkUKbIaS z_ZaSb^G*MsIRit(p*IJsdr~DI|9YMHLzRKyLE+iwau31_W2P1UEv5ynXl2m(npgddJR6p3gTEfBgOW`uDYe{}ssW{%c~E zoeT8la516&__fbj85)9x6t+hk+x~Tr6bl1`pHst~hdXp0 zpFUR=$G~90%2>qj{<@Np;eiUv3EQ{)$2aa4RAgZIAi(s5{mr-I#r?p*^`FH6^u7^L zdPVHolLi{s4y2WC4Zk zGmc5zK7Dn@vSNQGU??^->^%Cd$TsaO&`kB>^oBLz{MCOmsva=^aX$b5&7a$6v(}`2 z1j;Qp0R}+yIol)a(>Bk`-NVGt;Ql~#&Hsq?N7xw{Y{VEp&An>V`_`?7f#E>1pu+t# zmrb@!zxI|1$eWd0DV02H-`d-@-xYw)J9Bn+_s^s2XVq@qm?zG_z;$_(&b9=g1)TRA zfS!|N1Uf2(1sH-81c9m@+(rdQ17tKYjAn$9qPYEaLti1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sOg}mi(^Q|oVRx!i!MiqI9$}X^gE$6i*v8gu`gM(3&Sq?yl{1RbR@|^ zG}PpVMOjg-?75jyMSEZBzO?r}y-DY>!|dO0cigp+sruQyW!Cb-+S0;zh71f3>ND-W z9BP02>GpAU28M!J%}gn~V~;(*{rmYmRtAQOhjo$)r#JQZm-9b<@O=x=QDrxz6;4aU zKYsinSqaFserxOd_vg2|obCPH{q^>BGUes77qdsjuRH#%=X-qIy5sWeVLkB|!blP2$&vC!6{|pU2F=@PqeEa?i(CuaeFvu>e)4 zeU?b}N$z=l`sxfdK_;Nd^YhakmSz5uQhYuK7&jFc_gS~toxfaBT3Wa+5@?qAyLR1( z)s<4=udiCBF)}d3?U=vrVQl=F callbackTriggered = true, label: 'Test Button')), + ); + await tester.tap(find.byType(ZetaButton)); + await tester.pump(); + + expect(callbackTriggered, isTrue); + }); + + testWidgets('Initializes primary with correct Label', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaButton.primary(onPressed: () {}, label: 'Test Button'), + ), + ); + + final buttonFinder = find.byType(ZetaButton); + final ZetaButton button = tester.firstWidget(buttonFinder); + expect(button.borderType, null); + expect(button.label, 'Test Button'); + expect(button.leadingIcon, null); + expect(button.trailingIcon, null); + expect(button.size, ZetaWidgetSize.medium); + expect(button.type, ZetaButtonType.primary); + + await expectLater(find.byType(ZetaButton), matchesGoldenFile(join(getCurrentPath('button'), 'button_primary.png'))); + }); + testWidgets('Initializes secondary with correct Label', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaButton.secondary( + onPressed: () {}, + label: 'Test Button', + leadingIcon: Icons.abc, + size: ZetaWidgetSize.small, + ), + ), + ); + + final buttonFinder = find.byType(ZetaButton); + final ZetaButton button = tester.firstWidget(buttonFinder); + expect(button.borderType, null); + expect(button.label, 'Test Button'); + expect(button.leadingIcon, Icons.abc); + expect(button.trailingIcon, null); + expect(button.size, ZetaWidgetSize.small); + expect(button.type, ZetaButtonType.secondary); + + await expectLater( + find.byType(ZetaButton), + matchesGoldenFile(join(getCurrentPath('button'), 'button_secondary.png')), + ); + }); + testWidgets('Initializes positive with correct Label', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaButton.positive(onPressed: () {}, label: 'Test Button', trailingIcon: Icons.abc), + ), + ); + + final buttonFinder = find.byType(ZetaButton); + final ZetaButton button = tester.firstWidget(buttonFinder); + expect(button.borderType, null); + expect(button.label, 'Test Button'); + expect(button.leadingIcon, null); + expect(button.trailingIcon, Icons.abc); + expect(button.size, ZetaWidgetSize.medium); + expect(button.type, ZetaButtonType.positive); + + await expectLater( + find.byType(ZetaButton), + matchesGoldenFile(join(getCurrentPath('button'), 'button_positive.png')), + ); + }); + testWidgets('Initializes negative with correct Label', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaButton.negative(onPressed: () {}, label: 'Test Button', size: ZetaWidgetSize.small), + ), + ); + + final buttonFinder = find.byType(ZetaButton); + final ZetaButton button = tester.firstWidget(buttonFinder); + expect(button.borderType, null); + expect(button.label, 'Test Button'); + expect(button.leadingIcon, null); + expect(button.trailingIcon, null); + expect(button.size, ZetaWidgetSize.small); + expect(button.type, ZetaButtonType.negative); + + await expectLater( + find.byType(ZetaButton), + matchesGoldenFile(join(getCurrentPath('button'), 'button_negative.png')), + ); + }); + testWidgets('Initializes outline with correct Label', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaButton.outline(onPressed: () {}, label: 'Test Button', size: ZetaWidgetSize.large), + ), + ); + + final buttonFinder = find.byType(ZetaButton); + final ZetaButton button = tester.firstWidget(buttonFinder); + expect(button.borderType, null); + expect(button.label, 'Test Button'); + expect(button.leadingIcon, null); + expect(button.trailingIcon, null); + expect(button.size, ZetaWidgetSize.large); + expect(button.type, ZetaButtonType.outline); + + await expectLater(find.byType(ZetaButton), matchesGoldenFile(join(getCurrentPath('button'), 'button_outline.png'))); + }); + testWidgets('Initializes outlineSubtle with correct Label', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaButton.outlineSubtle(label: 'Test Button', borderType: ZetaWidgetBorder.sharp), + ), + ); + + final buttonFinder = find.byType(ZetaButton); + final ZetaButton button = tester.firstWidget(buttonFinder); + expect(button.borderType, ZetaWidgetBorder.sharp); + expect(button.label, 'Test Button'); + expect(button.leadingIcon, null); + expect(button.trailingIcon, null); + expect(button.size, ZetaWidgetSize.medium); + expect(button.type, ZetaButtonType.outlineSubtle); + + await expectLater( + find.byType(ZetaButton), + matchesGoldenFile(join(getCurrentPath('button'), 'button_outline_subtle.png')), + ); + }); + testWidgets('Initializes text with correct Label', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaButton.text(onPressed: () {}, label: 'Test Button', borderType: ZetaWidgetBorder.full), + ), + ); + + final buttonFinder = find.byType(ZetaButton); + final ZetaButton button = tester.firstWidget(buttonFinder); + expect(button.borderType, ZetaWidgetBorder.full); + expect(button.label, 'Test Button'); + expect(button.leadingIcon, null); + expect(button.trailingIcon, null); + expect(button.size, ZetaWidgetSize.medium); + expect(button.type, ZetaButtonType.text); + + await expectLater( + find.byType(ZetaButton), + matchesGoldenFile(join(getCurrentPath('button'), 'button_text.png')), + ); + }); + + testWidgets('Disabled button', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaButton.text(label: 'Test Button', borderType: ZetaWidgetBorder.full), + ), + ); + + final buttonFinder = find.byType(ZetaButton); + final ZetaButton button = tester.firstWidget(buttonFinder); + expect(button.borderType, ZetaWidgetBorder.full); + expect(button.label, 'Test Button'); + expect(button.leadingIcon, null); + expect(button.trailingIcon, null); + expect(button.onPressed, null); + expect(button.size, ZetaWidgetSize.medium); + expect(button.type, ZetaButtonType.text); + + await expectLater( + find.byType(ZetaButton), + matchesGoldenFile(join(getCurrentPath('button'), 'button_disabled.png')), + ); + }); + testWidgets('Interaction with button', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaButton(label: 'Test Button', onPressed: () {}), + ), + ); + + final buttonFinder = find.byType(ZetaButton); + final ZetaButton button = tester.firstWidget(buttonFinder); + + final filledButtonFinder = find.byType(FilledButton); + final FilledButton filledButton = tester.firstWidget(filledButtonFinder); + + final gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(location: Offset.zero); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.moveTo(tester.getCenter(find.byType(ZetaButton))); + await tester.pumpAndSettle(); + + expect(filledButton.style?.backgroundColor?.resolve({WidgetState.hovered}), ZetaColorBase.blue.shade50); + + await gesture.down(tester.getCenter(find.byType(ZetaButton))); + await tester.pumpAndSettle(); + expect(filledButton.style?.backgroundColor?.resolve({WidgetState.pressed}), ZetaColorBase.blue.shade70); + + await gesture.up(); + + await tester.pumpAndSettle(); + expect(button.label, 'Test Button'); + expect(button.leadingIcon, null); + expect(button.trailingIcon, null); + expect(button.size, ZetaWidgetSize.medium); + }); + testWidgets('Interaction with button', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + await tester.pumpWidget( + TestApp( + home: ZetaButton(label: 'Test Button', onPressed: () {}, focusNode: focusNode), + ), + ); + final buttonFinder = find.byType(ZetaButton); + final ZetaButton button = tester.firstWidget(buttonFinder); + focusNode.requestFocus(); + await tester.pump(); + final filledButtonFinder = find.byType(FilledButton); + final FilledButton filledButton = tester.firstWidget(filledButtonFinder); + + expect(button.label, 'Test Button'); + expect(button.leadingIcon, null); + expect(button.trailingIcon, null); + expect(button.size, ZetaWidgetSize.medium); + expect( + filledButton.style?.side?.resolve({WidgetState.focused}), + const BorderSide(color: ZetaColorBase.blue, width: ZetaSpacingBase.x0_5), + ); + }); + testWidgets('debugFillProperties works correctly', (WidgetTester tester) async { + final diagnostics = DiagnosticPropertiesBuilder(); + const ZetaButton(label: 'Test label').debugFillProperties(diagnostics); + + expect(diagnostics.finder('label'), '"Test label"'); + expect(diagnostics.finder('onPressed'), 'null'); + expect(diagnostics.finder('type'), 'primary'); + expect(diagnostics.finder('borderType'), 'null'); + expect(diagnostics.finder('size'), 'medium'); + expect(diagnostics.finder('leadingIcon'), 'null'); + expect(diagnostics.finder('trailingIcon'), 'null'); + }); +} diff --git a/test/src/components/button/golden/button_disabled.png b/test/src/components/button/golden/button_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..fd36246939e4b5cbfb5be99cf4c3ca1cf4dc7839 GIT binary patch literal 4266 zcmeHK{a4ag7{7{|vzc|8rDnqVp|ul7@^p$ydC}a|%vvuqUA}bGNt$G&CNUDrZPrl_ zZ8bH)*2!k4nTn&7LdE6+ni(@vA%!o5;fxniMBWtkZTk!MJNJkC+~@PdeV*q&FQ0R- zd~qNlFd!@d01%jz7=IW51PTD}G=D!BX*zf53@p4#4kyHcju+uGu;Nn^mvq!0UUdJw z%K)rCniL;hqB#2~$W01*4H z1^~t787{V2Xc?J`+BO}lE2G0TD=FMDcBdL79)IGt)rB1>EcH!r9qDtK2aK}6#BMxHTG_i7ogVTw-Qs^EY$LI zQ7>L#s((q3@f9UFH49TG(b_m4aBHC)5l=N;AI|4e=nn`7vcdz_fJ*Tvh&-;mcDz{0 z)&NDRf*i(+imHEPq+aZq9x@T}3i1 zy&0sMjr56J*hV_RPYj3H3H3r+v}sH4g>rlcZrTs1VwXZt#ZWWfwb2C~C&dB~@kdT= zRQ=E>DU!O4kQ?>n$Hw&a=#;lC2Ivwk+Op!k6C<$$TS1f1u?jgbOIujhCkq%gPwD7}9=9E;cDp*=;ngdg1gBNmAC1fw>8I_APxW|t3DaYQ5{Jwm)U&5fM_$UNXK+_DQN&$Pd*+rPpZ=YLc(WK z6QsU3W_pz(E!ux=-wMFPNa>M8)e)aPU|_jPYqocjDie}#!5(xLkVsvIP}Rt5g+jjQ z55U1cOR1cm_sAX@r1%ecz-?qUe>cQY6~hBEx-i_E8waVYWu_{21zSf#WPMApocWIG*x7Y zH&ZyG?zaIz1q5RV?gC}%;;C)I#^HR;+h-%)A{hU%;=`*2O?8;;e%Zg36oU&}Srhuc zZnAM-8~#4SVE68t97A);5~`h=DVf^~R94TA5XV%8;0%c1E`5e zUvWq--SVy!t&NOT+Zzu`ZH~4hr^>xRgsjMXMZt%gy|=<#0oU}{_SknP7{&DEcky(% z{qdnF!memRI3&QgX)nGSy4FG|)C2>fmW0TwjXGW5HfPl5u(RnVPTb9J2dnz#=BLD5 zJODXA2crmS?PD5)+)iag#@j^OS<9Rm!%2M_cO~Ei3$_qlFGnrIJRUFX*f=(~PhM-G z;o!_}Qy+reYiyM_wif7(kwWzor3{)-EW!zwDBBV66jC)fp6%#`hf+{%CA^1vc>|E= z11Iw88WaG;&pn{$K|ICaX#~$?@JvMyBY4=*!-gI<^swRoW<%HdBA=f)dv9EZzgGYx NeRd$eBkshde*hlu1hN1C literal 0 HcmV?d00001 diff --git a/test/src/components/button/golden/button_negative.png b/test/src/components/button/golden/button_negative.png new file mode 100644 index 0000000000000000000000000000000000000000..b0283c1eead01c7478839b90a74542bf867b91cd GIT binary patch literal 3720 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq~D+)5S5QV$R#Uw%K<}W!fL!xAeSnE2GvSr}!J`MwA3Rgy+sAOxQCv`zm33>k$n9SfZq4{J*P6p}>YaN2z3X&8oIUxx z#rTQZ!xTf`%O*fenNIIy2U6zzj7$s+DJ&ce3=;$u7#JMf8i1mb2*H~&$vyY&e`Lhi z{QtJ&+f(z$4=z33Y5viE^Bp_OJj?GdcKn_yethNgc{8i|7#Om13ZMSvUp{|+UEVv{ zHJz8=@3DMWb@DYULxc3@9}iD1U$)oZZgw?$cGBxN?d#v0H3@11Q7#I|k9T*rI zdKefP7>s6LuiX;UC+u&t?-H}jyI9%N!rNtk)@|HqxU9K3dH4QrU&|jqxbE$~@4nS; zYqRrr>Yw~RZ2$e(r*FdU`{bpilh!;Uu28Iv$ z>$oSJoqPH5!G8OgmyFByu1?-~i2uOlfBzzKa%FG-)n7kfUi^N=>l5Ft-|yWWRPy$J zNn(!ehT;Y8#8|@}T~I8(_xG}$?i=Fd z_I)^d!>0KE9b;gKIM*@bjJ|27gUiqDZ7kii(QsOM&iTDe3=O7R_k6vhT%4cKoAdTv z&(m)wccwEiY*;q!`<`#F?np-{f3MmL^t8Orvdmd^{~s(a{P^eg<6G13_cVJ?e}3=C z|1(9upX_*gXYu2A)8i$U&#NzcXUV{@X5-+#hZzy$O`k8JPZPJrkEF{%<i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`$cr;B4q#hkad&v)M`mp%UR{29MZcXNW0CoDPIz4ymrcGqfwD^&rv zocD4wvhv$j1bzrGP|t4_JJ|f+(N*B1(h~Qr0UusCdf0lbXrH#tWSMVH-J86!eg9a! zW^kTAIpO%@e{ykW-aPy*la_wj#J7G=QTd)<)1x1s`tAPs*xgKq|F{30yjk(_hUsecRp`+WoYVCHKGcYJ9J1{Ub^e`|oFc<+v8BTBr;1xWRH23l2rxNw`?=#jis+Xlb zeo+zi^WTdKDIi;Vcm1n7=PY(_uR6ZB_;E$ekCR1Df8RZtBXcME`CsYBN6wvko_&A) z@1Oe14Ud@|tLdHc@6%-UV|^m*3?6Gl73A+l^{xN=>Q)r9-DZ3F>v?PcG5q_Hyt(l6 zyI1@hUf=uw?9t7S&FSC5_Wl3)`oHARXb<6lmz%U_x1ekoi0eBX7wd3V3?Ffe%7u-vz2W?<;&Vq{`qNMYe%V3;7N zz`)?()&NYok^}^2&bKy||G#hVoiBVhyyWlBJhn4>uN%^yF_x04LFvyd`>?*~qneFVdQ&MBb@0Il@$*Z=?k literal 0 HcmV?d00001 diff --git a/test/src/components/button/golden/button_outline_subtle.png b/test/src/components/button/golden/button_outline_subtle.png new file mode 100644 index 0000000000000000000000000000000000000000..536c285b10c71b4a7ab8eb5fe3f970f3bc40f47c GIT binary patch literal 3555 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sHxY}#WAE}&f8lX^ORFX8ZO@dmJ(T}tfc){tfPsk(|p0=2OB4@(9p>E zChHK^Vs>+b_oIiBMt%D@f6Td6{;X=*%=7ck+MNFkG?*jjdK{3lkY{3HU^u}cz`&qj zeD~h}&ENPwEZV#8MsMb&R}2j26Qz=S4nItLYx}_U*8BCxBzAAT&cN{F{)f$a3=9(l z6&M&C+!}zUNHQ`pFr=_>;1ZlU@6*G|dB-0E%L@#Dvje!l&-Ovb;0!M^n0@Avy;@7Mgz`}ik+|9<)U zKa~+S^_4%%?%cblJ1_qCFW<{~Ha0r@|DS)jT)ti+e_zesS9}Z%&rfMb5bGrZo}a1C zdg7U+-;T<@<~bYx|9cw!UwX}cMur1FZ`J(xQE4ZWckLc?+>*clviAIZl;ktno|}i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq|dV)5S5QV$R#U{vC75B@cYOe=cuZws3A%^x~-zx17BXuq|ePy_G$a zRghIbPQ-t!>#McX<)U-_<%`pt)$<*_=+kCd$vsr&nd|Fvrs@?qa>eEG4T-r~#Rm>Ckz{}9t*U{FwYU|?wIVPIrnFk)h1 zU^ubHcP~TCdb{fP&5sZA-`{=V&CBiQd+yJ-tnD>tV%YJKQ=mfL{@{ol3e z&7aTvfB&rbw%tCu;@|T4Kj$pUUNp8ozi(BaS5xx;VC(bk&#jY7Q#(IzfAVM3`u|%$ zT|`-nKCrYp4XpnQ1r*O^>r5ieyrag z`^|8^RmuN~r?c<(n*qbb@F&)QGI`qj0_K!J(dL-R~*W?$#}kg?SY>W?=02k z$A6O1v9?#U`*-QH_q_kv52OCbGBa$LG4nh9*v@vpi4~YPSU4CMCI~73GmcvWP#BV7Mg>O$WHd31 z=8n;lVYE~ntr13R!_nGsv^E^A4N0yIpVd!DIdv{*B4Z3N`7n68`njxgN@xNA2$B{> literal 0 HcmV?d00001 diff --git a/test/src/components/button/golden/button_primary.png b/test/src/components/button/golden/button_primary.png new file mode 100644 index 0000000000000000000000000000000000000000..c2dd825ee514cdc79809381d995c3a9eddb8ec4b GIT binary patch literal 3720 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq~D+)5S5QV$R#Uw%swQ5)BW_)6~~_UOTVU+0oG}v_Wu7fVOn?#!W#R z1a)>g*@ z*6q6`o}XWHEc*O>x%GCnMej-(7~W}g`|sarw)e}&^~LWQk6&`vzi)o8;@g!w*$fPK z45!K0ZMFZ-SCF&Qj)7rY_RqIZn|GEsB)|Tx-TwId>v$P$-@g-c(B8^M>T&<< zb%G2HxgSMzfNoHBU|?wIVPIrnFhV#CEO_QsS>2B#=Opy)_U*pNxL)4p@w=-@Z-3ss znsmn^;{V1Kv(MH4J-qhg<@fH{=j|)=Oyz15(%=5H&-Z(LCHDW_@A;QM@Bd{zlmD7M z>*LSw^LnD&U!P}Y*s$+5*M#G8F}>XD?RQ*c%$M_fyl(E-dfO-D4y;6{Qm!> z`aQpIUfufKzVhk6k5>+>Uz_*;=c|hr<>!CtC%glj%j;kB zq_A)>Fia3sU|?`?YXF9`BqI~)f;-nTSk5xDf3W4@`x_;#|9|~i_UvB$yX*GH%Kr5+ zGDMtD+VgkuZNnep_WR1qY)aPib2Bn*I~XfU*y5Q_Ys>YY-DB)qJNK!?_cy!TfYFp% z`R`5EJJ|;}s-FCtyHOn&58Kjyp5v}Ae$Q}x+G}QpgxzA7O?<`m?n=nl?6lX5vy%v4 zCwq3U@R_Xqa>H};BYVx~TieD}KYMcLH82eXf)p3)1LN_JeFc{oVJDFlKoo}WsCKfG z=4jB31|1nC+Gw&FO*W&+X0$e>q*XLphK!aWqh$z688UM}!!xF7%-2(-lNo@()78&q Iol`;+0AjL|y8r+H literal 0 HcmV?d00001 diff --git a/test/src/components/button/golden/button_secondary.png b/test/src/components/button/golden/button_secondary.png new file mode 100644 index 0000000000000000000000000000000000000000..22ca24806bd37491e6de4f2a87422efdc3ffaf0a GIT binary patch literal 3865 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefr0O^r;B4q#hkZyZ9ATnGq!)cf974<)jMwsJKg+y=D8{@UmzA}IJN86 z4GC+<4@)~&q%I2GB@%eSYr_TsYiq}KfhxB&p6IB~apPR%Xk&VBZu`5tZ{PN{Zivvi z=d+{o->&aJr|jN8^XEB(vxoPb73)5l1aiT%V16L=PL7F%f#C#)00V=9vI7G{Lk|NZ z1A`GlaI@tx3H>-5dp(=qXDWVP`uzCVyQwS93#Z?_WoP)V{=uD!?~CJQ^6Q^m4nEJw zkkFg9|L4>1;`Tq@B?rH6Fgzw9|L@55W7hZo|6G~Qz_3B>bNrt#tAq0!oW<)N{p4UM zm~-}j*~>>)q#s<^y1HJ%eEt90SCR}2Yfk<-_7$wGyZP_N^3U?Y=NT9hd~3MH7#Jo9 zDljlOqLqi{96~ z&3*hSK5mEdVxadPzdXSZIsImi-MtUbzOOBr8C|_Qx%l-}@A>o3n;kotRG<4?|NqbM z$G_e^U3&ig96RfGcP%%6`5A5g-_q=T<=IQmpMUNxEZA`9Z|uiE|L(oJ5%KWj{Imc5 zuG@F?QNqj9e_nn+zqUkg0VJw{H7v|NCL^|qjS2G5NANLKk^mVx0w?1K~A6ZTGuU;54a8j$-|<|o&Q zsr&zx)jU2KxtA3foX=`Ffa*@1+4t{AgpV!LzsryP{}$faU7QAvsm5?@i3XgK&eZ%4 zUB2udLwg!9%+7y12~7dNVY>gTe~DWM4fSynd{ literal 0 HcmV?d00001 diff --git a/golden/arrow_right.png b/test/src/components/button/golden/button_text.png similarity index 79% rename from golden/arrow_right.png rename to test/src/components/button/golden/button_text.png index 30d99000c0bec9ab95a4b899e8d2f3732b6d8e53..7276f3b31fa8d9e538d1b575cf517237ca5eabe8 100644 GIT binary patch delta 422 zcmdllvsQY7V^FxKi(^Q|oVPcuyF>yR+Ac=l?c;ZmbO|uN+t4}FTJTQy4zY_%C8TyR zF(-=f);vm{qqqG*2yZ-hvEQBg(2G|O{;itzyi$&VfuZs2K6xNzVLw@s*`CQ)f0uG!{_!>a z?055H2g^Rze64%?`~KPFp30uHT_yYKpC{xjHD@>w=kwX-|L4pPcdy^w@%hW&RnqtN z?2?qKci|Nr2B1_Q%`Jp!8p jnQw4Sc3?gvHgkXdmY}0s4?Rc)s$lSR^>bP0l+XkK-Ymcd delta 587 zcmV-R0<`_D8^0WoL4WBYVP%C}iGvWgPVBQ4C zhHl@veX8rdXm2y(0{~#&Jc0!P0AvIR0059#yz}n%YU&ZNu4lg;PCWqtfDJ6qojW)6 z23U);3IH&F%ZuCFQ*VH^II92v^S8YI>HgFkU@gun0Koh$PF}254<0=nckkaDj}M=W zqobp#HzdJ-wzjs$<%^fbjcfbk>fV*9=Kuh(p~cCIl^>x4000Sp!wa*q0_F;nFaqKh Z=3lMPo_YzgNm~E_002ovPDHLkV1lNYC3gS- diff --git a/test/src/components/checkbox/checkbox_test.dart b/test/src/components/checkbox/checkbox_test.dart new file mode 100644 index 00000000..c9926017 --- /dev/null +++ b/test/src/components/checkbox/checkbox_test.dart @@ -0,0 +1,143 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +import '../../../test_utils/test_app.dart'; +import '../../../test_utils/tolerant_comparator.dart'; +import '../../../test_utils/utils.dart'; + +void main() { + setUpAll(() { + final testUri = Uri.parse(getCurrentPath('checkbox')); + goldenFileComparator = TolerantComparator(testUri, tolerance: 0.01); + }); + + group('ZetaCheckbox Tests', () { + testWidgets('Initializes with correct parameters', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaCheckbox( + value: true, + onChanged: (value) {}, + label: 'Test Checkbox', + ), + ), + ); + + final checkboxFinder = find.byType(ZetaCheckbox); + final ZetaCheckbox checkbox = tester.firstWidget(checkboxFinder); + + expect(checkbox.value, true); + expect(checkbox.rounded, null); + expect(checkbox.label, 'Test Checkbox'); + }); + + testWidgets('ZetaCheckbox changes state on tap', (WidgetTester tester) async { + bool? checkboxValue = true; + + await tester.pumpWidget( + TestApp( + home: ZetaCheckbox( + value: checkboxValue, + onChanged: (value) { + checkboxValue = value; + }, + ), + ), + ); + + final checkboxFinder = find.byType(ZetaCheckbox); + await expectLater( + checkboxFinder, + matchesGoldenFile(join(getCurrentPath('checkbox'), 'checkbox_enabled.png')), + ); + await tester.tap(find.byType(ZetaCheckbox)); + await tester.pump(); + + expect(checkboxValue, false); + }); + testWidgets("Disabled ZetaCheckbox doesn't change state on tap", (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaCheckbox( + value: true, + ), + ), + ); + + final checkboxFinder = find.byType(ZetaCheckbox); + await expectLater( + checkboxFinder, + matchesGoldenFile(join(getCurrentPath('checkbox'), 'checkbox_disabled.png')), + ); + await tester.tap(find.byType(ZetaCheckbox)); + await tester.pump(); + final ZetaCheckbox checkbox = tester.firstWidget(checkboxFinder); + + expect(checkbox.value, true); + }); + + testWidgets('ZetaCheckbox interaction', (WidgetTester tester) async { + final FocusNode node = FocusNode(); + + await tester.pumpWidget( + TestApp( + home: ZetaCheckbox( + focusNode: node, + onChanged: (value) {}, + value: true, + ), + ), + ); + + node.requestFocus(); + await tester.pump(); + + final animatedContainerFinder = find.byType(AnimatedContainer); + final AnimatedContainer animatedContainer = tester.firstWidget(animatedContainerFinder); + expect((animatedContainer.decoration as BoxDecoration?)?.boxShadow?.first.color, ZetaColorBase.blue.shade50); + + final gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(location: Offset.zero); + await tester.pump(); + await gesture.moveTo(tester.getCenter(find.byType(ZetaInternalCheckbox))); + await gesture.moveTo(tester.getCenter(find.byType(ZetaCheckbox))); + await gesture.moveTo(Offset.zero); + await gesture.moveTo(tester.getCenter(find.byType(ZetaInternalCheckbox))); + + await tester.pumpAndSettle(); + + // TODO(test): Luke hover state on checkbox + // expect((animatedContainer.decoration as BoxDecoration?)?.border?.top.color, ZetaColorBase.cool.shade90); + + await tester.tap(find.byType(ZetaCheckbox)); + await tester.pump(); + }); + + testWidgets('debugFillProperties works correctly', (WidgetTester tester) async { + final diagnostics = DiagnosticPropertiesBuilder(); + ZetaCheckbox().debugFillProperties(diagnostics); + + expect(diagnostics.finder('value'), 'false'); + expect(diagnostics.finder('label'), 'null'); + expect(diagnostics.finder('onChanged'), 'null'); + expect(diagnostics.finder('rounded'), 'null'); + expect(diagnostics.finder('useIndeterminate'), 'false'); + expect(diagnostics.finder('focusNode'), 'null'); + + final internalDiagnostics = DiagnosticPropertiesBuilder(); + ZetaInternalCheckbox(onChanged: (_) {}).debugFillProperties(internalDiagnostics); + expect(internalDiagnostics.finder('value'), 'false'); + expect(internalDiagnostics.finder('label'), 'null'); + expect(internalDiagnostics.finder('rounded'), 'null'); + expect(internalDiagnostics.finder('useIndeterminate'), 'false'); + expect(internalDiagnostics.finder('error'), 'false'); + expect(internalDiagnostics.finder('disabled'), 'false'); + expect(internalDiagnostics.finder('focusNode'), 'null'); + }); + }); +} diff --git a/test/src/components/checkbox/golden/checkbox_disabled.png b/test/src/components/checkbox/golden/checkbox_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..0ecfd7bfe7a9772b392f09ff4babddb4787ff4af GIT binary patch literal 3539 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sHxV|#WAE}&fB{OyF}a>8Xmq0}b4~d1-apS7ejcwX zE&lW8@?P%aa<+9=_j1a;bAcLS0=rpH^h(F~zkgp-{_w_T`+3|zPaUvTU|?`?ZvgsN zk`d^P6c(T{69hqmX&Zw##ObP0 Hl+XkK;n`SB literal 0 HcmV?d00001 diff --git a/test/src/components/checkbox/golden/checkbox_enabled.png b/test/src/components/checkbox/golden/checkbox_enabled.png new file mode 100644 index 0000000000000000000000000000000000000000..eac35ed1ae4dbe7bbf92ec42c8b2286d0e5e1235 GIT binary patch literal 3597 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sA;>Wi(^Q|oVRy3u99_SXn1&2CC*@8g93}rr5j5(Zxm256Z*c9KSX3os5PfIJG^}JFJ zXjx0^GEC1x+qyt8AQi_a z;DfGR)7Pv1{9)05&h7pBjERAP@BSm@h}-S{c{BEW{g!_H+{p;)hB|qO>9=}%u=v9XQj6kniVfE_jTGrQ7wa@ps&)>h} z^Ua-^YeRuSb2(=#gQRl?NN3)x=c)gd=iBYr|BCxe{F{5GK$FhNm4gEC%p-=GVK!-7 zpT#gR9C!$H@$AK4S0$d^36wg#-NNBs_1m3S#p?gxswxKRY0v+t`o-|rj<0viYJNU0 z%lSX+_@#rFO^z)E24zL9vE9CXk-JQQLD}_IQ~_x3?+>CnBt?`m$VEg&>8MI#68>l? zjfN5#<>hFy8BI2$$!4_X8m)^7HZ4bs%F&{7C>NFW%=eB(mqdIC2KE>j7(8A5T-G@y GGywo1G<1ys literal 0 HcmV?d00001 diff --git a/test/src/components/dialpad/dialpad_test.dart b/test/src/components/dialpad/dialpad_test.dart new file mode 100644 index 00000000..1b19da10 --- /dev/null +++ b/test/src/components/dialpad/dialpad_test.dart @@ -0,0 +1,285 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +import '../../../test_utils/test_app.dart'; +import '../../../test_utils/tolerant_comparator.dart'; +import '../../../test_utils/utils.dart'; + +void main() { + setUpAll(() { + final testUri = Uri.parse(getCurrentPath('dialpad')); + goldenFileComparator = TolerantComparator(testUri, tolerance: 0.01); + }); + + group('ZetaDialPad Tests', () { + testWidgets('Initializes with correct parameters and is enabled', (WidgetTester tester) async { + String number = ''; + String text = ''; + + Future debounceWait() => tester.binding.delayed(const Duration(milliseconds: 500)); + + await tester.pumpWidget( + TestApp( + screenSize: const Size(1000, 1000), + home: ZetaDialPad( + onNumber: (value) => number += value, + onText: (value) => text += value, + ), + ), + ); + final dialPadFinder = find.byType(ZetaDialPad); + final buttonFinder = find.byType(ZetaDialPadButton); + + final oneFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '1'); + final twoFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '2'); + final threeFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '3'); + final starFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '*'); + final hashFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '#'); + + final ZetaDialPad dialPad = tester.firstWidget(dialPadFinder); + final List dialPadButtons = tester.widgetList(buttonFinder).toList(); + + final ZetaDialPadButton one = tester.firstWidget(oneFinder); + final ZetaDialPadButton two = tester.firstWidget(twoFinder); + final ZetaDialPadButton three = tester.firstWidget(threeFinder); + + /// Dial Pad built correctly. + expect(dialPad.buttonsPerRow, 3); + expect(dialPadButtons.length, 12); + + /// Dial Pad buttons built correctly. + expect(one.primary, '1'); + expect(one.secondary, ''); + expect(two.primary, '2'); + expect(two.secondary, 'ABC'); + expect(three.primary, '3'); + expect(three.secondary, 'DEF'); + + /// Tap button with only number. + await tester.tap(oneFinder); + await tester.pump(); + expect(number, '1'); + + /// Tap button with number and text. + await tester.tap(twoFinder); + await tester.pump(); + await debounceWait(); + expect(number, '12'); + expect(text, 'A'); + + /// Tap different button. + await tester.tap(threeFinder); + await tester.pump(); + await debounceWait(); + expect(number, '123'); + expect(text, 'AD'); + + /// Tap text button twice. + await tester.tap(twoFinder); + await tester.tap(twoFinder); + await tester.pump(); + await debounceWait(); + expect(text, 'ADB'); + + /// Tap text button thrice. + await tester.tap(twoFinder); + await tester.tap(twoFinder); + await tester.tap(twoFinder); + await tester.pump(); + await debounceWait(); + expect(text, 'ADBC'); + + /// Tap different text buttons to ensure debounce is cancelled. + await tester.tap(twoFinder); + await tester.tap(threeFinder); + await tester.tap(twoFinder); + await tester.pump(); + await debounceWait(); + expect(text, 'ADBCADA'); + + /// Tap text button more times than there is options to ensure it loops around correctly. + await tester.tap(threeFinder); + await tester.tap(threeFinder); + await tester.tap(threeFinder); + await tester.tap(threeFinder); + await tester.tap(threeFinder); + await tester.tap(threeFinder); + await tester.tap(oneFinder); + await tester.pump(); + expect(text, 'ADBCADAF'); + number = ''; + + /// Tap buttons with symbols + await tester.ensureVisible(starFinder); + await tester.tap(starFinder); + await tester.tap(hashFinder); + await tester.pump(); + expect(number, '*#'); + + /// Allow all timers to end in text debounce + await debounceWait(); + + await expectLater( + dialPadFinder, + matchesGoldenFile(join(getCurrentPath('dialpad'), 'dialpad_enabled.png')), + ); + }); + }); + testWidgets('Initializes with correct parameters and is disabled', (WidgetTester tester) async { + const String number = ''; + const String text = ''; + + Future debounceWait() => tester.binding.delayed(const Duration(milliseconds: 500)); + + await tester.pumpWidget( + const TestApp( + screenSize: Size(1000, 1000), + home: ZetaDialPad(), + ), + ); + final dialPadFinder = find.byType(ZetaDialPad); + final buttonFinder = find.byType(ZetaDialPadButton); + + final oneFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '1'); + final twoFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '2'); + final threeFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '3'); + final starFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '*'); + final hashFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '#'); + + final ZetaDialPad dialPad = tester.firstWidget(dialPadFinder); + final List dialPadButtons = tester.widgetList(buttonFinder).toList(); + + final ZetaDialPadButton one = tester.firstWidget(oneFinder); + final ZetaDialPadButton two = tester.firstWidget(twoFinder); + final ZetaDialPadButton three = tester.firstWidget(threeFinder); + + /// Dial Pad built correctly. + expect(dialPad.buttonsPerRow, 3); + expect(dialPadButtons.length, 12); + + /// Dial Pad buttons built correctly. + expect(one.primary, '1'); + expect(one.secondary, ''); + expect(two.primary, '2'); + expect(two.secondary, 'ABC'); + expect(three.primary, '3'); + expect(three.secondary, 'DEF'); + + /// Tap button with only number. + await tester.tap(oneFinder); + await tester.pump(); + expect(number, ''); + + /// Tap button with number and text. + await tester.tap(twoFinder); + await tester.pump(); + await debounceWait(); + expect(number, ''); + expect(text, ''); + + /// Tap different button. + await tester.tap(threeFinder); + await tester.pump(); + await debounceWait(); + expect(number, ''); + expect(text, ''); + + /// Tap text button twice. + await tester.tap(twoFinder); + await tester.tap(twoFinder); + await tester.pump(); + await debounceWait(); + expect(text, ''); + + /// Tap text button thrice. + await tester.tap(twoFinder); + await tester.tap(twoFinder); + await tester.tap(twoFinder); + await tester.pump(); + await debounceWait(); + expect(text, ''); + + /// Tap different text buttons to ensure debounce is cancelled. + await tester.tap(twoFinder); + await tester.tap(threeFinder); + await tester.tap(twoFinder); + await tester.pump(); + await debounceWait(); + expect(text, ''); + + /// Tap text button more times than there is options to ensure it loops around correctly. + await tester.tap(threeFinder); + await tester.tap(threeFinder); + await tester.tap(threeFinder); + await tester.tap(threeFinder); + await tester.tap(threeFinder); + await tester.tap(threeFinder); + await tester.tap(oneFinder); + await tester.pump(); + expect(text, ''); + + /// Tap buttons with symbols + await tester.ensureVisible(starFinder); + await tester.tap(starFinder); + await tester.tap(hashFinder); + await tester.pump(); + expect(number, ''); + + /// Allow all timers to end in text debounce + await debounceWait(); + + await expectLater( + dialPadFinder, + matchesGoldenFile(join(getCurrentPath('dialpad'), 'dialpad_disabled.png')), + ); + }); + testWidgets('ZetaDialPadButton interaction', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + screenSize: Size(1000, 1000), + home: ZetaDialPadButton(primary: '1'), + ), + ); + final buttonFinder = find.byType(ZetaDialPadButton); + final inkwellFinder = find.byType(InkWell); + final InkWell inkWell = tester.firstWidget(inkwellFinder); + + final gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(location: Offset.zero); + await tester.pump(); + await gesture.moveTo(tester.getCenter(buttonFinder)); + await tester.pumpAndSettle(); + + expect(inkWell.overlayColor?.resolve({WidgetState.hovered}), ZetaColorBase.cool.shade20); + + await expectLater( + buttonFinder, + matchesGoldenFile(join(getCurrentPath('dialpad'), 'dialpadbutton.png')), + ); + }); + + testWidgets('debugFillProperties works correctly', (WidgetTester tester) async { + final diagnostics = DiagnosticPropertiesBuilder(); + const ZetaDialPad().debugFillProperties(diagnostics); + + expect(diagnostics.finder('onNumber'), 'null'); + expect(diagnostics.finder('onText'), 'null'); + expect(diagnostics.finder('buttonsPerRow'), '3'); + expect( + diagnostics.finder('buttonValues'), + '{1: , 2: ABC, 3: DEF, 4: GHI, 5: JKL, 6: MNO, 7: PQRS, 8: TUV, 9: WXYZ, *: , 0: +, #: }', + ); + + final internalDiagnostics = DiagnosticPropertiesBuilder(); + const ZetaDialPadButton(primary: '1').debugFillProperties(internalDiagnostics); + expect(internalDiagnostics.finder('primary'), '"1"'); + expect(internalDiagnostics.finder('secondary'), '""'); + expect(internalDiagnostics.finder('onTap'), 'null'); + expect(internalDiagnostics.finder('topPadding'), '3.0'); + }); +} diff --git a/test/src/components/dialpad/golden/dialpad_disabled.png b/test/src/components/dialpad/golden/dialpad_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..e2357d55bbb87bdccd91ad080de75564549a9a02 GIT binary patch literal 12517 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 literal 0 HcmV?d00001 diff --git a/test/src/components/dialpad/golden/dialpad_enabled.png b/test/src/components/dialpad/golden/dialpad_enabled.png new file mode 100644 index 0000000000000000000000000000000000000000..e2357d55bbb87bdccd91ad080de75564549a9a02 GIT binary patch literal 12517 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 literal 0 HcmV?d00001 diff --git a/test/src/components/dialpad/golden/dialpadbutton.png b/test/src/components/dialpad/golden/dialpadbutton.png new file mode 100644 index 0000000000000000000000000000000000000000..b7c289fcf7e5b0a112d1191a5339e065fd2d5e70 GIT binary patch literal 4743 zcmeH}`&W{A9>>3GUbfOMXFZjMIx}Z;n~pi^_Tr8mgkq}e8120d_JG| z>-+h<&vWVT32~mQeO3biJmU|>9s$55008GC4>!0|#VE~#H>dm~ar=O%ck4&ESe3so z{-_7MSRSV?0ns%$i>RMwHv^P}fo*5;O@o8F*4gjAa9u1ddV zdwtyYzZe<(#*Uh~?YG@`cJXQx-b}f!@B1S8=`TMm-*_RA5@VGXHWmB8B)Bf1)7exu zl|FrTQL!vU(JZv8)!JImuScr+d|m}omAG^afVW;q&gaoPZ=aM-qW1rc{2ET+RS?So zc!JLpIz3FHBo?rG_m`hZz~+p(0KoO72RS`V5oR~)^%>aw#RpkvGv7B%b2`M|1Avsv z-Rgy@3+n>S)aAvf#wqJPe*L_Gx+G!vy(-%Rl|Q-`)$V*wo}^MNnH6S>V$s-|*?O&H zVYbdZ9<>~Y|78Ka?hM(9+An13=yayMLB;%cdSzmg(2m1X2U`tgey#vmJxQytzDH6s zXU!Fu-OE0yRC+j7eNO7f{3Fy8!YSm|1QWxkzb<)~*&YgJUmzcL!O9b@C%6r5qJ$jH zbwO}44A}UmH2~z)2D^2g_*ZfJBwcT>lt76sow;sZtj8iV?dz%O2w|Ii>~ER-VBBWw z8E(U1Y7nWg#P#@NJtCFc)lL9dIs#oz$tLxzvn52Y-c5#Mm)8TZc{tGJ_XWQk@)a}LX=h#q0D0t8w=Ony@ll%hDi|?;OTbAc>E|0FZzzG+tbd0-!Ei=x|Ddx8 zSpFI}z$M=n`i#HJ5|#oGO(BQ%R!{GuguuK)V|L1rcxU-^l@mxiZA89@izHVkz-?gQ zf2+=Og7lM(H|pF}bZ407ns$0DuHv^Bmtg_bP1L1ec!ugbM!^1;KWI9v9AJJ={$Wr+2s<3| zX)^@-C5@o^PAEioVY(*Um{V!lAGX5)1zHp}8jZ(-HpTR9l%%|*DVzbF=b zwUwyaOnIqRcTazFcpLAQJ0$k{F{{G*?7}+3#P3C2$)EQoToH0$#^{|crwR)TR|x{x zn36pWfr&TQ;-S>?H|gBa!`~Jc7t>jvI9=y+2Bu%zwL?R*pLRen2klD5#KgqF!omb6 za)ZExa5%(>h=`a($n}nDX~x%Xx6`NQUagl5KlrXC7bz(zS!wFD0giWoMAJ}(;%s>( z%_lJaG66r50vqb98mj9-f=YQm(eUi`@u2a{kLN|Ya~xu){}ug5<^7n-mB5y6pcx)+ z81Ji7TXHF+7RtTM)^K(UY8q)5t!$2sjrG5Sl0L9^N28HBB<;wE7%Qd@>R6$<)Mbl4 z-DolmG2ukEJkNBwtAE$FH$##v?Cy?uIBPi{7@c2JVpSLWvqC;SrMWDlMc>+N!ij7jM1>@?r+Oho2B zoITOJBf>T%_Zm?MG-rsxl=i8od!etSb4c8jJ$v>%@aI@>HMeA%i%ivMD;{e#jmYbj zN*)9)kjZ4XI${4rj{eo@2!YOGrHCmql%ItZnyR&|pV;3@7I$8rRpN^5Y%`k*L+8DP zCFeBmaEBmSkz$kFF1p^6E~SwZ8J29r@tL0$;#nn+xjadur;=9mv=@CtCX+j$({Tm! zF))dWo{I7F8*D2yA<}uP=&DYZix@^3VXrpzH7|e0R)}nxWK8>_97V&!!}Z;~K(lrF z9WqpHI|NzHFN}i6{TB90gpQ7m^ovb2awTKw=sN#iwDyn!d6FY-kVts*c?C(SY63x3 zfD`I;I;}=?wjb6#c~$InwGM~Fp?B`w!Qt_X8jF8UACjFd*v8AE9onX9_Ej~}7K<** z#Bu{_7?e_ki1e6>#i3;04~+8ChDv3!)Ji`*T3cId@PU#%S_fe{^wip$HwU}B<7;bb zQbgq`s#Ck`HD?&MP6Qs?Fb%sgKoMHkm))2&fJo8z=aPHg&&(LmN;0~Q7k~J^vPX=? zVliJrhbZ2*5t isPressed = true), + ), + ); + + await tester.tap(find.byType(ZetaFAB)); + await tester.pumpAndSettle(); + expect(isPressed, isTrue); + }); + }); + + testWidgets('Icon Test', (WidgetTester tester) async { + final scrollController = ScrollController(); + await tester.pumpWidget( + TestApp( + home: ZetaFAB( + scrollController: scrollController, + onPressed: () {}, + type: ZetaFabType.inverse, + shape: ZetaWidgetBorder.rounded, + size: ZetaFabSize.large, + ), + ), + ); + expect(find.byIcon(ZetaIcons.add_round), findsOneWidget); + final fabFinder = find.byType(ZetaFAB); + final ZetaFAB fab = tester.firstWidget(fabFinder); + + expect(fab.initiallyExpanded, null); + expect(fab.type, ZetaFabType.inverse); + expect(fab.shape, ZetaWidgetBorder.rounded); + + await expectLater( + find.byType(ZetaFAB), + matchesGoldenFile(join(getCurrentPath('fabs'), 'FAB_inverse.png')), + ); + }); + + testWidgets('Expanded', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaFAB( + initiallyExpanded: true, + onPressed: () {}, + label: 'Label', + type: ZetaFabType.secondary, + shape: ZetaWidgetBorder.sharp, + ), + ), + ); + + final fabFinder = find.byType(ZetaFAB); + final ZetaFAB fab = tester.firstWidget(fabFinder); + + expect(fab.initiallyExpanded, true); + expect(fab.type, ZetaFabType.secondary); + expect(fab.shape, ZetaWidgetBorder.sharp); + + await expectLater( + find.byType(ZetaFAB), + matchesGoldenFile(join(getCurrentPath('fabs'), 'FAB_secondary.png')), + ); + }); + testWidgets('ZetaFAB interactive', (WidgetTester tester) async { + final FocusNode node = FocusNode(); + + await tester.pumpWidget( + TestApp( + home: ZetaFAB( + initiallyExpanded: true, + onPressed: () {}, + label: 'Label', + type: ZetaFabType.secondary, + shape: ZetaWidgetBorder.sharp, + focusNode: node, + ), + ), + ); + + final fabFinder = find.byType(ZetaFAB); + final ZetaFAB fab = tester.firstWidget(fabFinder); + final filledButtonFinder = find.byType(FilledButton); + final FilledButton filledButton = tester.firstWidget(filledButtonFinder); + + expect(fab.initiallyExpanded, true); + expect(fab.type, ZetaFabType.secondary); + expect(fab.shape, ZetaWidgetBorder.sharp); + + final gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(location: Offset.zero); + await tester.pumpAndSettle(); + await gesture.moveTo(tester.getCenter(fabFinder)); + await tester.pumpAndSettle(); + + expect(filledButton.style?.backgroundColor?.resolve({WidgetState.hovered}), ZetaColorBase.yellow.shade70); + + await gesture.moveTo(Offset.zero); + await tester.pumpAndSettle(); + + node.requestFocus(); + await tester.pumpAndSettle(); + expect( + filledButton.style?.side?.resolve({WidgetState.focused}), + BorderSide(color: ZetaColorBase.blue[50]!, width: ZetaSpacingBase.x0_5), + ); + }); + + testWidgets('debugFillProperties works correctly', (WidgetTester tester) async { + final diagnostics = DiagnosticPropertiesBuilder(); + const ZetaFAB().debugFillProperties(diagnostics); + + expect(diagnostics.finder('label'), 'null'); + expect(diagnostics.finder('onPressed'), 'null'); + expect(diagnostics.finder('type'), 'primary'); + expect(diagnostics.finder('size'), 'small'); + expect(diagnostics.finder('shape'), 'full'); + expect(diagnostics.finder('icon'), 'IconData(U+0E009)'); + expect(diagnostics.finder('initiallyExpanded'), 'null'); + expect(diagnostics.finder('focusNode'), 'null'); + }); +} diff --git a/test/src/components/fabs/golden/FAB_default.png b/test/src/components/fabs/golden/FAB_default.png new file mode 100644 index 0000000000000000000000000000000000000000..e9fd5e4786f461c03e395c74b9d9c44454eb0a76 GIT binary patch literal 4766 zcmeH}`#W3N8h{tk)~Tvq&dg}l<fjZ}%aB{{pDbN++#WA-oW*?WC^?e)F;{k~`Y zeAe4Tf9JuS004b2Pxo^Gz{~*9M(J*co)i-^FGGVC{+x#!ptBFnLpM5jH!pu(=t|Z7 zAsc{wo?h->`zM!51+m$41Y_2c>~u7)V{z~;=|aL0yB5qq#do9dYfpC}QY_%Q|5&*y z(95(oFwZ`wH~R0s?3Wc*5tRln|8C*OIb(X~Cj+7vwv%>r=0}9+-88$@#51R$#0KwO zZsWK~ayGITr*{pO?ocbXRBCnO$b6y$uV#MTTcDh{Bw$e5Ov+=%^8|WwE}bZy;L!W; z(+!6A89R2U)wbx@#IXht(@g={K zRi}eF%Wl{j$EChNN(|>R=Ka`hhot4p-7GCA{P8SES?s;OF=kvycy{mC;<%i=EZ&89 zLs~4`sG-GYpE&@ta0ge*Xa{+xi_e%smNF6*P~S(+H>JiR3>y?CE?k)}0QNfYuUy-Z zHep56_P)X8_k9N4QPsYLp_FR*T}7ir@g)GXD~$)tl2q7Q>rI}!^nTmIBR(d9U%WBt z@gnvi@9n3Mb7~t`+{B51^3If`)-MVUkNC(OBOc;Z&-W6z5kqPD+Th7oiBCX##DG6# zA*qA2+@yWUfmC6#_SDx78EK&dGG<7;bi5FPhfL2|v-gi96T6VBlAnVv^Nay-UJcXw zFiR(5u87=+S~rjHKGJK-U~|Xg1yi!)0HC5m_nMJw9SN@xmJ5?!rzmF$QcR(|q5l8=b8OV4#9LL@f$*Nn=J)g)L2PQaA4;r;TshPNm{f zeqh#$$t@cRZ}Q8+R-*i6r*RJ#)zi1XRo(0fuyUcn(0GfSbJAJcCgLS zjvJ(!Oe9xQdA*cLL07tX<~siva|^Z=#|n8s65w;vlpHc&{$xL%@FF2=K=mB}F^l&X zxtM(BQpq@Rsx9k?zZO8H6fuWv76+H3w)Lg(B#>vUscbf|?r9q#88NDcOl}^qWzZc1Z{A6jO*TjLefe~2e zX1KY|5dZ{+Z{>fRs~ZlP;)otKqqMX@h0(`lugmnH$(XW)>DSgp4!4MPoN8YZ8BU7l zjKBzM2elwWKj@csr2O(zP;PM?LN=@Jv3f&YnoE}_!vm{wd=C6CNzvh4lDg!^hBK=G zz7k&f%T(_@oX1;5(C`&x7?i{x4Ogi}-tc(gNsbKtxpYMQrh$1a&M2BJ)M{TRTKOPlEKP+tpL^jAMDHkiXGCT9TV7?)n#R{gXc@Lx~EU03a;}$Q)bN)qmQzY7k;C6#L&DakNxrA4(H&i!bS?+D3ZMXjU|eo-BjpkF#2n6 z^0ROZekSGtrGWKL8{BG{1?%}%Nv#q_dO3ZHF~k+*4~?z-Zit@uc4`g~Uph!P=q5Z@ znLs)8Hp6D;YQ>HO1-6ACT%9DPR$&~82yUK0O1hZTVHthRi~k7Qz_*{F<%$|UwR}^X zv*L265LP3j9THK=D+F3lpu%ZS!cmv>d#@n6l H7M}SZBZc`- literal 0 HcmV?d00001 diff --git a/test/src/components/fabs/golden/FAB_inverse.png b/test/src/components/fabs/golden/FAB_inverse.png new file mode 100644 index 0000000000000000000000000000000000000000..fed07d539b2211cc0eab01fea2fc6e8d3ecae997 GIT binary patch literal 4358 zcmeHISx}Q#6uuFVAWF1UR02YE1_lwZE(w&7P>KS><_MNxWKqP}LBNP6WD(F-Ekhvf zFj!;>#VU~&2}@-sLB#|`KspRdA%G2wAtV?=0vM9?$4-a#sq{Vn%l*%}ch33lchC7w z=J61}Et{-20RXlH`1_s!z{nne4S4uQ$WuVRaS2*rDJT4VKxMa$1Tu_Md;-GZ(8qwE z`xbz$RRO-Aho=_FLm2swnMAq%S{JZA0dw8AJ=S=e^t!)K z>EJ_rFlI!3?4!6o{B|QY0`H<=*q?o9omg~ZVUjZFz*mRANMBPsC|M-8p_$JBi& z^D$!4qO!4oa!`rouW+XdsqDMK%4G&N%`awoW zdW+a6L=rJS>oKicxH;+(TT!@rs{`1fa?_v8f(3D!acHi{`HBmu@4m9u{`G zuO3Smf1jV9Z&;%4VDg(*YDn`h5Ct>~04k9DBi=c-o+zCz4$Vv$)AC5u#ir6IQ*050axdc7$5kT61YCsenH+|HuiI=uRwA^^sIa9eIDU=rh&F z0Oa>^O*+_Kbm2)ZO*U9doC_~R-H&Pxu}!9TB88PvoDeS)034Kouo~KUTk4Ak5zN*x z&72cD5zk6(x64MPk2h7<)ExW}t9@3E=?q$DfN|a@-T-7U0fgw_2FTF? z-wJ^J-t{;!u`@7A^Tczvoy6I+@XL<~d`*e?Ju3~kkD7#qLhUanN~h5F0JI4l*F)&~0shCyR~MC2 zU17<1eD`jUarDse^0@6ktVZRNHOo`X6s=kG`CPU;R4}TA+7grsDhL0rZpKOpbti2@ zU|^uwjEGH|*#*FN1ukxGEOT~>uFun|`{oV|eZPxKu$K`4Ckm$^sTt#G#VtxV8^0Wz zVp@;SU`@QTK_cjZ)Zoi9_67jThj!{U1NrQ9MG9xM=71|zVgB3{0CUN--b_2`Mwbk> zYQ7IkiiD@H{_2*i(r`MeLN;8Noxr6QE&&i*+LflVY^LBYk1Rb8&BkeS zg(20%FWxI1i#)K4LrB4D$QdUnX?aYOiIkmVhr?pEcY9cTy0BTG)8c-nB*Hz(70h3v z6$9dX<|T*D*Ty7x0f2XhWKT|h`}z$@L?6Xr)e5BG%`@C1vNoC!9lbkUv63aoi#Uy{ zOS(4RmjVG1H4K184mV9E6$he4n51T{niQ)NuBtO>Ac`U?(e$^v5bBtDd9t{8jhggc z!pTl4A$7ZJDmX!2<^c3R&_`rI#a0AII6%uT7)0t9m+w36`IkviIa2g0P6oa7= s49Z|oMZ-ieOhdyoG)%*FOvB|}E|Q>I+xNH+L5D%W(GcHCpV%9J0?pGI3;+NC literal 0 HcmV?d00001 diff --git a/test/src/components/fabs/golden/FAB_secondary.png b/test/src/components/fabs/golden/FAB_secondary.png new file mode 100644 index 0000000000000000000000000000000000000000..df6727436b8de3c2dacfcccee811eef5ace68ebf GIT binary patch literal 3598 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 literal 0 HcmV?d00001 diff --git a/test/src/components/in_page_banner/golden/in_page_banner_negative.png b/test/src/components/in_page_banner/golden/in_page_banner_negative.png new file mode 100644 index 0000000000000000000000000000000000000000..406c1b0f83f3b40ece62c983d2fced42bd42b5a0 GIT binary patch literal 3949 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`G#)5S5QV$R#UC%f;b%O3ccE;d>1rP0fhSvzDFul?WX;aFYB%<8X~ zV5-sk?ScT4VeWwiB1dDol#+Clt~PTl3Mt&VGeCFI_ba!W+1FlP;<-HXw&CRY?EQzP zNG^MCXuSUV&!2zho&Wyh*>+!FwaF)!&i|7%$NFpU$5$`YkALMBXJ=qI;5K95*J&F+ zzs;Ba%r7rzUjL#t`P-$*`{la%Wu&>|ZOp#isXjmB?)D8gt(h1YqK|A9Ki7A9e`S`= zz50?j^1;ck-oLN-|KywV_ugo`KaFSa@iH*nSfuyw%k;;8lJCo3K7IaA?wiWoFwtIP7g*#X@kW>)CpsS|e_t1yJ&&28LHgn@<|luy%ggK6{$_tY>u&Xb z^<(>j)#E?k`Sj`2kB{f;_N}wd6H)J%m33}lVA$Zh#v0@R>ErhQw_3#6l;_26EV@!cKa2pb37W}*p}R%aku{Ys`Pcb^8^)ucAWjmA;!RvW6WRk>%oq<*RI+h{PL-l z`|<4iKi{?8*9BUiFx&FS$Ns)rZtm6dDj&YNd0o}v4?hP3!vv6a2e$?W1_nt+U__;` zzy;Hs>)O8mJTD^&4DR(+&wf4CmM#=!U?^a|J%M58rz`W#9;N;}?rWVd#V>2Q=h@Ee z>tV;P%;=eUbE|Eft@*L~`GO1#+q(b1wpY5dv-tRrI|u#qzDWU{y40rP&ygEjv#$eP zAGi0{t~-0*G2ASF_2dQ+yS)QCfo0ym&+%q&^WvR=$;>Et`SC+f-YtD@R?QFeMR#@D zyM}V0e;WD-L^9Tx9~A@z9ijX&8cL&~guetGO(CNxWHg1~YF~`zj?vsPnma~w2WHP> zn3fF2wwufI*35~&^~M(1ywuHk`sdP&o7U#b%I}mW#QgkwdG=ml+kHc8?9aRM$NP5k z_1ygVn7{9+v-|Os%E~u8zt1z=Y_R|4ZeW%Hb`y^pKmL^e-{4%`!_~?EANTjIJegv& z^UIU<$9C%1=kBTcb+hpAqorr>0Xr8rl+vE%Nn5|Gdp)E6$A=w1o8Qa+XFT@q!jb=M RVhb67z|+;wWt~$(69D}ZQ>Xv{ literal 0 HcmV?d00001 diff --git a/test/src/components/in_page_banner/golden/in_page_banner_positive.png b/test/src/components/in_page_banner/golden/in_page_banner_positive.png new file mode 100644 index 0000000000000000000000000000000000000000..7c12198be318eee4d87e4107fae6828d648e8189 GIT binary patch literal 3839 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`$Or;B4q#hkZy<5$ctl|AtB{5ik8^x21BYB@1`A7o2pVbfK*@Bt8!;xNSOWO`0DiM zN9NC;_gn7&yEi+2|GW9|pnOg0-_PZ>HPiTI@4dRqz|fHU>c>g-w5Qwc=eOF=t4g#h zyZw86l{`?p^zRdE-_Nz*`)7NkMfJn0H>>ZyTYHZk=!#=`F}v!{t(iB!b!{9A1H+Co z4gm%R1!V`IVLc2$XBsg9MNgm$c1z3FygTFl`O(kI(z9xh?~{IhjXA&ma4!lx5k zf73WU?EG2&`tl^>JfJsXmYS(L$o=?WTYUOo^K{$KhqRZoZ~%oL*EF#*FrNQ#Kt;z$5v|8uws;v8a-9G259RtGwvu~@P z*V&ifDfz5Z_ZHacxc~V6Z1Zb+XWj3YK9{+(xqfvyu!X;^bNadYbL0O!efjfQr~KJd zcjIS)JA=pP13P(tXS+Xtvhw-!JFizq?^R}C*x-9-L-qST&mZU(zj6M4PCajT_CMA- XvlX)Dg}MuXsgl9d)z4*}Q$iB}b1L4# literal 0 HcmV?d00001 diff --git a/test/src/components/in_page_banner/in_page_banner_test.dart b/test/src/components/in_page_banner/in_page_banner_test.dart new file mode 100644 index 00000000..a15b4205 --- /dev/null +++ b/test/src/components/in_page_banner/in_page_banner_test.dart @@ -0,0 +1,126 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; +import '../../../test_utils/test_app.dart'; +import '../../../test_utils/tolerant_comparator.dart'; +import '../../../test_utils/utils.dart'; + +void main() { + setUpAll(() { + final testUri = Uri.parse(getCurrentPath('in_page_banner')); + goldenFileComparator = TolerantComparator(testUri, tolerance: 0.01); + }); + + group('ZetaInPageBanner Tests', () { + testWidgets('ZetaInPageBanner creation', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaInPageBanner(content: Text('Test'), title: 'Title'), + ), + ); + final Finder decoratedBoxFinder = find.byType(DecoratedBox); + final DecoratedBox box = tester.firstWidget(decoratedBoxFinder); + + expect(find.byType(ZetaInPageBanner), findsOneWidget); + expect(find.text('Test'), findsOneWidget); + + expect(box.decoration.runtimeType, BoxDecoration); + final BoxDecoration decoration = box.decoration as BoxDecoration; + expect(decoration.color, ZetaColorBase.purple.shade10); + + await expectLater( + find.byType(ZetaInPageBanner), + matchesGoldenFile(join(getCurrentPath('in_page_banner'), 'in_page_banner_default.png')), + ); + }); + }); + + testWidgets("ZetaInPageBanner shows 'close icon' correctly", (WidgetTester tester) async { + await tester.pumpWidget( + TestApp(home: ZetaInPageBanner(content: const Text('Test'), onClose: () {}, status: ZetaWidgetStatus.negative)), + ); + + expect(find.byIcon(ZetaIcons.close_round), findsOneWidget); + final Finder decoratedBoxFinder = find.byType(DecoratedBox); + final DecoratedBox box = tester.firstWidget(decoratedBoxFinder); + expect(box.decoration.runtimeType, BoxDecoration); + final BoxDecoration decoration = box.decoration as BoxDecoration; + expect(decoration.color, ZetaColorBase.red.shade10); + await expectLater( + find.byType(ZetaInPageBanner), + matchesGoldenFile(join(getCurrentPath('in_page_banner'), 'in_page_banner_negative.png')), + ); + }); + + testWidgets("ZetaInPageBanner hides 'close icon' correctly", (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp(home: ZetaInPageBanner(content: Text('Test'), status: ZetaWidgetStatus.positive)), + ); + expect(find.byIcon(ZetaIcons.close_round), findsNothing); + final Finder decoratedBoxFinder = find.byType(DecoratedBox); + final DecoratedBox box = tester.firstWidget(decoratedBoxFinder); + expect(box.decoration.runtimeType, BoxDecoration); + final BoxDecoration decoration = box.decoration as BoxDecoration; + expect(decoration.color, ZetaColorBase.green.shade10); + await expectLater( + find.byType(ZetaInPageBanner), + matchesGoldenFile(join(getCurrentPath('in_page_banner'), 'in_page_banner_positive.png')), + ); + }); + + testWidgets('ZetaInPageBanner button callbacks work', (WidgetTester tester) async { + bool onPressed = false; + final key = GlobalKey(); + await tester.pumpWidget( + TestApp( + home: ZetaInPageBanner( + content: const Text('Test'), + status: ZetaWidgetStatus.neutral, + actions: [ + ZetaButton( + label: 'Test button', + onPressed: () => onPressed = true, + key: key, + ), + ], + ), + ), + ); + + final Finder decoratedBoxFinder = find.byType(DecoratedBox); + final DecoratedBox box = tester.firstWidget(decoratedBoxFinder); + expect(box.decoration.runtimeType, BoxDecoration); + final BoxDecoration decoration = box.decoration as BoxDecoration; + expect(decoration.color, ZetaColorBase.cool.shade10); + + await tester.tap(find.byKey(key)); + await tester.pumpAndSettle(); + expect(onPressed, isTrue); + + await expectLater( + find.byType(ZetaInPageBanner), + matchesGoldenFile(join(getCurrentPath('in_page_banner'), 'in_page_banner_buttons.png')), + ); + }); + testWidgets("ZetaInPageBanner 'close' icon tap test", (WidgetTester tester) async { + bool closeIconIsTapped = false; + await tester.pumpWidget( + TestApp(home: ZetaInPageBanner(onClose: () => closeIconIsTapped = true, content: const Text('Test'))), + ); + final closeIcon = find.byIcon(ZetaIcons.close_round); + await tester.tap(closeIcon); + await tester.pump(); + expect(closeIconIsTapped, isTrue); + }); + testWidgets('debugFillProperties works correctly', (WidgetTester tester) async { + final diagnostics = DiagnosticPropertiesBuilder(); + const ZetaInPageBanner(content: Placeholder()).debugFillProperties(diagnostics); + + expect(diagnostics.finder('onClose'), 'null'); + expect(diagnostics.finder('status'), 'info'); + expect(diagnostics.finder('title'), 'null'); + expect(diagnostics.finder('customIcon'), 'null'); + }); +} diff --git a/test/src/components/password/golden/password_default.png b/test/src/components/password/golden/password_default.png new file mode 100644 index 0000000000000000000000000000000000000000..91231e82dede2f6c446cdd35ee83d44887474814 GIT binary patch literal 3639 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sOh1ni(^Q|oVRz+=UoYvXn1%z^SBYu3eU$}=9^4nx*oRmFiEX%PT0dC zF14p&Q`3$ky=!)kYxgrCpZKc7!;HpfUfCbU}Ru0 zB2iE#ry6M2g3|Y^^N($gpTGC=JZbs+66O2;{IQ>}3p6$1xJ}KE%N4)AOfSDx{P~$W z$oL=M`}+Eht&N_)uk`F>b^HG3=jX@Ymo;qSF`Wz48XVKtw8!I?hG*?|$BUk&ud1EJ`( z*OIMlB_;!-378OW&tqp`*l{FI_xv$nY|Q{AgqJU07k)~5s0Iv<9RaJaR?PuM?Ngvw zt(|oB?6Yabb^p@-Y>em&KW!`sbau>)mtPWM=F0ZH{(SSs{rP`H6>iG`Q~V9yeNC(= z;X}UrafkV+nP`b{G(biJ1b;C#nnFfX$Y=_|Rf&)0j?vsPnma~w2WIo07A3i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`$mr;B4q#hkZy&v!pBl|AtB`}UvjEH=Jvdbi5;#3Iekrs|I}ts*Q+ zE~T%;RBqI|8Lkfk0&${_?^7h()`}U2m_TkOV>Bp|Fwr-ynA0IED z%wv7y;f=B%r>4J`i?^!%b>TAu!+dl3KX1Yx|GKtcY?fu|`S9bh`~Ur%_VO(h6d5nZ@>Hdch`UJo;~m8znA*Qr>4hQY_tB$AeKH@%#W#3-g{X+0vO~; zX`i>IJlkBs2(qyF{nG2x%C?Jx%-;Ng`$Wy#41fL2H{W=CcHeuSugu~d&}NGrH=nM3 z`|{At-qiO%i{})~w%%=b5ExHZ=uW`uE^-9V9G6HgPA|V%4NMZ+31+^Rx4cmWdi?4G zVI81DaR1w%vny@@Betj=o>I}!VdhmJ2>mC*nFEaJiy4k^enk&W7)fJA0K=%d`Co>#n41+0cCjm?RlIUHx3vIVCg!0NC5{G5`Po literal 0 HcmV?d00001 diff --git a/test/src/components/password/password_input_test.dart b/test/src/components/password/password_input_test.dart new file mode 100644 index 00000000..cfac9d7c --- /dev/null +++ b/test/src/components/password/password_input_test.dart @@ -0,0 +1,97 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +import '../../../test_utils/test_app.dart'; +import '../../../test_utils/tolerant_comparator.dart'; +import '../../../test_utils/utils.dart'; + +void main() { + setUpAll(() { + final testUri = Uri.parse(getCurrentPath('password')); + goldenFileComparator = TolerantComparator(testUri, tolerance: 0.01); + }); + + testWidgets('ZetaPasswordInput initializes correctly', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaPasswordInput(), + ), + ); + expect(find.byType(ZetaPasswordInput), findsOneWidget); + + await expectLater( + find.byType(ZetaPasswordInput), + matchesGoldenFile(join(getCurrentPath('password'), 'password_default.png')), + ); + }); + + testWidgets('Test password visibility', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaPasswordInput(), + ), + ); + final obscureIconOff = find.byIcon(ZetaIcons.visibility_off_round); + expect(obscureIconOff, findsOneWidget); + await tester.tap(obscureIconOff); + await tester.pump(); + + final obscureIconOn = find.byIcon(ZetaIcons.visibility_round); + expect(obscureIconOn, findsOneWidget); + }); + + testWidgets('Test error message visibility', (WidgetTester tester) async { + String? testValidator(String? value) { + final regExp = RegExp(r'\d'); + if (value != null && regExp.hasMatch(value)) return 'Error'; + return null; + } + + final controller = TextEditingController()..text = 'password123'; + final formKey = GlobalKey(); + + await tester.pumpWidget( + TestApp( + home: Form( + key: formKey, + child: ZetaPasswordInput( + controller: controller, + validator: testValidator, + rounded: false, + ), + ), + ), + ); + formKey.currentState?.validate(); + await tester.pump(); + + // There will be two matches for the error text as the form field itself contains a hidden one. + expect(find.text('Error'), findsExactly(2)); + final obscureIconOn = find.byIcon(ZetaIcons.visibility_off_sharp); + expect(obscureIconOn, findsOneWidget); + + await expectLater( + find.byType(ZetaPasswordInput), + matchesGoldenFile(join(getCurrentPath('password'), 'password_error.png')), + ); + }); + + testWidgets('debugFillProperties works correctly', (WidgetTester tester) async { + final diagnostics = DiagnosticPropertiesBuilder(); + const ZetaPasswordInput().debugFillProperties(diagnostics); + + expect(diagnostics.finder('controller'), 'null'); + expect(diagnostics.finder('obscureText'), 'true'); + expect(diagnostics.finder('hintText'), 'null'); + expect(diagnostics.finder('label'), 'null'); + expect(diagnostics.finder('footerText'), 'null'); + expect(diagnostics.finder('validator'), 'null'); + expect(diagnostics.finder('size'), 'large'); + expect(diagnostics.finder('placeholder'), 'null'); + expect(diagnostics.finder('onSubmit'), 'null'); + expect(diagnostics.finder('errorText'), 'null'); + }); +} diff --git a/test/src/components/tooltip/golden/arrow_down.png b/test/src/components/tooltip/golden/arrow_down.png index aa99574828a6aa4e8b76f44e1cb35ae22cefdb9e..4635ff7c5ae1b0da62d227e5480fddbec4bc28c2 100644 GIT binary patch delta 608 zcmX>sb3kT-WBn^n7srr_IdAW7%o7P`XuG&uZ0%jviE5fmc{(3?7_}dH3bA;I)d{(C zY?$-KGmg>qnW6@-=A^DI%f2t`72=XUdH?9V;#;z7>w5D(XQrF3{#vzHj)A+h=15g)zbbrvo&5d(A2Po2 zh`o3|pYM1x`~9=?7!8gdd&9`ESw>Fo?7Ra`memI)aS9}CytnUn@;4T-Q#YBX`7|(e ze|>nk{ibk)Mmm3l5hD`=LrUHmIff6Gw{F~!D1U#?_WRe>SF?JqX017YPOR{+MDm`> z&uMdFAN=ax@#=eh&*{DP4B<2D85no=0~w^rZ3Ctbh4zFzZwt?ax1 zsrTd?R-aLhU|?`?YhYktkOW)9!ok2WK~Moza1T36ga4+@n~nGFDSdtCdbOcELo$Z| zgWbi?;^*~C_KJUIG-z|*z`)Qjfq{{M!3Y#m^K6;w6WZ4A+h<$N#Qp91{P$`83^NYt zD;!A5&C5H7Fn|ANWE6Y*<0r8V2n0Tf z1`DLPt6#w=@EzEMGPuFo4s5NfQHGX;-%ER*XT2vk|D3$bFZbM>)#1CNqXDo`PoF;< zkDly~mwT_q{{H^#Ih+9pn#^rHqYkS<-ygqvlz%(lX0)H&k?|=R=w!XhPdj<>i z!On?B3wfFk<>3;NW2P z1QyEK1C~sH0001)bF&8ke2UiA*2cAK*N%PtYPA|;wHilJ0eFwkE?gMD{PyeY8K1PxuQtcqH*Y@5cb|p(|1s|mz-i_YER(SV zBY)ll0>B5kdiCn~{Nlx9U+=|y0E{6(0Qf*V4|h&Lk!`9c=$CZuC-uv0T+jqzPJ9pzn0Gvi1!2;k|?%%mP?%n=>WQY#{ zPC|eHaBTmL5b*)PNu8TL0D#lw-@ze105~cC0RaF2G9JMK001%q1ONcY2oL}OAhV7F goC}kH0}2-N5BhYSD>+{u?f?J)07*qoM6N<$f=J^b5C8xG diff --git a/test/src/components/tooltip/golden/arrow_left.png b/test/src/components/tooltip/golden/arrow_left.png index 7f66b33e576aa16865bf29dd67ae890685f00760..e15b340ed943963f1bbb478f927ebaa31b0f72d1 100644 GIT binary patch literal 3658 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sOgKRi(^Q|oVRxm=7ogH9C&Cfy#1};8tGV$yCx4MTaJBD@oH$fp}ta) zG3f5<^$tD<(-R^K7HZ#_R(rga^J1Ty)ZF_=@4b&cH^=8+ago{nGkc50S6|ICJ!ffG zXC-H6C8e&ef9&PUmp`{ZwBNjUuWecR`rhjD{QkdxX9xE)GaP8sJ;#1xvbufG`TaYL zuiBisVIFTUw>_`c?5hL=L(YXyf4KYQ<$Vp=Evgw9j5mlW=*RstIV$tu4I{&u15pio z>i$-BSsu8_%rK*ID+40~!;LB5^)^-PjOlxQef|Egzm6su9!oL|OHbb%VSh~G{Cs=) zbn%FK!T;a?$|rCB4YYpudnd+E|E6j`zWsjx?JGLd5B2)z_r%BVy>%izzU}Y*C;u22 zKD_&VSv8`)oqyRZW(J@==8Q!ZKN4i>R2>)?8qP-cDcS+)V?i~*pcSn@%+0`%GL4=6 z`|*R*zb~H$*6>s!xkG?~VZn!ImJ00b``J5wJN}!yckkYh56_*8UjID-sQ+2Y#;CPn z^)(L{_pkr=_7Q(s*|E*?^K)xfSnfR0{8R7nzyFuN|9$#=`a=^2hAVek_<)wMa4;}T z*m*%UVne3hK_-SBcdpej-n?~dRuW&qHwK2Z1YL)9v42w#fwQyt`8Sc`hRy5@2F%&t z8+r_nef)U&4!rfE-$O~ZWox#)9&t;ucLK6U=|8nR6 literal 3651 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sOhbzi(^Q|oVR!P_l2a&G(5~#+qQcyi#E5Ij>ir*ag(@CZ-?n8rY8KD z9b5fXtcU5lgSt+u>^5)5?b(S=DaV_5&s9(OZ1Z%c{^WSSeb3IGvAqB2#nq1=Egn96 z?Ed)Qzk3x`A97^mH5c2d^mhhq_|-(JA(nUHe=C;KR*$?PoJKi)_lfL z&Cig)7RJQFz>pAYXLa_`(;`c~*j-<)y%z62D$#w^!p>^e(O-tgDn30qX<>Er*X1Ak z@BcTvR$b4)Q1O4RmV=#LaoV3BpZ#CYdfL3<@6T^PJ|FGgTJycV;Q#eXu$sLe#n(ia z=lPqmGXNd2p83hOxwjwx-VL%aV*XQ!N6ZWi89GOSk^vv3;ushdHt*S4om}(%ZSTtG zzyME6uskNA1XQcB$BzBUvv>CyA5~5$FaG%G=*N>cH|OuYcd&+m;mk>CcENjh_9{Bu zyLh*{+?0O&Dg2L_mHK%O5J91Rd~(i}|; zqq$?WWB``YqZwf|BaCK*(Tp(KG#YIyLR#&Eszx{yUtKUabN{b~3}C;6!PC{xWt~$( F699fgpi}?= diff --git a/test/src/components/tooltip/golden/arrow_right.png b/test/src/components/tooltip/golden/arrow_right.png index 30d99000c0bec9ab95a4b899e8d2f3732b6d8e53..12a63dee30af88aac3fe90aa3c059ab7e6a4fe4a 100644 GIT binary patch delta 583 zcmV-N0=WIZ9J(BkL4V{)L_t(|obBB~jud48hT*?kw=+8lE_8#;W)jXIObj-5#vcjn#!@Acyk z-;bL&znFUl003L~;N;|=Z~uDxcJ3YUUT^+h*7PZ-9+Bs{jDY zw>~*JnR^3l#90LZSibe#0{{Ski{r!7K3uQYRX7vlOc#(4Si z<#>07>(An%-GBcv&i8%-05HE(1LUJim&Q-O{9J8Wr0btwAAg_IkN7X*{Xft92>`(S zJc7ldJbd_Q?g;<@Y(apqC=b7TBtifH7EFM!I3ff9V7UYcizGq-0G3IB0000P0m33Z z_~!n2@ZkR3GXMZMBLTwVhz|gOb4X_bs z6#!uQ)>l8fGWQ19h_ea+uzc$~cW%$U0XE{S0st)EYMQ3$@bJZW^7Pp_I(jvZkB{fx z1pnFH-5wo#dsoN3ySK-|!Hv1+006M1)ih0hgbn}zB>W98v!Mfs3bQ~1Kmiw-e*rJ+ Vo~|aXkLmyb002ovPDHLkV1oR_9lHPk delta 588 zcmV-S0<-YVP%C}iGvWgPVBQ4C zhHl@veX8rdXm2y(0{~#&Jc0!P0AvIR0059#yz}n%YU&ZNu4lg;PCWqtfDJ6qojW)6 z23U);3IH&F%ZuCFQ*VH^II92v^S8YI>HgFkU@gun0Koh$PF}254<0=nckkaDj}M=W zqobp#HzdJ-wzjs$<%^fbjcfbk>fV*9=Kuh(p~cCIl^>x4000Sp!wa*K1Ck1}5Cb*= a7Uo~A&z^b-vPoM20000lb6jSEWBo@@7srr_IdAW7>x#HkF@FpYdk6VH$tdmZ9NpQB93e-~4$od&LwPa+31jF*3ZV@8f^`_{YnWSJx{t z7_>4lCQJhIU)2gS9bgmt$IN7K_vq2ng}?sP#Ki5BTYWX_o#mN~oiTmQ&9@(aT+IIX z#fy7)iW$n<7#L@~INH7cn7_UKoNBh{7u(~{AN%{;{+umyg8B|t?u12~H-Fx#zG3Mc z-iDVf90y$1-~VI#on_mU&5ZR1b3vN#?k+F(Pw=*sX1L5Lz`&sJ*s+CS{=s|q?(Hak ze(uR@@$RD%-A5z#*Z+5ou|FoUK5nnnd-EN2!n5oCU*F5#&@Ze2RDIn%ujl^%KgsVT zqu;*cFF#(Ne?RVYdi|;I^>eEkepqZzU}RvBWMpDsNMYe%V3;7Nz`)?(Hu(UfK)s9r zgHU^W`{UWO&DG=U@A7lq*=EZS&&9~(@aX2t&AsdPzhh_3yDitC-x|GvfuW&?0ces@ z_t&bu^Qu`6=>7P%I~wTt?!Uj!&)%ud@P=i71B1_&{rl}9K7@Gi+uHZf=N*_x38!|H9I6!1L11-)w$h3JP(_-$)3CsdwpY5%_Es{8}NV16m O2s~Z=T-G@yGywo?&mM08 delta 605 zcmV-j0;2uL9LgM!L4Wi~L_t(|obBDQZk1&K$Km%huI(nl$$^3cNw2|z#w)P|3?^O) zq!dW&uHJ%C;2zk7GPvQ|4s5NH3?wAqG4%JHlRnSZ$-De=zLRfp_U`)jPcX`A7@?yz`FTt?g0R-mj{pb$HRmD_kW8J0G6>a_kREY*2jnO@$g{({kI_i zFoggCV3H5x<3Azn&wKZ;RUmy4O?u^^J zx8|M$ur>q;z(l|Q`N!D%;qKfsSV2dRpN{Xo`F8FZ0BgY`SO60}{rPb239Kl017JD< z0x;3>n>TY$V1Grq8vxS@5P*qJPfzEbz>0D=0HzZl002P7iwFTefsKugv9q%?`TSzB z7-O**=Vxb^;`|t6ynOj`oGo#F8OwhD7rh67j}ssOpTOr=u8d!P`*rRaD{c4d-SN-c zw-@ri|Ig=tk$V96IFDcf000>Q0ssJH1PA~CkP#pN0F%4{5`P{L01`KE-W*?Cy*l~) zMZYL;)%E~f76Jr-#KGf(rOsdUivm||55Q&N5i9@zAR|Bk0D#Qm?A`hK+#>+i!Ixic z&pm+^_V-`Mb58(R3%&sXm}qlzbM6VOD0c&3IspPO(e|}#b5CGJxf=k}2@rsZ?tXt~ z?g^|YcLQKLzcK*nR^a1+S=M0H@2^jdwX}r?cG~*&jDB) r0t5g6$an+`vjGDz3zMJ%gBHxcXdI#o%XrL>00000NkvXXu0mjfFCiM{ diff --git a/test/src/components/tooltip/tooltip_test.dart b/test/src/components/tooltip/tooltip_test.dart index 6f055db4..fa0ea5fd 100644 --- a/test/src/components/tooltip/tooltip_test.dart +++ b/test/src/components/tooltip/tooltip_test.dart @@ -1,17 +1,18 @@ -import 'dart:io'; +// ignore_for_file: avoid_dynamic_calls import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:path/path.dart' as p; +import 'package:path/path.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; import '../../../test_utils/test_app.dart'; import '../../../test_utils/tolerant_comparator.dart'; +import '../../../test_utils/utils.dart'; void main() { setUpAll(() { - final testUri = Uri.parse(p.join(Directory.current.path, 'golden').replaceAll(r'\', '/')); + final testUri = Uri.parse(getCurrentPath('tooltip')); goldenFileComparator = TolerantComparator(testUri, tolerance: 0.01); }); @@ -108,7 +109,7 @@ void main() { // Verifying the CustomPaint with different arrow directions. await expectLater( find.byType(ZetaTooltip), - matchesGoldenFile(p.join('golden', 'arrow_up.png')), + matchesGoldenFile(join(getCurrentPath('tooltip'), 'arrow_up.png')), ); }); @@ -128,7 +129,7 @@ void main() { // Verifying the CustomPaint with different arrow directions. await expectLater( find.byType(ZetaTooltip), - matchesGoldenFile(p.join('golden', 'arrow_down.png')), + matchesGoldenFile(join(getCurrentPath('tooltip'), 'arrow_down.png')), ); }); @@ -149,7 +150,7 @@ void main() { // Verifying the CustomPaint with different arrow directions. await expectLater( find.byType(ZetaTooltip), - matchesGoldenFile(p.join('golden', 'arrow_left.png')), + matchesGoldenFile(join(getCurrentPath('tooltip'), 'arrow_left.png')), ); }); @@ -170,7 +171,7 @@ void main() { // Verifying the CustomPaint with different arrow directions. await expectLater( find.byType(ZetaTooltip), - matchesGoldenFile(p.join('golden', 'arrow_right.png')), + matchesGoldenFile(join(getCurrentPath('tooltip'), 'arrow_right.png')), ); }); @@ -224,24 +225,12 @@ void main() { child: Text('Rounded tooltip'), ).debugFillProperties(diagnostics); - final rounded = diagnostics.properties.where((p) => p.name == 'rounded').map((p) => p.toDescription()).first; - expect(rounded, 'null'); - - final padding = diagnostics.properties.where((p) => p.name == 'padding').map((p) => p.toDescription()).first; - expect(padding, 'EdgeInsets.all(8.0)'); - - final color = diagnostics.properties.where((p) => p.name == 'color').map((p) => p.toDescription()).first; - expect(color.toLowerCase(), contains(Colors.amber.hexCode.toLowerCase())); - - final textStyle = diagnostics.properties.where((p) => p.name == 'textStyle').map((p) => p.toDescription()).first; - expect(textStyle, contains('size: 9.0')); - - final direction = - diagnostics.properties.where((p) => p.name == 'arrowDirection').map((p) => p.toDescription()).first; - expect(direction, 'down'); - - final maxWidth = diagnostics.properties.where((p) => p.name == 'maxWidth').map((p) => p.toDescription()).first; - expect(maxWidth, '170.0'); + expect(diagnostics.finder('rounded'), 'null'); + expect(diagnostics.finder('padding'), 'EdgeInsets.all(8.0)'); + expect(diagnostics.finder('color').toLowerCase(), contains(Colors.amber.hexCode.toLowerCase())); + expect(diagnostics.finder('textStyle'), contains('size: 9.0')); + expect(diagnostics.finder('arrowDirection'), 'down'); + expect(diagnostics.finder('maxWidth'), '170.0'); }); }); } diff --git a/test/src/theme/color_swatch_test.dart b/test/src/theme/color_swatch_test.dart index 8bf33200..11eadba5 100644 --- a/test/src/theme/color_swatch_test.dart +++ b/test/src/theme/color_swatch_test.dart @@ -160,4 +160,23 @@ void main() { expect(aaaSwatch.surface.value, Colors.blue.shade100.value); }); }); + + testWidgets('Light / Dark mode are inverted', (tester) async { + final ZetaColors light = ZetaColors(); + final ZetaColors dark = ZetaColors(brightness: Brightness.dark); + + expect(light.primary.shade10, dark.primary.shade100); + expect(light.primary.shade20, dark.primary.shade90); + expect(light.primary.shade30, dark.primary.shade80); + expect(light.primary.shade40, dark.primary.shade70); + expect(light.primary.shade50, dark.primary.shade60); + }); + + testWidgets('AAA mode value colors are 2 shades darker', (tester) async { + final ZetaColors aa = ZetaColors(); + final ZetaColors aaa = ZetaColors(brightness: Brightness.dark, contrast: ZetaContrast.aaa); + + expect(aa.primary.value, aa.primary.shade60.value); + expect(aaa.primary.value, aaa.primary.shade80.value); + }); } diff --git a/example/test/rounded_test.dart b/test/src/utils/rounded_test.dart similarity index 73% rename from example/test/rounded_test.dart rename to test/src/utils/rounded_test.dart index 1d5aa5b8..60ee61a4 100644 --- a/example/test/rounded_test.dart +++ b/test/src/utils/rounded_test.dart @@ -1,19 +1,19 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; - -import 'test_components.dart'; +import '../../test_utils/test_app.dart'; void main() { testWidgets('Global round inherited', (WidgetTester tester) async { - GlobalKey key = GlobalKey(); + final GlobalKey key = GlobalKey(); await tester.pumpWidget( - TestWidget( + TestApp( rounded: true, - widget: ZetaAccordion( + home: ZetaAccordion( key: key, title: 'Test Accordion', - child: ZetaStatusLabel(label: 'Label'), + child: const ZetaStatusLabel(label: 'Label'), ), ), ); @@ -34,9 +34,9 @@ void main() { testWidgets('Global sharp inherited', (WidgetTester tester) async { await tester.pumpWidget( - TestWidget( + const TestApp( rounded: false, - widget: ZetaAccordion( + home: ZetaAccordion( title: 'Test Accordion', child: ZetaStatusLabel(label: 'Label'), ), @@ -56,14 +56,14 @@ void main() { }); testWidgets('Global sharp, local round, not inherited', (WidgetTester tester) async { - GlobalKey key = GlobalKey(); + final GlobalKey key = GlobalKey(); await tester.pumpWidget( - TestWidget( + TestApp( rounded: false, - widget: ZetaAccordion( + home: ZetaAccordion( key: key, title: 'Test Accordion', - child: ZetaStatusLabel(label: 'Label', rounded: true), + child: const ZetaStatusLabel(label: 'Label', rounded: true), ), ), ); @@ -82,13 +82,13 @@ void main() { }); testWidgets('Global sharp, scoped round inherited', (WidgetTester tester) async { - final Key sharpKey = Key('sharp'); - final Key roundKey = Key('round'); + const Key sharpKey = Key('sharp'); + const Key roundKey = Key('round'); await tester.pumpWidget( - TestWidget( + const TestApp( rounded: false, - widget: Column( + home: Column( children: [ ZetaStatusLabel(label: 'Label', key: sharpKey), ZetaRoundedScope( @@ -126,13 +126,13 @@ void main() { }); testWidgets('Global sharp, scoped round, scoped sharp inherited', (WidgetTester tester) async { - final Key sharpKey = Key('sharp'); - final Key sharpKey2 = Key('round'); + const Key sharpKey = Key('sharp'); + const Key sharpKey2 = Key('round'); await tester.pumpWidget( - TestWidget( + const TestApp( rounded: false, - widget: Column( + home: Column( children: [ ZetaStatusLabel(label: 'Label', key: sharpKey), ZetaRoundedScope( @@ -168,4 +168,35 @@ void main() { expect(roundBox.decoration.runtimeType, BoxDecoration); expect((roundBox.decoration as BoxDecoration).borderRadius, ZetaRadius.none); }); + + testWidgets('ZetaRoundedScope debugFillProperties works correctly', (WidgetTester tester) async { + final diagnostics = DiagnosticPropertiesBuilder(); + + const ZetaRoundedScope(rounded: true, child: SizedBox()).debugFillProperties(diagnostics); + + final rounded = diagnostics.properties.where((p) => p.name == 'rounded').map((p) => p.toDescription()).first; + expect(rounded, 'true'); + }); + + testWidgets('ZetaStatefulWidget debugFillProperties works correctly', (WidgetTester tester) async { + final diagnostics = DiagnosticPropertiesBuilder(); + const _RoundedStateTestWidget(rounded: true).debugFillProperties(diagnostics); + + final rounded = diagnostics.properties.where((p) => p.name == 'rounded').map((p) => p.toDescription()).first; + expect(rounded, 'true'); + }); +} + +class _RoundedStateTestWidget extends ZetaStatefulWidget { + const _RoundedStateTestWidget({super.rounded}); + + @override + State<_RoundedStateTestWidget> createState() => _RoundedStateTestWidgetState(); +} + +class _RoundedStateTestWidgetState extends State<_RoundedStateTestWidget> { + @override + Widget build(BuildContext context) { + return const Placeholder(); + } } diff --git a/test/test_utils/test_app.dart b/test/test_utils/test_app.dart index cbb5180b..6e2396fb 100644 --- a/test/test_utils/test_app.dart +++ b/test/test_utils/test_app.dart @@ -1,22 +1,64 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; class TestApp extends StatelessWidget { - const TestApp({super.key, required this.home}); + const TestApp({ + super.key, + required this.home, + this.screenSize, + this.themeMode, + this.removeBody = true, + this.rounded, + }); + final Widget home; + final Size? screenSize; + final ThemeMode? themeMode; + final bool removeBody; + final bool? rounded; @override Widget build(BuildContext context) { return ZetaProvider( + initialThemeMode: themeMode ?? ThemeMode.system, + initialThemeData: ZetaThemeData(rounded: rounded ?? true), builder: (context, themeData, themeMode) { return MaterialApp( - home: Builder( - builder: (context) { - return home; - }, + theme: ThemeData( + fontFamily: themeData.fontFamily, + colorScheme: themeData.colorsLight.toScheme(), + textTheme: zetaTextTheme, + ), + darkTheme: ThemeData( + fontFamily: themeData.fontFamily, + colorScheme: themeData.colorsDark.toScheme(), + textTheme: zetaTextTheme, + ), + home: Scaffold( + body: removeBody + ? home + : SizedBox( + width: screenSize?.width, + height: screenSize?.height, + child: MediaQuery( + data: MediaQueryData(size: Size(screenSize?.width ?? 0, screenSize?.height ?? 0)), + child: SingleChildScrollView(child: home), + ), + ), ), ); }, ); } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('screenSize', screenSize)) + ..add(EnumProperty('themeMode', themeMode)) + ..add(DiagnosticsProperty('removeBody', removeBody)) + ..add(DiagnosticsProperty('rounded', rounded)); + } } diff --git a/test/test_utils/utils.dart b/test/test_utils/utils.dart new file mode 100644 index 00000000..21ea3356 --- /dev/null +++ b/test/test_utils/utils.dart @@ -0,0 +1,14 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:path/path.dart'; + +String getCurrentPath(String component, {String type = 'components'}) { + return join(Directory.current.path, 'test', 'src', type, component, 'golden'); +} + +extension Util on DiagnosticPropertiesBuilder { + dynamic finder(String finder) { + return properties.where((p) => p.name == finder).map((p) => p.toDescription()).first; + } +}