From 889164bf621d0ad8cee781a9f6981a309be44564 Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Tue, 15 Oct 2024 14:37:30 +0100 Subject: [PATCH] tests: organised chat item, checkbox, chip, dialpad, fab, icon, in page banner, password, search bar, slider, stepper input, and, tooltip --- .../{TESTING_README.mdx => TESTING_README.md} | 30 +- test/src/components/badge/label_test.dart | 2 +- .../components/badge/priority_pill_test.dart | 15 - test/src/components/button/button_test.dart | 8 +- .../components/chat_item/chat_item_test.dart | 17 +- .../components/checkbox/checkbox_test.dart | 2 +- test/src/components/chips/chip_test.dart | 3 - test/src/components/dialpad/dialpad_test.dart | 333 ++++++++++-------- .../dialpad/golden/dialpad_disabled.png | Bin 11188 -> 8944 bytes .../dialpad/golden/dialpad_enabled.png | Bin 11188 -> 8944 bytes .../dialpad/golden/dialpadbutton.png | Bin 4708 -> 4315 bytes test/src/components/fab/fab_test.dart | 271 ++++++++++++++ test/src/components/fabs/fab_test.dart | 219 ------------ .../components/fabs/golden/FAB_default.png | Bin 4754 -> 0 bytes .../components/fabs/golden/FAB_disabled.png | Bin 4446 -> 0 bytes .../components/fabs/golden/FAB_inverse.png | Bin 4352 -> 0 bytes .../components/fabs/golden/FAB_pressed.png | Bin 4883 -> 0 bytes .../components/fabs/golden/FAB_secondary.png | Bin 3599 -> 0 bytes test/src/components/icon/icon_test.dart | 104 +++--- .../in_page_banner/in_page_banner_test.dart | 228 +++++++----- .../password/password_input_test.dart | 159 +++++---- .../search_bar/search_bar_test.dart | 180 ++++------ test/src/components/slider/slider_test.dart | 78 ++-- .../stepper input/stepper_input_test.dart | 62 ---- .../stepper_input/stepper_input_test.dart | 95 +++++ test/src/components/tooltip/tooltip_test.dart | 226 ++++++------ test/test_utils/utils.dart | 30 +- 27 files changed, 1143 insertions(+), 919 deletions(-) rename test/{TESTING_README.mdx => TESTING_README.md} (82%) create mode 100644 test/src/components/fab/fab_test.dart delete mode 100644 test/src/components/fabs/fab_test.dart delete mode 100644 test/src/components/fabs/golden/FAB_default.png delete mode 100644 test/src/components/fabs/golden/FAB_disabled.png delete mode 100644 test/src/components/fabs/golden/FAB_inverse.png delete mode 100644 test/src/components/fabs/golden/FAB_pressed.png delete mode 100644 test/src/components/fabs/golden/FAB_secondary.png delete mode 100644 test/src/components/stepper input/stepper_input_test.dart create mode 100644 test/src/components/stepper_input/stepper_input_test.dart diff --git a/test/TESTING_README.mdx b/test/TESTING_README.md similarity index 82% rename from test/TESTING_README.mdx rename to test/TESTING_README.md index 0789e872..a9e4f8eb 100644 --- a/test/TESTING_README.mdx +++ b/test/TESTING_README.md @@ -11,24 +11,34 @@ As you are writing tests think about helper function you could write and add the ### Groups -- Accessibility Tests +- **Accessibility Tests** Semantic labels, touch areas, contrast ratios, etc. -- Content Tests - Finds the widget, parameter statuses, etc. -- Dimensions Tests - Size, padding, margin, alignment, etc. -- Styling Tests + +- **Content Tests** + Finds the widget, parameter statuses, etc. + Checking for the value of props and attributes of the widget. Checking for the presence of widgets. + +- **Dimensions Tests** + Size, padding, margin, alignment, etc. + getSize(). + +- **Styling Tests** Rendered colors, fonts, borders, radii etc. -- Interaction Tests + Checking the style of widgets and child widgets. + +- **Interaction Tests** Gesture recognizers, taps, drags, etc. -- Golden Tests + For example, using a boolean to check if the widgets interaction function runs. + +- **Golden Tests** Compares the rendered widget with the golden file. Use the `goldenTest()` function from test_utils/utils.dart. -- Performance Tests + +- **Performance Tests** Animation performance, rendering performance, data manupulation performance, etc. ### Testing File Template -``` +```dart import 'dart:ui'; import 'package:flutter/foundation.dart'; diff --git a/test/src/components/badge/label_test.dart b/test/src/components/badge/label_test.dart index 28522281..ec6d7c23 100644 --- a/test/src/components/badge/label_test.dart +++ b/test/src/components/badge/label_test.dart @@ -130,7 +130,7 @@ void main() { ZetaLabel, 'label_neutral', ); - goldenTest(goldenFile, const ZetaLabel(label: 'Test Label'), ZetaLabel, 'label_dark', darkMode: true); + goldenTest(goldenFile, const ZetaLabel(label: 'Test Label'), ZetaLabel, 'label_dark', themeMode: ThemeMode.dark); goldenTest(goldenFile, const ZetaLabel(label: 'Test Label', rounded: false), ZetaLabel, 'label_sharp'); }); group('$componentName Performance Tests', () {}); diff --git a/test/src/components/badge/priority_pill_test.dart b/test/src/components/badge/priority_pill_test.dart index e70ddba4..44302011 100644 --- a/test/src/components/badge/priority_pill_test.dart +++ b/test/src/components/badge/priority_pill_test.dart @@ -84,11 +84,6 @@ void main() { expect(zetaPriorityPill.size, ZetaPriorityPillSize.small); expect(find.text('test label'), findsOneWidget); - - await expectLater( - find.byType(ZetaPriorityPill), - matchesGoldenFile(goldenFile.getFileUri('priority_pill_high')), - ); }); testWidgets('Medium priority pill', (WidgetTester tester) async { await tester.pumpWidget( @@ -104,11 +99,6 @@ void main() { final ZetaPriorityPill zetaPriorityPill = tester.firstWidget(zetaPriorityPillFinder); expect(zetaPriorityPill.type, ZetaPriorityPillType.medium); expect(zetaPriorityPill.isBadge, true); - - await expectLater( - find.byType(ZetaPriorityPill), - matchesGoldenFile(goldenFile.getFileUri('priority_pill_medium')), - ); }); testWidgets('Low priority pill', (WidgetTester tester) async { await tester.pumpWidget( @@ -126,11 +116,6 @@ void main() { expect(zetaPriorityPill.type, ZetaPriorityPillType.low); expect(zetaPriorityPill.isBadge, true); expect(zetaPriorityPill.size, ZetaPriorityPillSize.small); - - await expectLater( - find.byType(ZetaPriorityPill), - matchesGoldenFile(goldenFile.getFileUri('priority_pill_low')), - ); }); }); group('$componentName Dimensions Tests', () {}); diff --git a/test/src/components/button/button_test.dart b/test/src/components/button/button_test.dart index 87d674b7..4e4ddb9b 100644 --- a/test/src/components/button/button_test.dart +++ b/test/src/components/button/button_test.dart @@ -284,8 +284,12 @@ void main() { ZetaButton, 'button_outline', ); - goldenTest(goldenFile, const ZetaButton.outlineSubtle(label: 'Test Button', borderType: ZetaWidgetBorder.sharp), - ZetaButton, 'button_outline_subtle'); + goldenTest( + goldenFile, + const ZetaButton.outlineSubtle(label: 'Test Button', borderType: ZetaWidgetBorder.sharp), + ZetaButton, + 'button_outline_subtle', + ); goldenTest( goldenFile, ZetaButton.text(onPressed: () {}, label: 'Test Button', borderType: ZetaWidgetBorder.full), diff --git a/test/src/components/chat_item/chat_item_test.dart b/test/src/components/chat_item/chat_item_test.dart index 0184fb7d..43ee381c 100644 --- a/test/src/components/chat_item/chat_item_test.dart +++ b/test/src/components/chat_item/chat_item_test.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:intl/intl.dart'; @@ -520,7 +519,7 @@ void main() { const subtitle = Text('Hello, how are you?'); final time = DateTime.now(); - goldenTest( + goldenTestWithCallbacks( goldenFile, Scaffold( body: Column( @@ -554,7 +553,7 @@ void main() { }, ); - goldenTest( + goldenTestWithCallbacks( goldenFile, Column( children: [ @@ -588,7 +587,7 @@ void main() { }, ); - goldenTest( + goldenTestWithCallbacks( goldenFile, Column( children: [ @@ -619,7 +618,7 @@ void main() { }, ); - goldenTest( + goldenTestWithCallbacks( goldenFile, Column( children: [ @@ -659,7 +658,7 @@ void main() { }, ); - goldenTest( + goldenTestWithCallbacks( goldenFile, Column( children: [ @@ -704,7 +703,7 @@ void main() { }, ); - goldenTest( + goldenTestWithCallbacks( goldenFile, Column( children: [ @@ -734,7 +733,7 @@ void main() { }, ); - goldenTest( + goldenTestWithCallbacks( goldenFile, Column( children: [ @@ -771,7 +770,7 @@ void main() { }, ); - goldenTest( + goldenTestWithCallbacks( goldenFile, Column( children: [ diff --git a/test/src/components/checkbox/checkbox_test.dart b/test/src/components/checkbox/checkbox_test.dart index 50cb7dd7..54e28a1d 100644 --- a/test/src/components/checkbox/checkbox_test.dart +++ b/test/src/components/checkbox/checkbox_test.dart @@ -140,7 +140,7 @@ void main() { }); }); group('$componentName Golden Tests', () { - goldenTest( + goldenTestWithCallbacks( goldenFile, ZetaCheckbox( onChanged: (value) {}, diff --git a/test/src/components/chips/chip_test.dart b/test/src/components/chips/chip_test.dart index fa97e52c..eed6dd86 100644 --- a/test/src/components/chips/chip_test.dart +++ b/test/src/components/chips/chip_test.dart @@ -1,6 +1,3 @@ -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; diff --git a/test/src/components/dialpad/dialpad_test.dart b/test/src/components/dialpad/dialpad_test.dart index 33bf66fe..2b9aa942 100644 --- a/test/src/components/dialpad/dialpad_test.dart +++ b/test/src/components/dialpad/dialpad_test.dart @@ -1,6 +1,5 @@ import 'dart:ui'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; @@ -10,13 +9,65 @@ import '../../../test_utils/tolerant_comparator.dart'; import '../../../test_utils/utils.dart'; void main() { - const goldenFile = GoldenFiles(component: 'dialpad'); + const String componentName = 'ZetaDialPad'; + const String parentFolder = 'dialpad'; + const goldenFile = GoldenFiles(component: parentFolder); setUpAll(() { goldenFileComparator = TolerantComparator(goldenFile.uri); }); - group('ZetaDialPad Tests', () { + group('$componentName Accessibility Tests', () {}); + + group('$componentName Content Tests', () { + final debugFillProperties = { + 'onNumber': 'null', + 'onText': 'null', + 'buttonsPerRow': '3', + 'buttonValues': '{1: , 2: ABC, 3: DEF, 4: GHI, 5: JKL, 6: MNO, 7: PQRS, 8: TUV, 9: WXYZ, *: , 0: +, #: }', + }; + debugFillPropertiesTest( + const ZetaDialPad(), + debugFillProperties, + ); + + final debugFillPropertiesSingleButton = { + 'primary': '"1"', + 'secondary': '""', + 'onTap': 'null', + 'topPadding': '3.0', + }; + debugFillPropertiesTest( + const ZetaDialPadButton(primary: '1'), + debugFillPropertiesSingleButton, + ); + }); + + group('$componentName Dimensions Tests', () {}); + + group('$componentName Styling Tests', () { + testWidgets('Hover styles for button are correct', (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); + }); + }); + + group('$componentName Interaction Tests', () { testWidgets('Initializes with correct parameters and is enabled', (WidgetTester tester) async { String number = ''; String text = ''; @@ -25,10 +76,6 @@ void main() { await tester.pumpWidget( TestApp( - // before: (tester) async { - // tester.view.devicePixelRatio = 1.0; - // tester.view.physicalSize = const Size(481, 480); - // }, screenSize: const Size(1000, 1000), home: ZetaDialPad( onNumber: (value) => number += value, @@ -127,163 +174,139 @@ void main() { /// Allow all timers to end in text debounce await debounceWait(); + }); - await expectLater( - dialPadFinder, - matchesGoldenFile(goldenFile.getFileUri('dialpad_enabled')), + 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(), + ), ); - }); - }); - testWidgets('Initializes with correct parameters and is disabled', (WidgetTester tester) async { - const String number = ''; - const String text = ''; + final dialPadFinder = find.byType(ZetaDialPad); + final buttonFinder = find.byType(ZetaDialPadButton); - Future debounceWait() => tester.binding.delayed(const Duration(milliseconds: 500)); + 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 == '#'); - 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(goldenFile.getFileUri('dialpad_disabled')), - ); - }); - 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 ZetaDialPad dialPad = tester.firstWidget(dialPadFinder); + final List dialPadButtons = tester.widgetList(buttonFinder).toList(); - 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(); + final ZetaDialPadButton one = tester.firstWidget(oneFinder); + final ZetaDialPadButton two = tester.firstWidget(twoFinder); + final ZetaDialPadButton three = tester.firstWidget(threeFinder); - expect(inkWell.overlayColor?.resolve({WidgetState.hovered}), ZetaColorBase.cool.shade20); + /// Dial Pad built correctly. + expect(dialPad.buttonsPerRow, 3); + expect(dialPadButtons.length, 12); - await expectLater( - buttonFinder, - matchesGoldenFile(goldenFile.getFileUri('dialpadbutton')), - ); - }); + /// 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'); - testWidgets('debugFillProperties works correctly', (WidgetTester tester) async { - final diagnostics = DiagnosticPropertiesBuilder(); - const ZetaDialPad().debugFillProperties(diagnostics); + /// Tap button with only number. + await tester.tap(oneFinder); + await tester.pump(); + expect(number, ''); - 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: +, #: }', - ); + /// 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(); + }); + }); - 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'); + group('$componentName Golden Tests', () { + goldenTest( + goldenFile, + const ZetaDialPad( + onNumber: print, + onText: print, + ), + ZetaDialPad, + 'dialpad_enabled', + screenSize: const Size(1000, 1000), + ); + goldenTest( + goldenFile, + const ZetaDialPad(), + ZetaDialPad, + 'dialpad_disabled', + screenSize: const Size(1000, 1000), + ); + goldenTest( + goldenFile, + const ZetaDialPadButton(primary: '1'), + ZetaDialPadButton, + 'dialpadbutton', + screenSize: const Size(1000, 1000), + ); }); + + group('$componentName Performance Tests', () {}); } diff --git a/test/src/components/dialpad/golden/dialpad_disabled.png b/test/src/components/dialpad/golden/dialpad_disabled.png index 5ee42187fe4268ea5ce61ab1da2bb74cea5c4acc..2e70f9684a5b9acdaa7b08d32d0641753a4bc297 100644 GIT binary patch literal 8944 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 P2IRP@rAf)rv)BF$Tg3QZ diff --git a/test/src/components/dialpad/golden/dialpad_enabled.png b/test/src/components/dialpad/golden/dialpad_enabled.png index 5ee42187fe4268ea5ce61ab1da2bb74cea5c4acc..2e70f9684a5b9acdaa7b08d32d0641753a4bc297 100644 GIT binary patch literal 8944 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 P2IRP@rAf)rv)BF$Tg3QZ diff --git a/test/src/components/dialpad/golden/dialpadbutton.png b/test/src/components/dialpad/golden/dialpadbutton.png index 7bbc925e25b8127a7558cc62e7e3f9cc4306d4e2..efb8765e5ae7bc476f4a3d1f77798bfd9fa81061 100644 GIT binary patch literal 4315 zcmeHK>r)d~6u$|KP>N#52S{QPr!%%z3nB_pd1*CBTcG2kg`&V1gz_j6Q4?Yy(T<`L zi8dW0f@G8_DI&y}3WNj@kwj}EV|k<+6LdBy6#^PGK*+0i{m_4)_$~Wk@7%lh{?0kS zbAD%c&wP^pRVvrGpww3xQYD4Ti3qK^#84m zTgY9X>b=AKtROBKQE$YpSaQ-}uncJR(j%p%9Rvt{{KTJ z$4(PxdWi0~2QIR%b-7G^d{-F&&$Y!^EC5;Fz5ty6hy*|!g#$sBVdh{lo641>i$#VD zx_kNa0H;Bt45H@e=Z`LzB`UH3xO6$~CUjA)ZrTCO9%%W#sot=*DzWn@d~}y0i0Cy-=%kg+_MMXse-53%QqU`SO9tZ~@ zvrgU8(gI^RV`WB1SW)AjNyC&ge^=9#CX;C(ZJj_Mpt9NQ(PaSKEQ0J59Xz=9QD2|P z@N78N zj}6V}JUk0oT4W0%1rVZw0s{k)(b2r8+v)$z&N6F+LS9{6-MfR7*&tF{S{l;*lMiBh zGtwW@{za_wZ9h3CW@>6RYgm#f<~5iJGi{Od{;6CaL#S8n*sBEg@V6!AC-0|^o%iEXzxl8rOKS{1dr;?O4 z_5bbQh7qEf>mj}?wAQD@<*>CW6nGvX`Z5y=s6fHSk>qkYVt>^|%*n|?G}V#L>!HSR zT`OWX7u3|$aP@k9!wAZRy%n?0Fnsn1ixpMou&9PjjV0pdW@W!9S!J`Bzr^TdxW_#ohlxY*SkNA5XD$)#X}`@xPwVlu0>BDJ_junF`1jv z6^zF>X8l9c6+t4Ah)DYw3agWlrqyc4+*ZNRn3XYUe2@|%pu(8>e7<<1$59r5gL&_F zUI(`4riTKgw<3^AqtQ^eVfo1SO|NeHwh_f{hK@ofbv64Yje| zF7l>L!8)Ce-uk+$O(t80GBMcr9knB!$LB8+T4BaBB*S6V_B`2%$ZqKHkh9x3T zwSD-?(1AnuTgSBMej6*MZ01F|q_tJxKo#H5+R5RDDPdL^*3m)o=FPas$Ve(TY(YSP zs^i%7gzT^z~6Q)|ZUovClqpKGmnjk-DHQ&&(h3!&lcx7d!^2Lj*J{k;oPB%)ujKYpG zCsR@KCL7kO+dKkOPo>l8X0w@VW4WYa#QFIiSdoYpqM@8wt=8C6g+HQ}ieR8c493i_ zE1@@6LxV{~sM|`YOP(l@m_#XSgpn_;=p~cMK^47sbA14CJklp{9DhQLw)XbfC#zKD zVx;s3$K>HGm?QJVgu%KVHjrP?W_Txv$~dxk?wjKKXtW+ow69ZOE1#PemxoUepPpKJ vPhW)|ae2h$5tm0?bN;*OX)OP*vDk17)<9wA!uEYoo*-d+(zfQUnJ4}QjZ7Nk literal 4708 zcmeH~`&Uy}7Jv^RNJWe~BX0th&I{UUbvz z_W{_u>-6zs!FL}irKBJ`d~xS{lBM)YOXT5=m*{3A+ux zu-9xOZyga5d6rgQ*gxvNe^2o9$@|XMsYl21!gyBB{D=(-YHc}5#PO8cC^26jmPGZf zCNC}Ly?rH@r^%11(xGP~X=94jAlD~l%HDR&q+IWLO2!xnL6tRxaDtfJvA>V_2?aTPQy|g@`MZY{?B#d@w4uHv?KU`LrGMn+WXG$o1-W zF%s$EZi8D_*6PFRr&E26VAKU}x_ZQ8R|z|PL#>}t$W&C!5ji0PEB7l9X#h9ulXYPx&bs@>bB2+sYt2~5D$F@!+1C$H|bjZ z!FAtRN~;G%Dvid6{MtkQbnR!P-@3qEvZzbS;4;6?)u(-w;C4Bk4a_dGZ#s z)^DKB@VbkiWG;5j;yJ4<6aZnP+_;M<`=Y6bVg#7OqZuGf){mb{jZ$q9bhYLeHrsym zpXK|x)&S^|k&Z?qyR80zJEc@Z2>pI^=34e@zIYb^j9Zy&hra`xHp)zbqcUG%20*HC z=ljJMdDe>(Xo5JGbCS^~EZJXc|7j=KTw5@|`My}x22p~{04BVDeNL2L@)G&U!m-wR zsk$`tw`2gOjt!WvBJ(%Zb;3l_Q!`=BlHRnt;LZF23N&`1E|K-6gu)t)PoS$sC6$ck zi&v}wIASG;Z=RxM%APBqsrCSH<$O{7z=O7^DM9@0!4*@ea8MwTg!7C>jH3&(i_ZRy zk!JuvM*rE$0ne0#cPnq8)+aPSNeY+uGB9G#5V+&2oBz_Hh|K&Gg(Tk00 zo4ig20;VBDJ!i8(TbUEReSfT^{RzITtU3`B z8@ucSz2Dj23aoQZ@_0O4Er~yyP)yOJs&2$kskD##pbO<%4GE1#&rD6t$F}XMrYNSS zp2D@R80OBTTB}4PCnwKn`}%Z0e+c){Yr~YYvrC(SN>ql|(GPKAUQ%3E?lr!Qc7Z4! z{1&aC{S^SK=W^pyI8jFyf|8zIiRQ9pLC%A`fmBU$~HU8ec@LREdF@dLimVD=q zR0B)Q<9`)K@u%_PujPS>N#4FSmVN2mh8T)BQtTn8 zU!qVbFJKokdvuo!F5*NDF-nz6ER#iiRWM2If=6B81Vy39A>70+Gh%DaSXqjX{zE03 z9Uc}|B@hTw=SPpB1kNRu5LW7PrO~**I7#Jyy)HBuCwl$5361prb$Yfs+&X>8nA!6x z+FpR5=tU8{7y=Fl(V;y&D3OsJ851xi+4S4YHHku8s~8OcEu)JNhDZ8Egpv1}mu3wtMO~;d) z!)9}e?QsOa??*Vhwp6zWY!TQZuti{tz!rfm0$T*O2>iJSOy~`I&XeYO7}_oPFAh$h Lz#ixNU%B^xa#P#` diff --git a/test/src/components/fab/fab_test.dart b/test/src/components/fab/fab_test.dart new file mode 100644 index 00000000..31f4adc7 --- /dev/null +++ b/test/src/components/fab/fab_test.dart @@ -0,0 +1,271 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.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() { + const String componentName = 'ZetaFAB'; + const String parentFolder = 'fab'; + + const goldenFile = GoldenFiles(component: parentFolder); + setUpAll(() { + goldenFileComparator = TolerantComparator(goldenFile.uri); + }); + + group('$componentName Accessibility Tests', () {}); + + group('$componentName Content Tests', () { + final debugFillProperties = { + 'label': 'null', + 'onPressed': 'null', + 'type': 'primary', + 'size': 'small', + 'shape': 'full', + 'icon': 'IconData(U+0E009)', + 'initiallyExpanded': 'false', + 'focusNode': 'null', + }; + debugFillPropertiesTest( + const ZetaFAB(), + debugFillProperties, + ); + + testWidgets('Initializes with correct parameters', (WidgetTester tester) async { + final scrollController = ScrollController(); + await tester.pumpWidget( + TestApp( + home: ZetaFAB(scrollController: scrollController, label: 'Label', onPressed: () {}), + ), + ); + + expect(find.byType(ZetaFAB), findsOneWidget); + }); + + 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.expanded, false); + expect(fab.type, ZetaFabType.inverse); + expect(fab.shape, ZetaWidgetBorder.rounded); + }); + + testWidgets('Expanded', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaFAB( + expanded: true, + onPressed: () {}, + label: 'Label', + type: ZetaFabType.secondary, + shape: ZetaWidgetBorder.sharp, + ), + ), + ); + + final fabFinder = find.byType(ZetaFAB); + final ZetaFAB fab = tester.firstWidget(fabFinder); + + expect(fab.expanded, true); + expect(fab.type, ZetaFabType.secondary); + expect(fab.shape, ZetaWidgetBorder.sharp); + }); + + testWidgets('Disabled FAB', (WidgetTester tester) async { + final scrollController = ScrollController(); + await tester.pumpWidget( + TestApp( + home: ZetaFAB(scrollController: scrollController, label: 'Disabled'), + ), + ); + + final fabFinder = find.byType(ZetaFAB); + final ZetaFAB fab = tester.firstWidget(fabFinder); + + expect(fab.onPressed, isNull); + expect(fab.type, ZetaFabType.primary); + expect(fab.shape, ZetaWidgetBorder.full); + }); + + testWidgets('Label is correct', (WidgetTester tester) async { + final scrollController = ScrollController(); + StateSetter? setState; + bool expanded = false; + + await tester.pumpWidget( + TestApp( + home: StatefulBuilder( + builder: (context, setState2) { + setState = setState2; + return ZetaFAB( + scrollController: scrollController, + expanded: expanded, + label: 'Label', + onPressed: () {}, + ); + }, + ), + ), + ); + + final labelFinder = find.text('Label'); + + expect(labelFinder, findsOne); + + setState?.call(() => expanded = true); + + await tester.pumpAndSettle(); + expect(labelFinder, findsOne); + }); + }); + + group('$componentName Dimensions Tests', () {}); + + group('$componentName Styling Tests', () { + testWidgets('hover colours are correct', (WidgetTester tester) async { + final FocusNode node = FocusNode(); + + await tester.pumpWidget( + TestApp( + home: ZetaFAB( + expanded: 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.expanded, 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: ZetaBorders.medium), + ); + }); + }); + + group('$componentName Interaction Tests', () { + testWidgets('OnPressed callback', (WidgetTester tester) async { + bool isPressed = false; + final scrollController = ScrollController(); + + await tester.pumpWidget( + TestApp( + home: ZetaFAB(scrollController: scrollController, label: 'Label', onPressed: () => isPressed = true), + ), + ); + final TestGesture e = await tester.press(find.byType(ZetaFAB)); + + await tester.pumpAndSettle(); + + await e.up(); + expect(isPressed, isTrue); + }); + }); + + group('$componentName Golden Tests', () { + goldenTest( + goldenFile, + ZetaFAB( + scrollController: ScrollController(), + label: 'Label', + onPressed: () {}, + ), + ZetaFAB, + 'FAB_default', + ); + goldenTestWithCallbacks( + goldenFile, + ZetaFAB(scrollController: ScrollController(), label: 'Label', onPressed: () => {}), + ZetaFAB, + 'FAB_pressed', + after: (tester) async { + await tester.press(find.byType(ZetaFAB)); + await tester.pumpAndSettle(); + }, + ); + goldenTest( + goldenFile, + ZetaFAB( + scrollController: ScrollController(), + onPressed: () {}, + type: ZetaFabType.inverse, + shape: ZetaWidgetBorder.rounded, + size: ZetaFabSize.large, + ), + ZetaFAB, + 'FAB_inverse', + ); + goldenTestWithCallbacks( + goldenFile, + ZetaFAB(scrollController: ScrollController(), label: 'Label', onPressed: () => {}), + ZetaFAB, + 'FAB_pressed', + after: (tester) async { + await tester.press(find.byType(ZetaFAB)); + await tester.pumpAndSettle(); + }, + ); + goldenTest( + goldenFile, + ZetaFAB( + expanded: true, + onPressed: () {}, + label: 'Label', + type: ZetaFabType.secondary, + shape: ZetaWidgetBorder.sharp, + ), + ZetaFAB, + 'FAB_secondary', + ); + goldenTest( + goldenFile, + ZetaFAB(scrollController: ScrollController(), label: 'Disabled'), + ZetaFAB, + 'FAB_disabled', + ); + }); + + group('$componentName Performance Tests', () {}); +} diff --git a/test/src/components/fabs/fab_test.dart b/test/src/components/fabs/fab_test.dart deleted file mode 100644 index f82fd5ed..00000000 --- a/test/src/components/fabs/fab_test.dart +++ /dev/null @@ -1,219 +0,0 @@ -import 'dart:ui'; - -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_utils/test_app.dart'; -import '../../../test_utils/tolerant_comparator.dart'; -import '../../../test_utils/utils.dart'; - -void main() { - const goldenFile = GoldenFiles(component: 'fab'); - - setUpAll(() { - goldenFileComparator = TolerantComparator(goldenFile.uri); - }); - - group('ZetaFAB Tests', () { - testWidgets('Initializes with correct parameters', (WidgetTester tester) async { - final scrollController = ScrollController(); - await tester.pumpWidget( - TestApp( - home: ZetaFAB(scrollController: scrollController, label: 'Label', onPressed: () {}), - ), - ); - - expect(find.byType(ZetaFAB), findsOneWidget); - - await expectLater( - find.byType(ZetaFAB), - matchesGoldenFile(goldenFile.getFileUri('FAB_default')), - ); - }); - - testWidgets('OnPressed callback', (WidgetTester tester) async { - bool isPressed = false; - final scrollController = ScrollController(); - - await tester.pumpWidget( - TestApp( - home: ZetaFAB(scrollController: scrollController, label: 'Label', onPressed: () => isPressed = true), - ), - ); - final TestGesture e = await tester.press(find.byType(ZetaFAB)); - - await tester.pumpAndSettle(); - - await expectLater( - find.byType(ZetaFAB), - matchesGoldenFile(goldenFile.getFileUri('FAB_pressed')), - ); - - await e.up(); - 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.expanded, false); - expect(fab.type, ZetaFabType.inverse); - expect(fab.shape, ZetaWidgetBorder.rounded); - - await expectLater( - find.byType(ZetaFAB), - matchesGoldenFile(goldenFile.getFileUri('FAB_inverse')), - ); - }); - - testWidgets('Expanded', (WidgetTester tester) async { - await tester.pumpWidget( - TestApp( - home: ZetaFAB( - expanded: true, - onPressed: () {}, - label: 'Label', - type: ZetaFabType.secondary, - shape: ZetaWidgetBorder.sharp, - ), - ), - ); - - final fabFinder = find.byType(ZetaFAB); - final ZetaFAB fab = tester.firstWidget(fabFinder); - - expect(fab.expanded, true); - expect(fab.type, ZetaFabType.secondary); - expect(fab.shape, ZetaWidgetBorder.sharp); - - await expectLater( - find.byType(ZetaFAB), - matchesGoldenFile(goldenFile.getFileUri('FAB_secondary')), - ); - }); - testWidgets('ZetaFAB interactive', (WidgetTester tester) async { - final FocusNode node = FocusNode(); - - await tester.pumpWidget( - TestApp( - home: ZetaFAB( - expanded: 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.expanded, 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: ZetaBorders.medium), - ); - }); - - testWidgets('Disabled FAB', (WidgetTester tester) async { - final scrollController = ScrollController(); - await tester.pumpWidget( - TestApp( - home: ZetaFAB(scrollController: scrollController, label: 'Disabled'), - ), - ); - - final fabFinder = find.byType(ZetaFAB); - final ZetaFAB fab = tester.firstWidget(fabFinder); - - expect(fab.onPressed, isNull); - expect(fab.type, ZetaFabType.primary); - expect(fab.shape, ZetaWidgetBorder.full); - - await expectLater( - find.byType(ZetaFAB), - matchesGoldenFile(goldenFile.getFileUri('FAB_disabled')), - ); - }); - - 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'), 'false'); - expect(diagnostics.finder('focusNode'), 'null'); - }); - - testWidgets('Label is correct', (WidgetTester tester) async { - final scrollController = ScrollController(); - StateSetter? setState; - bool expanded = false; - - await tester.pumpWidget( - TestApp( - home: StatefulBuilder( - builder: (context, setState2) { - setState = setState2; - return ZetaFAB( - scrollController: scrollController, - expanded: expanded, - label: 'Label', - onPressed: () {}, - ); - }, - ), - ), - ); - - final labelFinder = find.text('Label'); - - expect(labelFinder, findsOne); - - setState?.call(() => expanded = true); - - await tester.pumpAndSettle(); - expect(labelFinder, findsOne); - }); -} diff --git a/test/src/components/fabs/golden/FAB_default.png b/test/src/components/fabs/golden/FAB_default.png deleted file mode 100644 index 8ab4dac26b1a97669fe4749481a7a4ce46ed0c4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4754 zcmeH}>sM1(8pd}50?JKsbwmV0WfUz8j0NN#E}}pcQbkCp1W;ID3<)X(Dj@`6Dj)(n zZ9(o>I-&_ANDAS8mq^tBB_tx3R8fH(2*nW60FgP&tTlhZe9ZoG&OYlod%y4RefGO{ z?$<$n`nyba0RZ#^{C&>>pkV<35~rgDe<@AQyb3=MiRb)$0E=(B08ca%eFDzwz#~m3 zCI zo4B%mdq2N?2g&_=r_4BOt)5QxM4{5kKyd5C2Gzp^fal@jG>vyF(@Sl#H!8|-bLjL| z;p5W#MkaaFE7=NBYl7(`8OF3ukzleYcLu=bM54jn+Dej0zuTNWX>P(6uKMIZ^>KUu zDi+^;gHl23^J4oUK-B&cO2#7TrJ#8E0Q-Uz#jU@x(`N`@(VBX z2^V~EdP1G~1Ys!ps03oRrOPC3YaZ5A54aeor8J{t=HsVYB zXhj{9HR!~Liy{rfY5w(Q5=edoPUx7OQaoi?5G0ICw?!8*Np7{!ZItwJGd=}?q=`J_ zf7mQisaJkeeR%%b4n-KBTTX2jMZ;?kbXa%|t_=&ayX-^VswiXHAx<-H5h#_6qME84F;E$>#O?G3hf6qIk#^sP&2P2E}Iuv)R$ z$t9Sn^}%y%p0%(p`<~M+p5wz#2}I%WH1ZAvsMgR%zKi;}-d`%uV;Vs7#`Oy&CW}>D zQp**kFfMH1l$sd=7svW3-cuphRbF#x6m zrDaa~!YFzOv66dpyU21{vR_K=rL%4GKlery0?^~ldXoHz%}?#`rCgkl_W15KFG3;*$u9<62m!om7?MmU z{m`m)ID zVTR#iOlTq8NZ0TaflL(aMxHJ*rn+0AjS359dkloyFuJZvC8=8vv!FdM;lIgtU*ucf zIzXBG%+hg0oOcapV@ri@xABYI0ccx1RO~vFp2Q({MLB!u<_%01kcCUd>k4g9y%CYj z9_Iz27;LVG1*!7;G(V@0??a}hpF6^f9>7E~J z4aTu{MiubhG)O-g^OnoqT=|RQy zcn(Y4(Z)yjQX>I)R+5;pIXv4wDX)PKjt9N0Zo|B+F83(&;D4L03*2-K%bn*{<^Ze? zbZER&9)1`r>EazGKA%6IkG988rf{L$C&?a9+VNC3Pxr(mfqzZGeu7}sGT$|sRCD}) zJ)Xotf@*G?kp=8*&PwAl0s&X?I06a4fX;3JEKb3G1;>z@0Oag}HC}fBEV!fzTX(mm z7XTT?YN?ulnt+;snt+;snt+;snt+;sn!x{&z$abSledV%18!6BO&kQA4Dx09L}mUP D)R5gM diff --git a/test/src/components/fabs/golden/FAB_disabled.png b/test/src/components/fabs/golden/FAB_disabled.png deleted file mode 100644 index 24e1062f26bee35450fec28d77f284b33d665c59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4446 zcmeH}`%}_c7{*_`B)KJ(ZM14=xmjD2=}b58bkp1owF_mI+M3B);&lZB6}F4j4=RQ)}e~r${sj$gIo~Swp-)D4S&~px^~Gkle5PH|&p`U(THOeP+&?&v~9R=W0|$ z*kVT)M*vtHzHiS#09y|Ln`ra`q;i9DJ{_4*SqH;*0jJY#1X5Bk7~-Rob$>8E}0sm9KqvVSROc zR9#l}L+3vtiP8ENj6RL07>x>ZDX8S}^T>^6b+fQpSkG~<)|gxhZbeF*r91*b&Xe=% z+TRaJ5`ybKrT80v0C2naD2@4JY`jLy+g6%KrqU~0u)RFOreSVO2dN>jlqlVDie(2+ zesXfUE_7G7o{8PAAtXD!c*7$E@uPb_WghUi1J!s_7IRT+RBw%OxT6p51^C z9`qZdyUTNCDQ3<E<>$#J8gT1BO({PC;N9*H=3ey5lT&Ib0{5AL7 z%}q(CST=yStihXv^)m6W$~k3QscD)O68zGKF=tf7c(XB?-ZR=(Lktt3>`DdOHMlml zX8Lhpe5F!YqY$TReF5%9qTWpBDQg=~No?XfE^7>Zo&Zr5xR#hS3dTs@c{wn&A+BCi zG00%(2UiwU9;uPFv{?>Hw}e?Fd4ui-;j8;?tf09*hKQ{24+#-X>U73fuMoNfS#<2{EDpBID@%{@7VvIWX6 z6ujsj!@Qlg#c`FL1}E^T>RI)D`7fL-fh`o?Q=0KFoYyoVBAHQu#pn3bP&VLG&1YVT#11C>R4=!{9P~ph|T^@m}iajau4xq}B^2oTUi)kE=dRVKC5b^yI)@3%aE(-?` z^K?vA>dUz^&fgF)KEdi(u%if=d~{R0hTX?N~6S9(!Xm0zmhw04M_>n*RsE@rt!D)HsJgTl<@Un6B4PfKw%|-OJjsx6pcZ^GHIO$3 zBUZ&9H)Le-NLZ?ZZ;QLdmPp!gC}5hFdk~3OEJ-F`d!zoZ+-(i793Xv7zIPEXx%RxC zNc)`PHxD^?qGl~?a&oWuV|npMO~(BbIn%bFx`-I}Mm5dy?tzyxD`9*_Op?;Zlo((Z zPcZ)MnvY3F^3hCOL;LNz-p#RX$YF=Kv;C8}R|DDtV+hi24Vx{)J?dW#fYDLii$u}h z)zxatu1>0f3psVhZ2V`nYe*m~AjNo8m5|%af$xg8Y$HUcfwL zyn{MOl>HYhj#Btthn+*f@eZ}@+O;z-tXLG3JqWPhN0j*-uIp*c7Bn}wJZ&$DSZA2c zOun@fm|^caQ4_}oF-WIQX6oUuF03M#(kS<9uT4ImPk%b|g6(@QM{`!t-;>0xA5D$F z;PUquXBAZ|CXda(Q03ylRC~~)l>zwt^_S8xgmUS#2(JBljr{h Dy$(uB diff --git a/test/src/components/fabs/golden/FAB_inverse.png b/test/src/components/fabs/golden/FAB_inverse.png deleted file mode 100644 index 41bf5c0f2bb19182a90763d2cac9cf67d3ab9219..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4352 zcmeHJX;2eq82&<}poo#7YB?fUuUa`oNu)r6B1*9ZtmqJp1)Mk>$}I{3HbFWH)|l8L zAXgZVh6x}Tkwb%oA_V1%ILINl0a7Cnu8?4^E~6c%|D4LNPWI34zTbO&&-XmfCq6%~$Nj??u~uh_Qeg6gRSAAt@?@(k(SsQVO>sUlBI-=v~7=li9? zp+7B-aw(;Ei;HPz+wi1usGltCCRw;h%>n4Pr-UV$JH`Z`fLhCiGu!byC%KXoX^Hjl zqK8fOkaAk=o3|??BZI|60+6OiM???RUWjTZs-yZ6XQ`f?kY@7q6+ef81$rf8baa$m z06^^>%CTopa4J!cTR_`t@7d2nO%cML$!8c4E9V-`~fPPXt69P{VJ=JI5cMs%!t z@On-~v9Wpz#b1-jix}_bV5MIIaHD?wCJKwi@^ftBi{x=D`zeii!q$j|6b^@D_uj!9 zInu=N!>DCugSpYou5yWHfnPOq+t(8Zx4eZDhR=726X4zoTgv=#tIVApq|A%=s;iyx z8&_VK%7JNY=L}IFD8p(9*p6RNq*`$4IYdt-2=j zi|>)Qc;@47$s8s+c;=EvBd^^MwBfq@)siy zGV?G}c(X%x6(JNP+)60)>98(^XG=wdfA&Wbl>E&7NP>zpU2W{$R#rhMP+G#CoTul<(=;7Vo*NU6A2$`?7X+;L6l`j0auCjCdOs!&=aTu& zjW2$mLV^HJXpTUHn(U30#WiG!=nIMXMKM5%`6!`b7d_7@_D38H(%~{Y%1qadHk_!K zU1>$@QnnV=>j7Z!ra-e?Wmu}=a)Jat1%3BdtK|%)olUpm6*~xK)TWA7(X5_D{Pbh) zq^XEEDHSHf_G3m_)^FuPhM6x#exLK`k>dwZ58E=8ceY-o#tSx+$YgRMj@T&{i>v1H z2d(h{5Q5A6mGw-VH#%QEf)O4QDATshhk6L0wr9e3XI$`f7j@N#Q8T%=IK?SZJ|*uk z+)ZEPVRx*oAD&<*VQCAmMpQ-SLSt`8Sj8WmNRV`K_6%}lgWjt3=9=gRcRnV+D%{*z ze*1Knq&z)6J!*2hz;xX>G(o_R-C&F0EwQFk5i^ng$`@3cpl|MBRP)_R`r*~$0Vn&;r9D$1m-%bQ7N2O;1Lb56Q2A!~n|3V?aGbQ1VX z1!=>Vb|Pu<)Z)2RUpFn6v|Q41>GS^*wK~%3=zpxEEDL1A^B?G6qtm6ZR)EKTFSioc HfaJdcV>>IR diff --git a/test/src/components/fabs/golden/FAB_pressed.png b/test/src/components/fabs/golden/FAB_pressed.png deleted file mode 100644 index 10365d1177bd0e25fb188f97bef163c7039ead94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4883 zcmeH~X;hO}8pkh-f*|TRl|=}lbw+0fSwv_Q2%(}djDvJ!3m^nVma-T?)<6ihwMZ2g z90ftcRznGfNCClw1W+U{n1GQ)2q9Q0n1m21yhH*debIiIGxKpi=6<=$dG0;W`Q7LL zzvq^GdBo4mWV;Cfz|8;e2af_^UG;?jF@Wk-+0smlQ zxD^jD=_?!_3@#a(z|8i6>IBHdl{1X~w> zL$o!@m~U3zNJ_l0r*1t`lMznY^u+Z>+5?Ytm->IPO@lDNpk4bo z2I1}=Y;`eVG)>v_)evD^l;$3#B;(Ys9^DsEjdHmIYC0)-r~sG=QfEVm4J~6m7IY zHj`d0)vNoPwe+F6lCUHT`rX4$*l=Wl{Q4+6j>r!Jpu%S-!fscwpWIY39;GFyVjY`g zpG7)(c6hBUY8XlLm6QemoQ?kZH}6HStUKeYXQQCL+N&i2-$Dz)EbVvCWJJ_T^x8ph zGZM@$Gm%S&R>kGBO!)TncE z7$H9zo*H^bIBwH6qNZ4=L7kP-PyQSGs)r`#myx zF!v#@Kh76ooEN_2UW&&2B7A#GNX2xetp2-Nb)vzSlia(K$1g0DtmL`5xUZ60v#T+# zE}`eu1fHg+JbmJEjADe8`QlRde62y29LHu82$a<_0Nx!d8iU>i1t=@Z!f5*&*y=Ni zR77lMO5K!-JoouuuDW=oGp5=pT2U^Ohbc(u6zs0nh@X-cCY|K!NcLVSXS0oU^Rmk9 zrFC>GVU)fB0NNX$`Ydhi`1|K0MD3N4ZBzgTJZVaFZjCQToO!vGIX%=+MFyZ}w@@wR zbE?LBcDE#G_q3P*@5l%Y(lUi$(AxK^?;tv>k29waoQbrCLaD_+b}CCA?)tb-uzg=4 zRcbcyS@Fe9ZfHGF6n-abvM-HqU2%wP4jV|@aW(1z>=qSu0_tsk_YK5pUY@=A?~yss zPwSw`*MCHKOo-@=yUm@6!#~*O4>95p`B5$clPv&@4l{k@&LNx?Oa9pO+7tO zgP^%RGk0a32|sxYz*94ty;Fo(px3|4Jttx2i0yf7?ONko#u2O5Nt&+E z(u;x0a&56K=BTw+Ch_n*eE}oLa zxbxVWr>3KX09bZ3>S#-rkGNwxh99|8QS!~Mn^_wo+cS@+GCNt%AOLDYLZIvRJUW?7 zX>h)p+FiiX?tmfCLPFX#V~?N?yhcpvaQ1NsAB;pUx7t^d^x*Y`Y8rCz%Z}zG%x&1(wiAe01z(-a~7y5=KWEYld-sdm>*P4 z6yA&2NBU?ETb(vsUYd`{5W~sRudVN1ec4 zN`sm9tslDMP!%drC|MM9C{JPpz%Aik7nclm2YP~}vTarsq=zA_ZTwT~KE*R-IkHye zSSXR@*lhqNuB8h=BbD&$;1hz%LP@K(*;o1MAhu~Z2ub2xgSZNdkGe%Q!cp6;s(uu8 zGaJ?V(54mpf3~?ac-1ZRh2~(+;%cWt4!@KJAJ&14a9rcj)QE_HN~c-v+?BKfvnnz5v%R zIALfEz?L1}02EoSMf4fNm2c-;1j}ZRzM(EuM?gnFM?gnFM?gnFM?gnFM?gp5|4U#h Z3={fmy&l&R{)GeJf9S};<^wTb{|4I!Gm!uQ diff --git a/test/src/components/fabs/golden/FAB_secondary.png b/test/src/components/fabs/golden/FAB_secondary.png deleted file mode 100644 index 40f2cf3ba1d760f5282a78a9f44b82509eaf100d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3599 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|sA;FCi(^Q|oVRzayXT}zG(0R%FZcb>prJYGnDb;O4yP{BU`|GFPwgd_ z{B*XS@ec^Paf|aGV}0`>GqI>!M-(De7F2Mg@f&YT+B);+j&$|v*snI{zi%_Y|JyKn zeyx!hvtQ=>XLCPZJ8S*g4(KB3tZna@fsT0I&cMjPV8q12z;J>?fPq0l*@1zfp$E61 z^=iEvdq4cyvF-aqk#tG>H}#f%a{oM<}pcoS*qpclK(>|W*jcR)G*x_k2c?`q8< za)qqiFe^5H5?%BE_pfg0<@?-9pI+U5{I`7l?<41DP<7@f%MP?p9 zdGg_ndv$3qfByWFawhF|_U!+^&o_U(!##cay#HUPzds&czFyy!pMl|Y0m3zeJPZyR zpMU-@@?-YfuG_PzeAWGZB`;rH>1StPIJe;>^OLjE^1ge87#J$Nb~LdvFrO*r}| zrK{LyAJE4Z)nWUZN(<`iYyQ2wCXx;e>v=`em8{ttXZUYSxyqV7FaGMT`TPtADouX6 zzi7QL|L@6Kpst(+y*12CKw6CvNT#rGFfdFIRA69maBBd@nIt)aH?3@JV%GcyM)854 z4|u6yAcgK3)lPO)jt1Rm&{3;c7)?u~X=yYqQC_`{=A+SkG@6e_Vm_K#&luktl~{Py RXb}Stc)I$ztaD0e0swT;O2hyF diff --git a/test/src/components/icon/icon_test.dart b/test/src/components/icon/icon_test.dart index 05cbbb5e..d7f1dc9b 100644 --- a/test/src/components/icon/icon_test.dart +++ b/test/src/components/icon/icon_test.dart @@ -1,28 +1,61 @@ -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_utils/test_app.dart'; +import '../../../test_utils/tolerant_comparator.dart'; import '../../../test_utils/utils.dart'; void main() { - group('Zeta Icon', () { - testWidgets('renders icon correctly', (WidgetTester tester) async { - await tester.pumpWidget(const TestApp(home: ZetaIcon(ZetaIcons.add_round))); + const String componentName = 'ZetaIcon'; + const String parentFolder = 'icon'; + + const goldenFile = GoldenFiles(component: parentFolder); + setUpAll(() { + goldenFileComparator = TolerantComparator(goldenFile.uri); + }); + + group('$componentName Accessibility Tests', () { + testWidgets('applies correct semantic label to icon', (WidgetTester tester) async { + const String semanticLabel = 'Add Icon'; + await tester.pumpWidget(const TestApp(home: ZetaIcon(ZetaIcons.add_round, semanticLabel: semanticLabel))); final iconFinder = find.byIcon(ZetaIcons.add_round); - expect(iconFinder, findsOneWidget); + final iconWidget = tester.widget(iconFinder); + expect(iconWidget.semanticLabel, equals(semanticLabel)); }); + }); + group('$componentName Content Tests', () { + final debugFillProperties = { + 'icon': 'IconData(U+0E045)', + 'rounded': 'false', + 'size': '10.0', + 'fill': 'null', + 'weight': 'null', + 'grade': 'null', + 'opticalSize': 'null', + 'color': 'null', + 'shadows': 'null', + 'semanticLabel': '"Cached"', + 'textDirection': 'null', + 'applyTextScaling': 'null', + }; + debugFillPropertiesTest( + const ZetaIcon( + ZetaIcons.cached, + rounded: false, + size: 10, + semanticLabel: 'Cached', + ), + debugFillProperties, + ); - testWidgets('applies correct size to icon', (WidgetTester tester) async { - const double iconSize = 24; - await tester.pumpWidget(const TestApp(home: ZetaIcon(ZetaIcons.add_round, size: iconSize))); + testWidgets('renders icon correctly', (WidgetTester tester) async { + await tester.pumpWidget(const TestApp(home: ZetaIcon(ZetaIcons.add_round))); final iconFinder = find.byIcon(ZetaIcons.add_round); - final iconWidget = tester.widget(iconFinder); - expect(iconWidget.size, equals(iconSize)); + expect(iconFinder, findsOneWidget); }); - testWidgets('applies correct color to icon', (WidgetTester tester) async { + testWidgets('color value is correct', (WidgetTester tester) async { const Color iconColor = Colors.red; await tester.pumpWidget(const TestApp(home: ZetaIcon(ZetaIcons.add_round, color: iconColor))); final iconFinder = find.byIcon(ZetaIcons.add_round); @@ -30,14 +63,6 @@ void main() { expect(iconWidget.color, equals(iconColor)); }); - testWidgets('applies correct semantic label to icon', (WidgetTester tester) async { - const String semanticLabel = 'Add Icon'; - await tester.pumpWidget(const TestApp(home: ZetaIcon(ZetaIcons.add_round, semanticLabel: semanticLabel))); - final iconFinder = find.byIcon(ZetaIcons.add_round); - final iconWidget = tester.widget(iconFinder); - expect(iconWidget.semanticLabel, equals(semanticLabel)); - }); - testWidgets('applies sharp family to icon', (WidgetTester tester) async { await tester.pumpWidget( const TestApp( @@ -58,7 +83,18 @@ void main() { expect(iconFinderRound, findsOneWidget); expect(iconFinderSharp, findsExactly(1)); }); - + }); + group('$componentName Dimensions Tests', () { + testWidgets('applies correct size to icon', (WidgetTester tester) async { + const double iconSize = 24; + await tester.pumpWidget(const TestApp(home: ZetaIcon(ZetaIcons.add_round, size: iconSize))); + final iconFinder = find.byIcon(ZetaIcons.add_round); + final sizeOfIcon = tester.getSize(iconFinder); + expect(sizeOfIcon.width, equals(iconSize)); + expect(sizeOfIcon.height, equals(iconSize)); + }); + }); + group('$componentName Styling Tests', () { testWidgets('applies correct font family to icon', (WidgetTester tester) async { await tester.pumpWidget(const TestApp(home: ZetaIcon(ZetaIcons.add_round))); final iconFinder = find.byIcon(ZetaIcons.add_round); @@ -145,28 +181,10 @@ void main() { final iconWidget = tester.widget(iconFinder); expect(iconWidget.icon?.fontFamily, equals('MaterialIcons')); }); - - testWidgets('debugFillProperties works correctly', (WidgetTester tester) async { - final diagnostics = DiagnosticPropertiesBuilder(); - const ZetaIcon( - ZetaIcons.cached, - rounded: false, - size: 10, - semanticLabel: 'Cached', - ).debugFillProperties(diagnostics); - - expect(diagnostics.finder('icon'), 'IconData(U+0E045)'); - expect(diagnostics.finder('rounded'), 'false'); - expect(diagnostics.finder('size'), '10.0'); - expect(diagnostics.finder('fill'), 'null'); - expect(diagnostics.finder('weight'), 'null'); - expect(diagnostics.finder('grade'), 'null'); - expect(diagnostics.finder('opticalSize'), 'null'); - expect(diagnostics.finder('color'), 'null'); - expect(diagnostics.finder('shadows'), 'null'); - expect(diagnostics.finder('semanticLabel'), '"Cached"'); - expect(diagnostics.finder('textDirection'), 'null'); - expect(diagnostics.finder('applyTextScaling'), 'null'); - }); }); + group('$componentName Interaction Tests', () {}); + group('$componentName Golden Tests', () { + // goldenTest(goldenFile, widget, widgetType, 'PNG_FILE_NAME'); + }); + group('$componentName Performance Tests', () {}); } 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 index 4c825515..930c4617 100644 --- a/test/src/components/in_page_banner/in_page_banner_test.dart +++ b/test/src/components/in_page_banner/in_page_banner_test.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; @@ -8,120 +7,175 @@ import '../../../test_utils/tolerant_comparator.dart'; import '../../../test_utils/utils.dart'; void main() { - const goldenFile = GoldenFiles(component: 'in_page_banner'); + const String componentName = 'ZetaInPageBanner'; + const String parentFolder = 'in_page_banner'; + const goldenFile = GoldenFiles(component: parentFolder); setUpAll(() { goldenFileComparator = TolerantComparator(goldenFile.uri); }); - group('ZetaInPageBanner Tests', () { - testWidgets('ZetaInPageBanner creation', (WidgetTester tester) async { + group('$componentName Accessibility Tests', () {}); + group('$componentName Content Tests', () { + final debugFillProperties = { + 'onClose': 'null', + 'status': 'info', + 'title': 'null', + 'customIcon': 'null', + }; + debugFillPropertiesTest( + const ZetaInPageBanner(content: Placeholder()), + debugFillProperties, + ); + + testWidgets('renders correct icon and text', (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); + }); + + 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); + }); + + 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); + }); + }); + group('$componentName Dimensions Tests', () {}); + group('$componentName Styling Tests', () { + testWidgets('default background colour is correct', (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(box.decoration.runtimeType, BoxDecoration); final BoxDecoration decoration = box.decoration as BoxDecoration; expect(decoration.color, ZetaColorBase.purple.shade10); + }); - await expectLater( - find.byType(ZetaInPageBanner), - matchesGoldenFile(goldenFile.getFileUri('in_page_banner_default')), + testWidgets('negative background colour is correct', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp(home: ZetaInPageBanner(content: const Text('Test'), onClose: () {}, status: ZetaWidgetStatus.negative)), ); + + 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); }); - }); - testWidgets("ZetaInPageBanner shows 'close icon' correctly", (WidgetTester tester) async { - await tester.pumpWidget( - TestApp(home: ZetaInPageBanner(content: const Text('Test'), onClose: () {}, status: ZetaWidgetStatus.negative)), - ); + testWidgets('positive background colour is correct', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp(home: ZetaInPageBanner(content: Text('Test'), status: ZetaWidgetStatus.positive)), + ); - 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(goldenFile.getFileUri('in_page_banner_negative')), - ); - }); + 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); + }); - 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(goldenFile.getFileUri('in_page_banner_positive')), - ); - }); + testWidgets('neutral background colour is correct', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp(home: ZetaInPageBanner(content: Text('Test'), status: ZetaWidgetStatus.neutral)), + ); - 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); + }); + }); + group('$componentName Interaction Tests', () { + testWidgets('button callback works', (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 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( + 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); + }); + }); - await expectLater( - find.byType(ZetaInPageBanner), - matchesGoldenFile(goldenFile.getFileUri('in_page_banner_buttons')), + group('$componentName Golden Tests', () { + goldenTest( + goldenFile, + const ZetaInPageBanner(content: Text('Test'), title: 'Title'), + ZetaInPageBanner, + 'in_page_banner_default', ); - }); - 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'))), + goldenTest( + goldenFile, + ZetaInPageBanner(content: const Text('Test'), onClose: () {}, status: ZetaWidgetStatus.negative), + ZetaInPageBanner, + 'in_page_banner_negative', + ); + goldenTest( + goldenFile, + const ZetaInPageBanner(content: Text('Test'), status: ZetaWidgetStatus.positive), + ZetaInPageBanner, + 'in_page_banner_positive', + ); + goldenTest( + goldenFile, + ZetaInPageBanner( + content: const Text('Test'), + status: ZetaWidgetStatus.neutral, + actions: [ + ZetaButton( + label: 'Test button', + onPressed: () {}, + ), + ], + ), + ZetaInPageBanner, + 'in_page_banner_buttons', ); - 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'); }); + group('$componentName Performance Tests', () {}); } diff --git a/test/src/components/password/password_input_test.dart b/test/src/components/password/password_input_test.dart index 57dbbd28..3fe66c3c 100644 --- a/test/src/components/password/password_input_test.dart +++ b/test/src/components/password/password_input_test.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; @@ -8,87 +7,113 @@ import '../../../test_utils/tolerant_comparator.dart'; import '../../../test_utils/utils.dart'; void main() { - const goldenFile = GoldenFiles(component: 'password'); + const String componentName = 'ZetaPasswordInput'; + const String parentFolder = 'password'; + const goldenFile = GoldenFiles(component: parentFolder); setUpAll(() { goldenFileComparator = TolerantComparator(goldenFile.uri); }); - testWidgets('ZetaPasswordInput initializes correctly', (WidgetTester tester) async { - await tester.pumpWidget( - TestApp( - home: ZetaPasswordInput(), - ), + group('$componentName Accessibility Tests', () {}); + group('$componentName Content Tests', () { + final debugFillProperties = { + 'size': 'medium', + 'placeholder': 'null', + 'label': 'null', + 'hintText': 'null', + 'errorText': 'null', + 'semanticLabel': 'null', + 'showSemanticLabel': 'null', + 'obscureSemanticLabel': 'null', + }; + debugFillPropertiesTest( + ZetaPasswordInput(), + debugFillProperties, ); - expect(find.byType(ZetaPasswordInput), findsOneWidget); - await expectLater( - find.byType(ZetaPasswordInput), - matchesGoldenFile(goldenFile.getFileUri('password_default')), - ); - }); + testWidgets('ZetaPasswordInput initializes correctly', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaPasswordInput(), + ), + ); + expect(find.byType(ZetaPasswordInput), findsOneWidget); + }); - testWidgets('Test password visibility', (WidgetTester tester) async { - await tester.pumpWidget( - TestApp( - home: ZetaPasswordInput(), - ), - ); - final obscureIconOff = find.byIcon(ZetaIcons.visibility_off_round); - expect(obscureIconOff, findsOneWidget); - await tester.tap(obscureIconOff); - await tester.pump(); + testWidgets('obscure icon in rendered correctly', (WidgetTester tester) async { + await tester.pumpWidget( + 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); - }); + 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; - } + 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(); + final controller = TextEditingController()..text = 'password123'; + final formKey = GlobalKey(); - await tester.pumpWidget( - TestApp( - home: Form( - key: formKey, - child: ZetaPasswordInput( - controller: controller, - validator: testValidator, - rounded: false, + 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); + ); + formKey.currentState?.validate(); + await tester.pump(); - await expectLater( - find.byType(ZetaPasswordInput), - matchesGoldenFile(goldenFile.getFileUri('password_error')), - ); + // 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); + }); }); - testWidgets('Test debugFillProperties', (WidgetTester tester) async { - final diagnostics = DiagnosticPropertiesBuilder(); - ZetaPasswordInput().debugFillProperties(diagnostics); - - expect(diagnostics.finder('size'), 'medium'); - expect(diagnostics.finder('placeholder'), 'null'); - expect(diagnostics.finder('label'), 'null'); - expect(diagnostics.finder('hintText'), 'null'); - expect(diagnostics.finder('errorText'), 'null'); - expect(diagnostics.finder('semanticLabel'), 'null'); - expect(diagnostics.finder('showSemanticLabel'), 'null'); - expect(diagnostics.finder('obscureSemanticLabel'), 'null'); + group('$componentName Dimensions Tests', () {}); + group('$componentName Styling Tests', () {}); + group('$componentName Interaction Tests', () {}); + group('$componentName Golden Tests', () { + goldenTest(goldenFile, ZetaPasswordInput(), ZetaPasswordInput, 'password_default'); + final formKey = GlobalKey(); + goldenTestWithCallbacks( + goldenFile, + Form( + key: formKey, + child: ZetaPasswordInput( + controller: TextEditingController()..text = 'password123', + validator: (String? value) { + final regExp = RegExp(r'\d'); + if (value != null && regExp.hasMatch(value)) return 'Error'; + return null; + }, + rounded: false, + ), + ), + ZetaPasswordInput, + 'password_error', + after: (tester) async { + formKey.currentState?.validate(); + await tester.pump(); + }, + ); }); + group('$componentName Performance Tests', () {}); } diff --git a/test/src/components/search_bar/search_bar_test.dart b/test/src/components/search_bar/search_bar_test.dart index 120b326a..720598a6 100644 --- a/test/src/components/search_bar/search_bar_test.dart +++ b/test/src/components/search_bar/search_bar_test.dart @@ -26,8 +26,10 @@ abstract class ISearchBarEvents { ]) void main() { late MockISearchBarEvents callbacks; - const goldenFile = GoldenFiles(component: 'search_bar'); + const String componentName = 'ZetaSearchBar'; + const String parentFolder = 'search_bar'; + const goldenFile = GoldenFiles(component: parentFolder); setUpAll(() { goldenFileComparator = TolerantComparator(goldenFile.uri); }); @@ -36,8 +38,25 @@ void main() { callbacks = MockISearchBarEvents(); }); - group('ZetaSearchBar', () { - testWidgets('renders with default parameters', (WidgetTester tester) async { + group('$componentName Accessibility Tests', () {}); + group('$componentName Content Tests', () { + final debugFillProperties = { + 'size': 'medium', + 'shape': 'rounded', + 'placeholder': 'null', + 'textInputAction': 'null', + 'onSpeechToText': 'null', + 'showSpeechToText': 'true', + 'focusNode': 'null', + 'microphoneSemanticLabel': 'null', + 'clearSemanticLabel': 'null', + }; + debugFillPropertiesTest( + ZetaSearchBar(), + debugFillProperties, + ); + + testWidgets('renders text field', (WidgetTester tester) async { await tester.pumpWidget( TestApp( home: Scaffold( @@ -50,82 +69,6 @@ void main() { expect(find.byType(TextField), findsOneWidget); }); - testWidgets('golden: renders initializes correctly', (WidgetTester tester) async { - await tester.pumpWidget( - TestApp( - home: ZetaSearchBar(), - ), - ); - expect(find.byType(ZetaSearchBar), findsOneWidget); - - await expectLater( - find.byType(ZetaSearchBar), - matchesGoldenFile(goldenFile.getFileUri('search_bar_default')), - ); - }); - - testWidgets('golden: renders size medium correctly', (WidgetTester tester) async { - await tester.pumpWidget( - TestApp( - home: ZetaSearchBar(), - ), - ); - expect(find.byType(ZetaSearchBar), findsOneWidget); - - await expectLater( - find.byType(ZetaSearchBar), - matchesGoldenFile(goldenFile.getFileUri('search_bar_medium')), - ); - }); - - testWidgets('golden: renders size small correctly', (WidgetTester tester) async { - await tester.pumpWidget( - TestApp( - home: ZetaSearchBar( - size: ZetaWidgetSize.small, - ), - ), - ); - expect(find.byType(ZetaSearchBar), findsOneWidget); - - await expectLater( - find.byType(ZetaSearchBar), - matchesGoldenFile(goldenFile.getFileUri('search_bar_small')), - ); - }); - - testWidgets('golden: renders shape full correctly', (WidgetTester tester) async { - await tester.pumpWidget( - TestApp( - home: ZetaSearchBar( - shape: ZetaWidgetBorder.full, - ), - ), - ); - expect(find.byType(ZetaSearchBar), findsOneWidget); - - await expectLater( - find.byType(ZetaSearchBar), - matchesGoldenFile(goldenFile.getFileUri('search_bar_full')), - ); - }); - - testWidgets('golden: renders shape sharp correctly', (WidgetTester tester) async { - await tester.pumpWidget( - TestApp( - home: ZetaSearchBar( - shape: ZetaWidgetBorder.sharp, - ), - ), - ); - expect(find.byType(ZetaSearchBar), findsOneWidget); - - await expectLater( - find.byType(ZetaSearchBar), - matchesGoldenFile(goldenFile.getFileUri('search_bar_sharp')), - ); - }); - testWidgets('sets initial value correctly', (WidgetTester tester) async { const initialValue = 'Initial value'; @@ -168,6 +111,25 @@ void main() { expect(find.text(updatedValue), findsOneWidget); }); + testWidgets('speech-to-text button visibility', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: Scaffold( + body: ZetaSearchBar( + showSpeechToText: false, + ), + ), + ), + ); + + await tester.pumpAndSettle(); + expect(find.byIcon(ZetaIcons.search), findsNothing); + expect(find.byIcon(ZetaIcons.microphone), findsNothing); + }); + }); + group('$componentName Dimensions Tests', () {}); + group('$componentName Styling Tests', () {}); + group('$componentName Interaction Tests', () { testWidgets('triggers onChanged callback when text is entered', (WidgetTester tester) async { await tester.pumpWidget( TestApp( @@ -237,22 +199,6 @@ void main() { expect(find.text('Disabled input'), findsNothing); }); - testWidgets('speech-to-text button visibility', (WidgetTester tester) async { - await tester.pumpWidget( - TestApp( - home: Scaffold( - body: ZetaSearchBar( - showSpeechToText: false, - ), - ), - ), - ); - - await tester.pumpAndSettle(); - expect(find.byIcon(ZetaIcons.search), findsNothing); - expect(find.byIcon(ZetaIcons.microphone), findsNothing); - }); - testWidgets('clear button functionality', (WidgetTester tester) async { await tester.pumpWidget( TestApp( @@ -273,20 +219,34 @@ void main() { verify(callbacks.onChange.call('')).called(1); }); - - test('debugFillProperties', () { - final diagnostics = DiagnosticPropertiesBuilder(); - ZetaSearchBar().debugFillProperties(diagnostics); - - expect(diagnostics.finder('size'), 'medium'); - expect(diagnostics.finder('shape'), 'rounded'); - expect(diagnostics.finder('placeholder'), 'null'); - expect(diagnostics.finder('textInputAction'), 'null'); - expect(diagnostics.finder('onSpeechToText'), 'null'); - expect(diagnostics.finder('showSpeechToText'), 'true'); - expect(diagnostics.finder('focusNode'), 'null'); - expect(diagnostics.finder('microphoneSemanticLabel'), 'null'); - expect(diagnostics.finder('clearSemanticLabel'), 'null'); - }); }); + group('$componentName Golden Tests', () { + goldenTest(goldenFile, ZetaSearchBar(), ZetaSearchBar, 'search_bar_default'); + goldenTest(goldenFile, ZetaSearchBar(), ZetaSearchBar, 'search_bar_medium'); + goldenTest( + goldenFile, + ZetaSearchBar( + size: ZetaWidgetSize.small, + ), + ZetaSearchBar, + 'search_bar_small', + ); + goldenTest( + goldenFile, + ZetaSearchBar( + shape: ZetaWidgetBorder.full, + ), + ZetaSearchBar, + 'search_bar_full', + ); + goldenTest( + goldenFile, + ZetaSearchBar( + shape: ZetaWidgetBorder.sharp, + ), + ZetaSearchBar, + 'search_bar_sharp', + ); + }); + group('$componentName Performance Tests', () {}); } diff --git a/test/src/components/slider/slider_test.dart b/test/src/components/slider/slider_test.dart index 70522376..f6f5adca 100644 --- a/test/src/components/slider/slider_test.dart +++ b/test/src/components/slider/slider_test.dart @@ -3,33 +3,67 @@ import 'package:flutter_test/flutter_test.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() { - testWidgets('ZetaSlider min/max values', (WidgetTester tester) async { - const double sliderValue = 0.5; - double? changedValue; - - await tester.pumpWidget( - TestApp( - home: ZetaSlider( - value: sliderValue, - onChange: (value) { - changedValue = value; - }, + const String componentName = 'ZetaSlider'; + const String parentFolder = 'slider'; + + const goldenFile = GoldenFiles(component: parentFolder); + setUpAll(() { + goldenFileComparator = TolerantComparator(goldenFile.uri); + }); + + group('$componentName Accessibility Tests', () {}); + + group('$componentName Content Tests', () { + // final debugFillProperties = { + // '': '', + // }; + // debugFillPropertiesTest( + // widget, + // debugFillProperties, + // ); + }); + + group('$componentName Dimensions Tests', () {}); + + group('$componentName Styling Tests', () {}); + + group('$componentName Interaction Tests', () { + testWidgets('ZetaSlider min/max values', (WidgetTester tester) async { + const double sliderValue = 0.5; + double? changedValue; + + await tester.pumpWidget( + TestApp( + home: ZetaSlider( + value: sliderValue, + onChange: (value) { + changedValue = value; + }, + ), ), - ), - ); + ); - final slider = tester.widget(find.byType(Slider)); - expect(slider.min, 0.0); - expect(slider.max, 1.0); + final slider = tester.widget(find.byType(Slider)); + expect(slider.min, 0.0); + expect(slider.max, 1.0); - // Drag the slider to the minimum value - await tester.drag(find.byType(Slider), const Offset(-400, 0)); - expect(changedValue, 0.0); + // Drag the slider to the minimum value + await tester.drag(find.byType(Slider), const Offset(-400, 0)); + expect(changedValue, 0.0); - // Drag the slider to the maximum value - await tester.drag(find.byType(Slider), const Offset(400, 0)); - expect(changedValue, 1.0); + // Drag the slider to the maximum value + await tester.drag(find.byType(Slider), const Offset(400, 0)); + expect(changedValue, 1.0); + }); }); + + group('$componentName Golden Tests', () { + // goldenTest(goldenFile, widget, widgetType, 'PNG_FILE_NAME'); + }); + + group('$componentName Performance Tests', () {}); } diff --git a/test/src/components/stepper input/stepper_input_test.dart b/test/src/components/stepper input/stepper_input_test.dart deleted file mode 100644 index 53c4b4c1..00000000 --- a/test/src/components/stepper input/stepper_input_test.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/src/components/stepper_input/stepper_input.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -import '../../../test_utils/test_app.dart'; - -void main() { - testWidgets('ZetaStepperInput increases value when increment button is pressed', (WidgetTester tester) async { - int value = 0; - await tester.pumpWidget( - TestApp( - home: ZetaStepperInput( - value: value, - onChange: (newValue) { - value = newValue; - }, - ), - ), - ); - - expect(value, 0); - - await tester.tap(find.byIcon(ZetaIcons.add_round)); - await tester.pump(); - - expect(value, 1); - }); - - testWidgets('ZetaStepperInput increases value when programatically changed', (WidgetTester tester) async { - int value = 0; - StateSetter? setState; - await tester.pumpWidget( - StatefulBuilder( - builder: (context, setState2) { - setState = setState2; - - return TestApp( - home: ZetaStepperInput( - value: value, - onChange: (newValue) { - value = newValue; - }, - ), - ); - }, - ), - ); - - final ZetaStepperInputState stepperInputState = tester.state(find.byType(ZetaStepperInput)); - - expect(value, stepperInputState.value); - - setState?.call(() { - value = 1; - }); - - await tester.pump(); - - expect(value, stepperInputState.value); - }); -} diff --git a/test/src/components/stepper_input/stepper_input_test.dart b/test/src/components/stepper_input/stepper_input_test.dart new file mode 100644 index 00000000..3058e0e6 --- /dev/null +++ b/test/src/components/stepper_input/stepper_input_test.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:zeta_flutter/src/components/stepper_input/stepper_input.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() { + const String componentName = 'ZetaStepperInput'; + const String parentFolder = 'stepper_input'; + + const goldenFile = GoldenFiles(component: parentFolder); + setUpAll(() { + goldenFileComparator = TolerantComparator(goldenFile.uri); + }); + + group('$componentName Accessibility Tests', () {}); + group('$componentName Content Tests', () { + // final debugFillProperties = { + // '': '', + // }; + // debugFillPropertiesTest( + // widget, + // debugFillProperties, + // ); + + testWidgets('ZetaStepperInput increases value when programatically changed', (WidgetTester tester) async { + int value = 0; + StateSetter? setState; + await tester.pumpWidget( + StatefulBuilder( + builder: (context, setState2) { + setState = setState2; + + return TestApp( + home: ZetaStepperInput( + value: value, + onChange: (newValue) { + value = newValue; + }, + ), + ); + }, + ), + ); + + final ZetaStepperInputState stepperInputState = tester.state(find.byType(ZetaStepperInput)); + + expect(value, stepperInputState.value); + + setState?.call(() { + value = 1; + }); + + await tester.pump(); + + expect(value, stepperInputState.value); + }); + }); + + group('$componentName Dimensions Tests', () {}); + + group('$componentName Styling Tests', () {}); + + group('$componentName Interaction Tests', () { + testWidgets('ZetaStepperInput increases value when increment button is pressed', (WidgetTester tester) async { + int value = 0; + await tester.pumpWidget( + TestApp( + home: ZetaStepperInput( + value: value, + onChange: (newValue) { + value = newValue; + }, + ), + ), + ); + + expect(value, 0); + + await tester.tap(find.byIcon(ZetaIcons.add_round)); + await tester.pump(); + + expect(value, 1); + }); + }); + + group('$componentName Golden Tests', () { + // goldenTest(goldenFile, widget, widgetType, 'PNG_FILE_NAME'); + }); + + group('$componentName Performance Tests', () {}); +} diff --git a/test/src/components/tooltip/tooltip_test.dart b/test/src/components/tooltip/tooltip_test.dart index b1c5284f..17790a42 100644 --- a/test/src/components/tooltip/tooltip_test.dart +++ b/test/src/components/tooltip/tooltip_test.dart @@ -15,15 +15,56 @@ import 'tooltip_test.mocks.dart'; MockSpec(), ]) void main() { + const String componentName = 'ZetaTooltip'; + const String parentFolder = 'tooltip'; + final mockZeta = MockZeta(); when(mockZeta.radius).thenReturn(const ZetaRadiiAA(primitives: ZetaPrimitivesLight())); - const goldenFile = GoldenFiles(component: 'tooltip'); + const goldenFile = GoldenFiles(component: parentFolder); setUpAll(() { goldenFileComparator = TolerantComparator(goldenFile.uri); }); - group('ZetaTooltip Widget Tests', () { + group('$componentName Accessibility Tests', () {}); + group('$componentName Content Tests', () { + final debugFillProperties = { + 'rounded': 'null', + 'padding': 'EdgeInsets.all(8.0)', + 'color': 'MaterialColor(primary value: Color(0xffffc107))', + 'textStyle': 'TextStyle(inherit: true, size: 9.0)', + 'arrowDirection': 'down', + 'maxWidth': '170.0', + }; + debugFillPropertiesTest( + const ZetaTooltip( + padding: EdgeInsets.all(8), + color: Colors.amber, + textStyle: TextStyle(fontSize: 9), + maxWidth: 170, + child: Text('Rounded tooltip'), + ), + debugFillProperties, + ); + + testWidgets('debugFillProperties works correctly', (WidgetTester tester) async { + final diagnostics = DiagnosticPropertiesBuilder(); + const ZetaTooltip( + padding: EdgeInsets.all(8), + color: Colors.amber, + textStyle: TextStyle(fontSize: 9), + maxWidth: 170, + child: Text('Rounded tooltip'), + ).debugFillProperties(diagnostics); + + 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'); + }); + testWidgets('renders with default properties', (WidgetTester tester) async { await tester.pumpWidget( const TestApp( @@ -38,13 +79,13 @@ void main() { expect(find.text('Tooltip text'), findsOneWidget); expect(find.byType(ZetaTooltip), findsOneWidget); }); - - testWidgets('renders with custom color and padding', (WidgetTester tester) async { + }); + group('$componentName Dimensions Tests', () { + testWidgets('renders with custom padding', (WidgetTester tester) async { await tester.pumpWidget( const TestApp( home: Scaffold( body: ZetaTooltip( - color: Colors.red, padding: EdgeInsets.all(20), child: Text('Tooltip text'), ), @@ -52,23 +93,38 @@ void main() { ), ); - final tooltipBox = tester.widget( + final padding = tester.widget( find.descendant( of: find.byType(ZetaTooltip), - matching: find.byType(DecoratedBox), + matching: find.byType(Padding), ), ); - expect((tooltipBox.decoration as BoxDecoration).color, Colors.red); + expect(padding.padding, const EdgeInsets.all(20)); + }); + }); + group('$componentName Styling Tests', () { + testWidgets('renders with custom color', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: Scaffold( + body: ZetaTooltip( + color: Colors.red, + padding: EdgeInsets.all(20), + child: Text('Tooltip text'), + ), + ), + ), + ); - final padding = tester.widget( + final tooltipBox = tester.widget( find.descendant( of: find.byType(ZetaTooltip), - matching: find.byType(Padding), + matching: find.byType(DecoratedBox), ), ); - expect(padding.padding, const EdgeInsets.all(20)); + expect((tooltipBox.decoration as BoxDecoration).color, Colors.red); }); testWidgets('renders with custom text style', (WidgetTester tester) async { @@ -99,89 +155,6 @@ void main() { expect(textSpan.style?.color, Colors.blue); }); - testWidgets('renders with arrow correctly in up direction', (WidgetTester tester) async { - await tester.pumpWidget( - const TestApp( - home: Scaffold( - body: ZetaTooltip( - arrowDirection: ZetaTooltipArrowDirection.up, - child: Text('Tooltip up'), - ), - ), - ), - ); - - expect(find.text('Tooltip up'), findsOneWidget); - - // Verifying the CustomPaint with different arrow directions. - await expectLater( - find.byType(ZetaTooltip), - matchesGoldenFile(goldenFile.getFileUri('arrow_up')), - ); - }); - - testWidgets('renders with arrow correctly in down direction', (WidgetTester tester) async { - await tester.pumpWidget( - const TestApp( - home: Scaffold( - body: ZetaTooltip( - child: Text('Tooltip down'), - ), - ), - ), - ); - - expect(find.text('Tooltip down'), findsOneWidget); - - // Verifying the CustomPaint with different arrow directions. - await expectLater( - find.byType(ZetaTooltip), - matchesGoldenFile(goldenFile.getFileUri('arrow_down')), - ); - }); - - testWidgets('renders with arrow correctly in left direction', (WidgetTester tester) async { - await tester.pumpWidget( - const TestApp( - home: Scaffold( - body: ZetaTooltip( - arrowDirection: ZetaTooltipArrowDirection.left, - child: Text('Tooltip left'), - ), - ), - ), - ); - - expect(find.text('Tooltip left'), findsOneWidget); - - // Verifying the CustomPaint with different arrow directions. - await expectLater( - find.byType(ZetaTooltip), - matchesGoldenFile(goldenFile.getFileUri('arrow_left')), - ); - }); - - testWidgets('renders with arrow correctly in right direction', (WidgetTester tester) async { - await tester.pumpWidget( - const TestApp( - home: Scaffold( - body: ZetaTooltip( - arrowDirection: ZetaTooltipArrowDirection.right, - child: Text('Tooltip right'), - ), - ), - ), - ); - - expect(find.text('Tooltip right'), findsOneWidget); - - // Verifying the CustomPaint with different arrow directions. - await expectLater( - find.byType(ZetaTooltip), - matchesGoldenFile(goldenFile.getFileUri('arrow_right')), - ); - }); - testWidgets('renders with rounded and sharp corners', (WidgetTester tester) async { await tester.pumpWidget( const TestApp( @@ -221,23 +194,52 @@ void main() { expect((roundedTooltipBox.decoration as BoxDecoration).borderRadius, mockZeta.radius.minimal); expect((sharpTooltipBox.decoration as BoxDecoration).borderRadius, null); }); - - testWidgets('debugFillProperties works correctly', (WidgetTester tester) async { - final diagnostics = DiagnosticPropertiesBuilder(); - const ZetaTooltip( - padding: EdgeInsets.all(8), - color: Colors.amber, - textStyle: TextStyle(fontSize: 9), - maxWidth: 170, - child: Text('Rounded tooltip'), - ).debugFillProperties(diagnostics); - - 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'); - }); }); + group('$componentName Interaction Tests', () {}); + group('$componentName Golden Tests', () { + goldenTest( + goldenFile, + const Scaffold( + body: ZetaTooltip( + arrowDirection: ZetaTooltipArrowDirection.up, + child: Text('Tooltip up'), + ), + ), + ZetaTooltip, + 'arrow_up', + ); + goldenTest( + goldenFile, + const Scaffold( + body: ZetaTooltip( + child: Text('Tooltip down'), + ), + ), + ZetaTooltip, + 'arrow_down', + ); + goldenTest( + goldenFile, + const Scaffold( + body: ZetaTooltip( + arrowDirection: ZetaTooltipArrowDirection.left, + child: Text('Tooltip left'), + ), + ), + ZetaTooltip, + 'arrow_left', + ); + goldenTest( + goldenFile, + const Scaffold( + body: ZetaTooltip( + arrowDirection: ZetaTooltipArrowDirection.right, + child: Text('Tooltip right'), + ), + ), + ZetaTooltip, + 'arrow_right', + ); + }); + group('$componentName Performance Tests', () {}); } diff --git a/test/test_utils/utils.dart b/test/test_utils/utils.dart index 65e5b1c9..5117d045 100644 --- a/test/test_utils/utils.dart +++ b/test/test_utils/utils.dart @@ -3,8 +3,8 @@ import 'dart:io'; import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:path/path.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart'; import '../test_utils/test_app.dart'; extension Util on DiagnosticPropertiesBuilder { @@ -32,6 +32,32 @@ class GoldenFiles { } void goldenTest( + GoldenFiles goldenFile, + Widget widget, + Type widgetType, + String fileName, { + ThemeMode themeMode = ThemeMode.system, + Size? screenSize, + bool? rounded, +}) { + testWidgets('$fileName golden', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + screenSize: screenSize, + themeMode: themeMode, + rounded: rounded, + home: widget, + ), + ); + + await expectLater( + find.byType(widgetType), + matchesGoldenFile(goldenFile.getFileUri(fileName)), + ); + }); +} + +void goldenTestWithCallbacks( GoldenFiles goldenFile, Widget widget, Type widgetType, @@ -39,6 +65,7 @@ void goldenTest( Future Function(WidgetTester)? before, Future Function(WidgetTester)? after, bool darkMode = false, + Size? screenSize, }) { testWidgets('$fileName golden', (WidgetTester tester) async { if (before != null) { @@ -47,6 +74,7 @@ void goldenTest( await tester.pumpWidget( TestApp( + screenSize: screenSize, themeMode: darkMode ? ThemeMode.dark : ThemeMode.light, home: widget, ),