From 02f5d4cd3dcb5dd05039e945748b08cffd15a80e Mon Sep 17 00:00:00 2001 From: Prashant Sawant <75819349+ps9310@users.noreply.github.com> Date: Mon, 15 Jul 2024 09:54:19 -0400 Subject: [PATCH] feat: Add FocusNode to ZetaSearchBar (#132) test: adds tests for ZetaSearchBar --- coverage/lcov.info | 880 +++++++++--------- .../pages/components/search_bar_example.dart | 4 + lib/src/components/search_bar/search_bar.dart | 28 +- .../golden/in_page_banner_negative.png | Bin 3944 -> 3951 bytes .../search_bar/golden/search_bar_default.png | Bin 0 -> 3924 bytes .../search_bar/golden/search_bar_full.png | Bin 0 -> 5022 bytes .../search_bar/golden/search_bar_large.png | Bin 0 -> 3719 bytes .../search_bar/golden/search_bar_medium.png | Bin 0 -> 3959 bytes .../search_bar/golden/search_bar_sharp.png | Bin 0 -> 3719 bytes .../search_bar/golden/search_bar_small.png | Bin 0 -> 3920 bytes .../search_bar/search_bar_test.dart | 322 +++++++ .../search_bar/search_bar_test.mocks.dart | 56 ++ test/src/utils/extensions_test.mocks.dart | 7 + test/test_utils/utils.dart | 7 +- 14 files changed, 865 insertions(+), 439 deletions(-) create mode 100644 test/src/components/search_bar/golden/search_bar_default.png create mode 100644 test/src/components/search_bar/golden/search_bar_full.png create mode 100644 test/src/components/search_bar/golden/search_bar_large.png create mode 100644 test/src/components/search_bar/golden/search_bar_medium.png create mode 100644 test/src/components/search_bar/golden/search_bar_sharp.png create mode 100644 test/src/components/search_bar/golden/search_bar_small.png create mode 100644 test/src/components/search_bar/search_bar_test.dart create mode 100644 test/src/components/search_bar/search_bar_test.mocks.dart diff --git a/coverage/lcov.info b/coverage/lcov.info index aa09329f..913cd03b 100644 --- a/coverage/lcov.info +++ b/coverage/lcov.info @@ -1,3 +1,107 @@ +SF:lib/src/theme/contrast.dart +DA:18,23 +DA:20,23 +DA:22,5 +DA:31,2 +DA:33,2 +DA:35,2 +DA:44,5 +DA:46,5 +DA:48,2 +DA:57,3 +DA:59,3 +DA:61,2 +DA:70,2 +DA:72,2 +DA:74,2 +DA:83,2 +DA:85,2 +DA:87,2 +DA:96,6 +DA:98,6 +DA:100,2 +DA:108,2 +DA:110,2 +DA:112,2 +DA:120,3 +DA:122,3 +DA:124,2 +DA:141,2 +DA:143,2 +DA:145,1 +LF:30 +LH:30 +end_of_record +SF:lib/src/theme/theme_data.dart +DA:22,20 +DA:31,1 +DA:33,1 +DA:34,1 +DA:36,20 +DA:37,20 +DA:39,1 +DA:41,1 +DA:42,1 +DA:44,20 +DA:45,20 +DA:64,40 +DA:71,40 +DA:74,19 +DA:77,19 +DA:79,19 +DA:80,19 +DA:81,19 +DA:82,19 +DA:86,4 +DA:87,4 +DA:88,4 +DA:89,4 +DA:90,4 +DA:91,4 +LF:25 +LH:25 +end_of_record +SF:lib/src/zeta.dart +DA:15,19 +DA:52,15 +DA:53,30 +DA:54,62 +DA:55,4 +DA:56,2 +DA:58,4 +DA:67,2 +DA:68,4 +DA:69,2 +DA:70,2 +DA:77,3 +DA:79,9 +DA:80,9 +DA:81,6 +DA:82,6 +DA:83,6 +DA:90,17 +DA:91,17 +DA:95,1 +DA:96,1 +DA:97,1 +DA:98,1 +DA:101,1 +DA:102,1 +DA:103,2 +DA:104,1 +DA:105,1 +DA:113,1 +DA:115,1 +DA:117,3 +DA:118,3 +DA:119,3 +DA:120,3 +DA:121,3 +DA:122,3 +DA:123,3 +LF:37 +LH:37 +end_of_record SF:lib/src/components/accordion/accordion.dart DA:11,2 DA:38,1 @@ -77,15 +181,15 @@ LF:74 LH:53 end_of_record SF:lib/src/utils/rounded.dart -DA:11,7 -DA:21,12 -DA:22,12 -DA:25,1 -DA:26,3 +DA:11,8 +DA:21,13 +DA:22,13 +DA:25,2 +DA:26,6 DA:27,1 DA:29,1 DA:30,3 -DA:37,218 +DA:37,227 DA:42,8 DA:44,8 DA:45,24 @@ -93,11 +197,11 @@ DA:52,5 DA:57,3 DA:59,3 DA:60,9 -DA:67,13 -DA:69,44 +DA:67,14 +DA:69,46 DA:70,12 DA:73,16 -DA:76,41 +DA:76,43 LF:21 LH:21 end_of_record @@ -2243,21 +2347,21 @@ LF:27 LH:0 end_of_record SF:lib/src/components/icon/icon.dart -DA:17,210 -DA:190,9 -DA:192,9 -DA:193,18 -DA:194,9 -DA:195,9 -DA:196,9 -DA:197,9 -DA:198,9 -DA:199,9 -DA:200,9 -DA:201,9 -DA:202,9 -DA:203,9 -DA:204,9 +DA:17,219 +DA:190,10 +DA:192,10 +DA:193,20 +DA:194,10 +DA:195,10 +DA:196,10 +DA:197,10 +DA:198,10 +DA:199,10 +DA:200,10 +DA:201,10 +DA:202,10 +DA:203,10 +DA:204,10 DA:208,1 DA:210,1 DA:212,3 @@ -2272,15 +2376,15 @@ DA:220,3 DA:221,3 DA:222,3 DA:223,3 -DA:229,7 -DA:230,7 -DA:231,7 -DA:233,7 -DA:234,7 -DA:235,7 -DA:240,9 -DA:241,18 -DA:242,14 +DA:229,8 +DA:230,8 +DA:231,8 +DA:233,8 +DA:234,8 +DA:235,8 +DA:240,10 +DA:241,20 +DA:242,16 LF:38 LH:38 end_of_record @@ -2890,7 +2994,7 @@ DA:334,0 DA:335,0 DA:336,0 DA:337,0 -DA:342,25 +DA:342,26 DA:344,0 LF:141 LH:1 @@ -2938,7 +3042,7 @@ LF:38 LH:38 end_of_record SF:lib/src/components/phone_input/countries.dart -DA:4,25 +DA:4,26 DA:20,0 DA:22,0 DA:23,0 @@ -3458,100 +3562,108 @@ LF:18 LH:0 end_of_record SF:lib/src/components/search_bar/search_bar.dart -DA:8,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:58,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:68,0 -DA:77,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:85,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:92,0 -DA:94,0 -DA:95,0 -DA:98,0 -DA:100,0 -DA:101,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:109,0 -DA:111,0 -DA:113,0 -DA:115,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:121,0 -DA:122,0 -DA:124,0 -DA:126,0 -DA:135,0 -DA:136,0 -DA:138,0 -DA:139,0 -DA:140,0 -DA:145,0 -DA:146,0 -DA:147,0 -DA:149,0 -DA:151,0 -DA:155,0 -DA:156,0 -DA:158,0 -DA:159,0 -DA:165,0 -DA:167,0 -DA:168,0 -DA:173,0 -DA:175,0 -DA:176,0 -DA:178,0 -DA:179,0 -DA:182,0 -DA:196,0 -DA:197,0 -DA:198,0 -DA:199,0 -DA:200,0 -DA:206,0 -DA:207,0 -DA:208,0 -DA:209,0 -DA:212,0 -DA:213,0 -DA:214,0 -DA:215,0 -DA:218,0 -DA:222,0 -DA:223,0 -DA:224,0 -DA:227,0 -DA:231,0 -DA:232,0 -DA:233,0 -DA:236,0 -DA:237,0 -DA:238,0 -LF:92 -LH:0 +DA:8,2 +DA:66,1 +DA:67,1 +DA:69,1 +DA:71,1 +DA:73,3 +DA:74,3 +DA:75,3 +DA:76,3 +DA:77,3 +DA:78,3 +DA:79,3 +DA:80,3 +DA:81,3 +DA:82,3 +DA:83,3 +DA:84,3 +DA:93,1 +DA:95,1 +DA:96,4 +DA:97,3 +DA:98,3 +DA:101,1 +DA:103,1 +DA:104,3 +DA:105,3 +DA:106,4 +DA:107,4 +DA:111,1 +DA:113,2 +DA:114,1 +DA:117,1 +DA:119,1 +DA:120,2 +DA:122,1 +DA:123,3 +DA:124,1 +DA:125,2 +DA:126,2 +DA:127,1 +DA:129,2 +DA:130,2 +DA:131,6 +DA:133,1 +DA:135,1 +DA:137,2 +DA:139,2 +DA:140,1 +DA:141,7 +DA:143,2 +DA:144,1 +DA:146,1 +DA:148,8 +DA:157,1 +DA:158,1 +DA:160,1 +DA:161,6 +DA:162,1 +DA:168,1 +DA:169,3 +DA:170,3 +DA:172,1 +DA:174,3 +DA:178,2 +DA:179,1 +DA:181,1 +DA:182,3 +DA:188,1 +DA:190,2 +DA:191,1 +DA:197,2 +DA:199,1 +DA:200,3 +DA:202,4 +DA:203,2 +DA:206,1 +DA:220,2 +DA:221,5 +DA:222,2 +DA:223,2 +DA:224,2 +DA:230,1 +DA:231,1 +DA:232,1 +DA:233,1 +DA:236,1 +DA:237,1 +DA:238,1 +DA:239,1 +DA:242,1 +DA:246,1 +DA:247,1 +DA:248,4 +DA:251,1 +DA:255,1 +DA:256,1 +DA:257,4 +DA:260,1 +DA:261,1 +DA:262,1 +LF:100 +LH:100 end_of_record SF:lib/src/components/segmented_control/segmented_control.dart DA:11,0 @@ -3935,47 +4047,6 @@ DA:146,0 LF:50 LH:0 end_of_record -SF:lib/src/zeta.dart -DA:15,18 -DA:52,14 -DA:53,28 -DA:54,58 -DA:55,4 -DA:56,2 -DA:58,4 -DA:67,2 -DA:68,4 -DA:69,2 -DA:70,2 -DA:77,2 -DA:79,6 -DA:80,6 -DA:81,3 -DA:82,3 -DA:83,3 -DA:90,16 -DA:91,16 -DA:95,1 -DA:96,1 -DA:97,1 -DA:98,1 -DA:101,1 -DA:102,1 -DA:103,2 -DA:104,1 -DA:105,1 -DA:113,1 -DA:115,1 -DA:117,3 -DA:118,3 -DA:119,3 -DA:120,3 -DA:121,3 -DA:122,3 -DA:123,3 -LF:37 -LH:37 -end_of_record SF:lib/src/components/snack_bar/snack_bar.dart DA:38,0 DA:82,0 @@ -5685,8 +5756,8 @@ DA:63,1 DA:64,1 DA:65,1 DA:66,7 -DA:75,53 -DA:78,54 +DA:75,56 +DA:78,57 DA:81,3 DA:94,1 DA:96,1 @@ -5746,26 +5817,26 @@ LF:76 LH:76 end_of_record SF:lib/src/theme/color_swatch.dart -DA:15,47 -DA:20,22 +DA:15,49 +DA:20,23 DA:32,3 DA:45,3 DA:48,3 DA:49,3 DA:50,3 -DA:67,23 -DA:68,90 -DA:71,44 -DA:74,18 -DA:77,16 -DA:80,16 -DA:83,22 -DA:86,16 -DA:89,20 -DA:92,16 -DA:95,46 -DA:98,14 -DA:106,36 +DA:67,24 +DA:68,94 +DA:71,46 +DA:74,20 +DA:77,18 +DA:80,18 +DA:83,24 +DA:86,18 +DA:89,22 +DA:92,18 +DA:95,48 +DA:98,16 +DA:106,38 DA:112,4 DA:118,16 DA:124,8 @@ -5774,155 +5845,121 @@ DA:136,4 DA:142,20 DA:148,4 DA:153,8 -DA:165,23 -DA:169,92 -DA:172,84 -DA:175,105 -DA:178,66 -DA:181,21 -DA:184,42 -DA:189,7 -DA:190,7 -DA:191,7 -DA:192,7 -DA:193,7 -DA:194,7 -DA:195,7 -DA:196,7 -DA:197,7 -DA:198,7 -DA:199,7 -DA:200,7 -DA:201,7 -DA:202,7 -DA:203,7 +DA:165,24 +DA:169,96 +DA:172,88 +DA:175,110 +DA:178,69 +DA:181,22 +DA:184,44 +DA:189,8 +DA:190,8 +DA:191,8 +DA:192,8 +DA:193,8 +DA:194,8 +DA:195,8 +DA:196,8 +DA:197,8 +DA:198,8 +DA:199,8 +DA:200,8 +DA:201,8 +DA:202,8 +DA:203,8 LF:50 LH:50 end_of_record -SF:lib/src/theme/contrast.dart -DA:18,22 -DA:20,22 -DA:22,5 -DA:31,2 -DA:33,2 -DA:35,2 -DA:44,5 -DA:46,5 -DA:48,2 -DA:57,3 -DA:59,3 -DA:61,2 -DA:70,2 -DA:72,2 -DA:74,2 -DA:83,2 -DA:85,2 -DA:87,2 -DA:96,6 -DA:98,6 -DA:100,2 -DA:108,2 -DA:110,2 -DA:112,2 -DA:120,3 -DA:122,3 -DA:124,2 -DA:141,2 -DA:143,2 -DA:145,1 -LF:30 -LH:30 -end_of_record SF:lib/src/theme/color_scheme.dart -DA:29,18 -DA:95,18 -DA:151,18 -DA:152,17 -DA:153,17 -DA:154,18 -DA:155,17 -DA:156,17 -DA:157,18 -DA:158,18 -DA:159,18 -DA:160,18 -DA:161,18 -DA:162,18 -DA:163,18 -DA:164,18 -DA:165,18 -DA:166,18 -DA:167,18 -DA:168,18 -DA:169,18 -DA:170,18 -DA:171,18 -DA:172,18 -DA:173,18 -DA:174,18 -DA:175,18 -DA:176,18 -DA:177,18 -DA:178,18 -DA:179,18 -DA:180,18 -DA:181,18 -DA:182,18 -DA:183,18 -DA:184,18 -DA:185,18 -DA:186,18 -DA:187,18 -DA:188,18 -DA:189,18 -DA:190,18 -DA:191,18 -DA:192,18 -DA:193,18 -DA:194,18 -DA:195,18 -DA:196,18 +DA:29,19 +DA:95,19 +DA:151,19 +DA:152,18 +DA:153,18 +DA:154,19 +DA:155,18 +DA:156,18 +DA:157,19 +DA:158,19 +DA:159,19 +DA:160,19 +DA:161,19 +DA:162,19 +DA:163,19 +DA:164,19 +DA:165,19 +DA:166,19 +DA:167,19 +DA:168,19 +DA:169,19 +DA:170,19 +DA:171,19 +DA:172,19 +DA:173,19 +DA:174,19 +DA:175,19 +DA:176,19 +DA:177,19 +DA:178,19 +DA:179,19 +DA:180,19 +DA:181,19 +DA:182,19 +DA:183,19 +DA:184,19 +DA:185,19 +DA:186,19 +DA:187,19 +DA:188,19 +DA:189,19 +DA:190,19 +DA:191,19 +DA:192,19 +DA:193,19 +DA:194,19 +DA:195,19 +DA:196,19 DA:200,1 DA:202,1 DA:204,3 DA:205,3 -DA:208,17 -DA:211,1 -DA:212,1 -DA:213,3 -DA:214,3 -DA:215,3 +DA:208,18 +DA:211,2 +DA:212,2 +DA:213,6 +DA:214,6 +DA:215,6 DA:217,1 DA:218,7 LF:60 LH:60 end_of_record SF:lib/src/theme/colors.dart -DA:16,22 -DA:34,22 -DA:35,22 -DA:36,22 -DA:37,22 -DA:38,22 -DA:39,22 -DA:42,22 -DA:48,22 -DA:50,21 -DA:56,21 -DA:57,22 -DA:58,22 -DA:59,22 -DA:60,22 -DA:61,22 -DA:62,22 -DA:63,22 -DA:64,22 -DA:78,20 -DA:91,20 +DA:16,23 +DA:34,23 +DA:35,23 +DA:36,23 +DA:37,23 +DA:38,23 +DA:39,23 +DA:42,23 +DA:48,23 +DA:50,22 +DA:56,22 +DA:57,23 +DA:58,23 +DA:59,23 +DA:60,23 +DA:61,23 +DA:62,23 +DA:63,23 +DA:64,23 +DA:78,21 +DA:91,21 DA:100,1 DA:101,1 -DA:118,20 -DA:131,20 +DA:118,21 +DA:131,21 DA:141,1 DA:142,1 DA:148,1 @@ -5940,7 +5977,7 @@ DA:169,1 DA:172,1 DA:176,1 DA:180,1 -DA:276,51 +DA:276,54 DA:285,6 DA:292,6 DA:301,6 @@ -5996,10 +6033,10 @@ DA:592,1 DA:593,1 DA:594,1 DA:595,1 -DA:599,22 -DA:607,22 -DA:611,22 -DA:617,22 +DA:599,23 +DA:607,23 +DA:611,23 +DA:617,23 DA:623,3 DA:640,3 DA:641,3 @@ -6015,35 +6052,35 @@ DA:650,3 DA:651,3 DA:652,3 DA:653,8 -DA:660,20 -DA:663,40 +DA:660,21 +DA:663,42 DA:664,3 -DA:670,17 -DA:671,68 -DA:672,68 -DA:673,17 -DA:674,17 -DA:676,17 -DA:678,17 -DA:680,17 -DA:681,17 -DA:682,17 -DA:683,17 -DA:690,5 -DA:691,5 -DA:692,5 -DA:693,5 -DA:694,5 -DA:695,5 -DA:696,5 -DA:697,5 -DA:698,5 -DA:699,5 -DA:700,5 -DA:701,5 -DA:702,5 -DA:703,5 -DA:741,34 +DA:670,18 +DA:671,72 +DA:672,72 +DA:673,18 +DA:674,18 +DA:676,18 +DA:678,18 +DA:680,18 +DA:681,18 +DA:682,18 +DA:683,18 +DA:690,6 +DA:691,6 +DA:692,6 +DA:693,6 +DA:694,6 +DA:695,6 +DA:696,6 +DA:697,6 +DA:698,6 +DA:699,6 +DA:700,6 +DA:701,6 +DA:702,6 +DA:703,6 +DA:741,36 DA:744,2 DA:751,1 DA:752,4 @@ -6065,8 +6102,8 @@ DA:848,1 DA:849,4 DA:855,1 DA:856,4 -DA:863,17 -DA:864,52 +DA:863,18 +DA:864,55 DA:871,1 DA:872,4 DA:879,5 @@ -6144,35 +6181,6 @@ DA:1050,2 LF:243 LH:243 end_of_record -SF:lib/src/theme/theme_data.dart -DA:22,19 -DA:31,1 -DA:33,1 -DA:34,1 -DA:36,19 -DA:37,19 -DA:39,1 -DA:41,1 -DA:42,1 -DA:44,19 -DA:45,19 -DA:64,38 -DA:71,38 -DA:74,18 -DA:77,18 -DA:79,18 -DA:80,18 -DA:81,18 -DA:82,18 -DA:86,3 -DA:87,3 -DA:88,3 -DA:89,3 -DA:90,3 -DA:91,3 -LF:25 -LH:25 -end_of_record SF:lib/src/utils/debounce.dart DA:10,2 DA:11,4 @@ -6236,22 +6244,22 @@ LF:46 LH:46 end_of_record SF:lib/src/utils/nothing.dart -DA:6,326 -DA:8,1 +DA:6,339 +DA:8,2 LF:2 LH:2 end_of_record SF:lib/src/zeta_provider.dart -DA:23,32 -DA:24,34 +DA:23,34 +DA:24,36 DA:32,1 DA:40,1 DA:41,1 -DA:49,16 -DA:59,16 -DA:60,16 -DA:105,17 -DA:106,17 +DA:49,17 +DA:59,17 +DA:60,17 +DA:105,18 +DA:106,18 DA:108,1 DA:110,1 DA:112,3 @@ -6274,19 +6282,19 @@ DA:136,1 DA:137,2 DA:138,1 DA:139,1 -DA:186,17 -DA:188,17 -DA:189,34 -DA:192,102 -DA:195,51 -DA:198,51 -DA:201,51 -DA:204,85 -DA:207,51 -DA:210,51 -DA:216,17 -DA:218,34 -DA:219,17 +DA:186,18 +DA:188,18 +DA:189,36 +DA:192,108 +DA:195,54 +DA:198,54 +DA:201,54 +DA:204,90 +DA:207,54 +DA:210,54 +DA:216,18 +DA:218,36 +DA:219,18 DA:226,1 DA:228,1 DA:231,1 @@ -6297,22 +6305,22 @@ DA:245,3 DA:247,4 DA:249,2 DA:251,2 -DA:258,17 -DA:260,68 -DA:261,16 -DA:262,16 -DA:263,16 -DA:264,16 -DA:265,16 -DA:266,16 -DA:267,48 -DA:269,16 -DA:271,16 -DA:272,64 -DA:274,16 -DA:276,16 -DA:277,64 -DA:279,16 +DA:258,18 +DA:260,72 +DA:261,17 +DA:262,17 +DA:263,17 +DA:264,17 +DA:265,17 +DA:266,17 +DA:267,51 +DA:269,17 +DA:271,17 +DA:272,68 +DA:274,17 +DA:276,17 +DA:277,68 +DA:279,17 DA:284,1 DA:285,1 DA:286,1 @@ -6320,13 +6328,13 @@ DA:287,1 DA:288,1 DA:289,1 DA:290,5 -DA:294,1 -DA:296,1 -DA:297,4 -DA:298,4 -DA:299,4 -DA:300,4 -DA:301,0 +DA:294,2 +DA:296,2 +DA:297,8 +DA:298,8 +DA:299,8 +DA:300,8 +DA:301,4 DA:302,2 DA:303,3 DA:304,3 @@ -6361,7 +6369,7 @@ DA:358,1 DA:360,3 DA:361,3 DA:362,3 -DA:367,16 +DA:367,17 DA:376,0 DA:378,0 DA:380,0 @@ -6373,12 +6381,12 @@ DA:388,0 DA:389,0 DA:390,0 DA:391,0 -DA:395,16 -DA:399,16 -DA:400,16 -DA:402,16 +DA:395,17 +DA:399,17 +DA:400,17 +DA:402,17 DA:405,0 -DA:406,16 +DA:406,17 LF:137 -LH:120 +LH:121 end_of_record diff --git a/example/lib/pages/components/search_bar_example.dart b/example/lib/pages/components/search_bar_example.dart index 9b357322..afaf0520 100644 --- a/example/lib/pages/components/search_bar_example.dart +++ b/example/lib/pages/components/search_bar_example.dart @@ -27,6 +27,10 @@ class _SearchBarExampleState extends State { padding: const EdgeInsets.all(20), child: ZetaSearchBar( onChanged: (value) {}, + textInputAction: TextInputAction.search, + onSubmit: (text) { + print(text); + }, ), ), Padding( diff --git a/lib/src/components/search_bar/search_bar.dart b/lib/src/components/search_bar/search_bar.dart index 9ec0354b..c549b236 100644 --- a/lib/src/components/search_bar/search_bar.dart +++ b/lib/src/components/search_bar/search_bar.dart @@ -12,11 +12,14 @@ class ZetaSearchBar extends StatefulWidget { this.hint, this.initialValue, this.onChanged, + this.onSubmit, this.onSpeechToText, this.disabled = false, this.showLeadingIcon = true, this.showSpeechToText = true, @Deprecated('Use disabled instead. ' 'enabled is deprecated as of 0.11.0') bool enabled = true, + this.focusNode, + this.textInputAction, }); /// Determines the size of the input field. @@ -35,7 +38,13 @@ class ZetaSearchBar extends StatefulWidget { final String? initialValue; /// A callback, which provides the entered text. - final void Function(String?)? onChanged; + final void Function(String? text)? onChanged; + + /// A callback, called when [textInputAction] is performed. + final void Function(String text)? onSubmit; + + /// The type of action button to use for the keyboard. + final TextInputAction? textInputAction; /// A callback, which is invoked when the microphone button is pressed. final Future Function()? onSpeechToText; @@ -51,8 +60,12 @@ class ZetaSearchBar extends StatefulWidget { /// Default is `true`. final bool showSpeechToText; + /// A [FocusNode] for the underlying [TextFormField] + final FocusNode? focusNode; + @override State createState() => _ZetaSearchBarState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -65,7 +78,10 @@ class ZetaSearchBar extends StatefulWidget { ..add(StringProperty('initialValue', initialValue)) ..add(ObjectFlagProperty.has('onSpeechToText', onSpeechToText)) ..add(DiagnosticsProperty('showLeadingIcon', showLeadingIcon)) - ..add(DiagnosticsProperty('showSpeechToText', showSpeechToText)); + ..add(DiagnosticsProperty('showSpeechToText', showSpeechToText)) + ..add(DiagnosticsProperty('focusNode', focusNode)) + ..add(ObjectFlagProperty.has('onSubmit', onSubmit)) + ..add(EnumProperty('textInputAction', textInputAction)); } } @@ -87,6 +103,9 @@ class _ZetaSearchBarState extends State { super.didUpdateWidget(oldWidget); _size = widget.size ?? ZetaWidgetSize.large; _shape = widget.shape ?? ZetaWidgetBorder.rounded; + if (oldWidget.initialValue != widget.initialValue) { + _controller.text = widget.initialValue ?? ''; + } } @override @@ -103,9 +122,12 @@ class _ZetaSearchBarState extends State { return ZetaRoundedScope( rounded: widget.shape != ZetaWidgetBorder.sharp, child: TextFormField( + focusNode: widget.focusNode, enabled: !widget.disabled, controller: _controller, keyboardType: TextInputType.text, + textInputAction: widget.textInputAction, + onFieldSubmitted: widget.onSubmit, onChanged: (value) => setState(() => widget.onChanged?.call(value)), style: ZetaTextStyles.bodyMedium, decoration: InputDecoration( @@ -138,6 +160,7 @@ class _ZetaSearchBarState extends State { children: [ if (_controller.text.isNotEmpty && !widget.disabled) ...[ IconButton( + key: const ValueKey('search-clear-btn'), visualDensity: const VisualDensity( horizontal: -4, vertical: -4, @@ -166,6 +189,7 @@ class _ZetaSearchBarState extends State { padding: const EdgeInsets.only(right: ZetaSpacing.minimum), child: widget.showSpeechToText ? IconButton( + key: const ValueKey('speech-to-text-btn'), visualDensity: const VisualDensity( horizontal: -4, vertical: -4, 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 index 3088dce8aab8cb247f2b5755900cf2c48f486bae..5f808d4846d11e152ced62b40d068fb93bf34f62 100644 GIT binary patch literal 3951 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`Gr)5S5QV$R#Ur@QZ^OEx?#=Tn>8vdq|5ePw&B_S*lA9*(-w)u;0RYjkSAe*E}q<^H~GaeZC}hK62)z0aR* z{G6LF``KMiYWKbR`!n`_x*XqE%--L3R9{AJ_xru+XWqr%c_Yin(4hP1)y(3@pVrTl zdoEW~@n-g~PcweqzI}gl)obSO{j=>q+&g;@Xy%PYdVgP}KR$F){rHzBH=iGSSH3@c z^LIuDhHV>S-`5FfdFI z1O};tTLUokB+&%Z%Jw$@|M#0a`RSYP*R$r{EWcfGIQrg~S)wK(~I z=i~L2c}6pPLqIy??*>`T6nJ-{e+*?=#>3 z@f+{WWM`(7_Y3{|U;ebsp0{&bN#UITx6I8SSpluFnp^Yeo=^s*< zf6fUxX(0t}{+gUK_x9zVH4gWmFADVNhO<98#26TIjOYJ6(pY$U-d6jAUp^h}e*E!$ zP5I&XVqg_AKTfnC`*-xH>G?U9?;>URLea$!FuXBz46Np^JA-*|1(+_`|Enzdti?$ sN6`55_8!^t`<7yTGBU;Qcjy0McYAlyG5Xhzopr0P-_dZ~y=R literal 3944 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`Gh)5S5QV$R#UzTNZEB^w@A+xg7mS!=v@<`tnkTQ2?Lcj3C_>UyO& z`=V0Ik%qt~lUz-SmL{{%rnMct+J)L0VIn1oQ&;@p4%*t}(eZP|$r~1zznM-hd>Ayt z=_?FfcT%HK@HlH~BsL zJ^N?#e>}SJ|D^lzH`4ZhpYEvov$F8PYW3rHl==H_HnVT5c4uHnXx~x!^Hs#Zt2+z7 z-gul`_-d!&*X#UsId9)B?(em>|N8OmJzfTe8w>OPyhwk1tNXtE<;mf3vc>X$Pn5l9 zW?*=e@Z0{+Lc^br;QCR4+A3ugAtnGnKxACq`IbNPIk-{0Tf{vgA^aHr2qR^j@*|Mzy(ePf?JE7s!E z%)$>}R&KX7pXqaqzy8yuW$$*x&awLW)R2XPfnoQNWz0ZF?Wq0p_E2l#&r?%<&&tKb z$h@~M$?*PmV-my8=SQ9&|MDmH^}L;1zx?`feCGSSqooWC2iR=C|JifaK?<#$ljlFg+0-QYoPQht{mj~@ zQ`hbQCe|Ijxt1$N0X1fq_Am5g64eps<}FsKCJB z;06+u92Fc5kkQ02nh{1zhS5@Sv_=@M4M%Ik(b{mdHl%fJm{ygRShprF`qn#JV0TM4 z=j*LYGa_fmU#^zhQ@`fVv+uX}0^9Bzn%DmMRi1pl`FsD(*2%|@KTYoM-+D6TjP0in zGb{_vm%Rt}dfy0`>&Hr-*8g7?^Y_%|Ax)ZhY@_KVHv}^y$Lqn#j5bz|H`Jr>mdKI;Vst0E{p+ A?EnA( diff --git a/test/src/components/search_bar/golden/search_bar_default.png b/test/src/components/search_bar/golden/search_bar_default.png new file mode 100644 index 0000000000000000000000000000000000000000..ecfc9ef1e7193e9cd79b7bdeacf96a792c25ad8b GIT binary patch literal 3924 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefr0Ozr;B4q#hkZy?epiROCET5{9B>#oQQ3cmMwJZ3VG4MF`sF|3N5uO z`iBmkIKUy~(;;}U;RnMCEg{!cH%_(9I>f-DxF9#F-KtMk{(q-rgn-bBZ-mO z^Sd@L|M~LId%j(|c=6)RlP6zR{CN0ySD%Pv1=WMDAh&(2<*T>SXej(w%MK5E*@ zFCRQOc{Bdsw}hD8zgBMCSy;Me?OMGmcLs(BlVe$7vIazz);Yco42O_?%w8&Hgn~6m$5Q1 z{E1(?c5UCwFBLlaRf0f+Cp$L)Lqw91iGd-7g@b`%f}jEegM%ALaOTNM_C9~VW7g&M z_R|mVuXz4BxwPn=C<8-7an-LcFK^tuIrH@9ygNG#r%l)Y7JF=`{a^b#Kac--_r0!Q z;o*OmzwiJ2w(#|}vpa3L85n-N=i}!;9-aTUO7DEt*Q?>je*OB@nihKyXsrpSUl=FRJ?{{FA#-Ol>$n>HEw`TOhJ?BBJ^s;|Fa-=@B( z$VzSURMvU*Mry`;@;~1xUj6vn+uP#v*cl!?erj`l1s@;ZvDfSO8%{5t-)Vk8-nPnQ z->*~G)2fc8$5&T%i*h6pTf8k&G_bbb7{{QRk|FZe^ZR^c)>TbDm$_<7O4&aB@S7_t{`=l@Sre7>s*7*#3f9T|K0xh z-?w%7K({pPoCQqI!1VgD;{VAV`?eZR>+9<~=jZ2l{4oFbWAE-YasZw6EG;*;GzXY` zUq?$P8%6#MZ_ugI1f|%6@rY!@A;7?(pzHuNvWEev2a=XX1xEv9G%)}R)zOSFnh{1b r!e~Yqts+O82cu1+(b^DOZTQ*$r1yo>`+0UfVgLe9S3j3^P6>4f#mb5 zA1)t{kKM4&a~%Xh8xDVWC=r5I_(70M%9_>SO#|hJT<`_UON@<%*b=WP@MC3O^x@<+ z;8U^&{}Tjl{qFFggUJO=I>ixkQ);`>>1?;EO~*|6W2WV3L1c3} zYr1I?Kgp5Ihqvza+Sqz=6~(j~;jvyblbaIDyg+}d@}xgS)Snn!fS{B)}o92X%|4cBJes)-6w(wZFz)p2K5}W}g_0hC$^r z@;~ZFvVtSVlYfcx=L)-V#Y?VI4TX3!1jBPz2Zh@&xqO%xE7Ig|J1&iv1m+{98VTy3 z1PJ<#i(tf)c#&-i+l~8F6Ul7T@$&>!eWBz}esW|n_kI^jnA3XA5IClQpmOrfL3|?V z7>^|iX}hyjb+J8!s_r6eyb{oylZ^1>mKZ4FmpwtfDG>C&$is(Dv`%HBm4Eh z_zhPE@oCK+9U~QYfcp$_MF4Pb>>5^bxUG%GN6boT=*Q9Ott;@MUebUXjK&%ZCylUO zA!r8iV}C+v@4YnNUh4PAlJn*3E17BOv3^T%5+-2?00v`TJvk1owOZm92W#cnr6-OVoSToCO@*< zB(tf5?6!(N#o^2>K2oNDu%S6Qsle=a%NGAHq@7d^_S)F6# zdsnV^fgsFjN=v%J+-NkT?Vr0S8BxHY$UBPCJjp=34CRAmgq0w-VnLOa35U3^2?WT-rnBn1L3R zniI)d+&tTl8Doahjt6yuRt^fh{aZ|+W7FtWGXv} zKCdiY1twTA%!K*85SEB~T>R+KuQ`Eltsv?d%~+w?)5{AzKXWpLp0sf@45UwWW_N;X zWvn#ZlTK1^Ark=E(4ztc>s8hX@vDLpx@!=y%4n{q2>u{M_A-?BPF(_f zDt*LtJHeV6z85_PF`R=bZc(t9uO5Iba&Pz~qRkB#k#zd{vL)^4yjwar^njyaT z1Vfz2d;P{erNX+JvL1OSn*P*X2{SLzmM4z{0TCOp%+}a<6$$HLuX`_?x$l4V+`=Cq zuDlocu+GMiOx8ED`c56A`@Aq2g;K4O11V}KqBAAbFfe*6ZQ#h|Q~zbt%Q;*oSy zBipeaV6C;|eD=tk@QI4%>pH-Y3#Sbmhy}q#JKO*~cHKm7GLScJfuMLfb-pSxg)d6c z91Br>nQT_Rv$k32&_iisJ29BpD)LQtY$()f^%x+rm&V`KMUZW3xU%pwy7PddW8%M^ zK&^f=dvB~EmY!)Z(>%iB%=%rhM3h63jI+gY zX<6u=G=5Utk?});YFG-E@xt+pKJ31IoQMHSEz%E#>fWaVL==`!1W`V68#u_V{)vRr zg>GDvhc7BXTizSYh<9jES|6=-8=tWY_g9cc;``kKoCb)64QOIk)3Q8i#fLiq?L)*c z#>kxYNyCAgSq?3(1RO})8>Lyn8b&2`C|LaxmT0_{J#sw<#4$5af$czRNQUjJq3y3LoqAUqhT z#4f*HJ4v{B6DmAMB5)|6Pqaq1nICQk4FD(3WRB_3;vTuw(T~3J2NyWHw?0mj73`=V zPzL_P=gu3nQrr7qixlpSaNagYKf2@cp~_P1iUcM)<7idK?>H1VMf`Mzg)h z{-7TC-yoA168f}6+55AZvpWiuTDi1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq~D^)5S5QV$R#UzTH<-B@R4Hw@GJ7SDi6a`f!or%jGK+CWbu}&%C_J z^>kB|>**D)Ul^Tuv?i3X>86-06fa&nDOh1i^SO-M99-wQ_fM{heO>(jeR|pRD?1x=f8Q&_XcKiv+f&tNe-zg*ASwQHB!ygty#oP2)X z&$`nye%}87KDxf=`@R1K>r(%JIk@|Mk8?Yp-qT2+rTcH+yC?VjeEsez>2vLBvvP8B z&X~UD5`)>E_E6j)ZKqr5=V$qk&u+gruk!f2ckgyoeZ4;O`M*4)nLT&!-rf29`t|F_ z|Nj2|eBS+=H)SusOlkdHeypVNd+xV)vGVSHGBc~?7#jXhk6agccV}_>9NX$V&1(5> z^8@+!_u0l-fBofjzT)AFiyu#4U0r;B|F2W0AFp1&e`fW+Bc0QaE%lxrzU}{qhtH3F zeQo}1o_*PyqaUB{)PFXQouR=n<{;3=PE0He3@12%;isVNz`)SZ!@$VEV1!kW`@i~^ z?%C6i8=LdlTuRTsdn>9$mVsdd%l5q7-rC>)YL=Y8w|Dp6Eql4yPaL0Lx38xd7#j<@ z#rH*@j0@iYH2TaN#!cIfyggk544n`1|K#JJr0;7geQ~q-@n(O!S=EXR3>R+SxM6;7 zPG$1d;}tgR64tKOjmw_=GUcMPj>W!PKToD?++S}M`=b=7GUAWwmqY*l{yu)*{_loY z$v~U9t90rZfo`A2gVpgQ3i=$ENdA0kD<)= literal 0 HcmV?d00001 diff --git a/test/src/components/search_bar/golden/search_bar_medium.png b/test/src/components/search_bar/golden/search_bar_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..43b88a140d33847c59d63b1fc30b2c8548aa7ecb GIT binary patch literal 3959 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`Gq)5S5QV$R#UzS(mtB^y50PntY$<`%`7R>oEwts7ef(=RqCG;zDK zy0RQRe<60^eCL9f%LT%lxLHMGIf4o;U-igpFS@*O<=kbNm*(ve5YKDR@-qt0dj37y z{`=?shi^W4WU0?xU0v|ftyU}$)L2UOR8 zrDT^4$h3-U-N3+*muF&OU^u}cz`&rO>;RNM^JE9}|2?}c?S4Es7}LJ@%cWmGo~&Mf z#*~|ZVa~j}ckdd`KKpFeT)*YXsi~>!ZYHyz;IIGk_~Y%_`{%#jpkMd!^W$S*vy0C% zF)%EDKDYdzP2SzA@^v@0!}a=mdsi2qm9uu>YHx3U{O#@jc`xL=y}ciQ_)zff=hLT8 zH}2nW|NYOwgAZr;Ogs1CPqX37Gygx$v)*o_7rV>kyA1))<^{Cxk9r*}T*@B6v) zj z-qOOtX6j}?5ry}6EB}W~1DbK}+_PtCWz)cx%uKdt+*$bd)(#+c-w2EqftxpWSecov zd-lAF31t7glMIm&5f&e9r~NzKp7F0;)z6}C+h=cY_20kMCkxlw0G(%d#rS9ZvtPe{ zReZlDf4+(rm=vejPWE>IC8NmIFbD)VXySjYM+I2lgyI+eRTRd0&@w>gc{!T#k!KSm{_V50_4Jdg0@uOd_B5vHi zZEa;?A@f~6r+@9+SV5o%=FECoQVG)C{d#q>QRFZGhB;q>nfk!-=KO;|X*^CtBw{4@ zjtYXJbu>V5r|8iXGMYm0mwBTpWHg10rVx~7;%J33TA{%E45Nu*I46eB`3pDQPA<7M R0c)I$ztaD0e0stw@Sv&v$ literal 0 HcmV?d00001 diff --git a/test/src/components/search_bar/golden/search_bar_sharp.png b/test/src/components/search_bar/golden/search_bar_sharp.png new file mode 100644 index 0000000000000000000000000000000000000000..7bbccd7dc701a09f34ce391c04a50282c9a2aeea GIT binary patch literal 3719 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq~D^)5S5QV$R#UzTH<-B@R4Hw@GJ7SDi6a`f!or%jGK+CWbu}&%C_J z^>kB|>**D)Ul^Tuv?i3X>86-06fa&nDOh1i^SO-M99-wQ_fM{heO>(jeR|pRD?1x=f8Q&_XcKiv+f&tNe-zg*ASwQHB!ygty#oP2)X z&$`nye%}87KDxf=`@R1K>r(%JIk@|Mk8?Yp-qT2+rTcH+yC?VjeEsez>2vLBvvP8B z&X~UD5`)>E_E6j)ZKqr5=V$qk&u+gruk!f2ckgyoeZ4;O`M*4)nLT&!-rf29`t|F_ z|Nj2|eBS+=H)SusOlkdHeypVNd+xV)vGVSHGBc~?7#jXhk6agccV}_>9NX$V&1(5> z^8@+!_u0l-fBofjzT)AFiyu#4U0r;B|F2W0AFp1&e`fW+Bc0QaE%lxrzU}{qhtH3F zeQo}1o_*PyqaUB{)PFXQouR=n<{;3=PE0He3@12%;isVNz`)SZ!@$VEV1!kW`@i~^ z?%C6i8=LdlTuRTsdn>9$mVsdd%l5q7-rC>)YL=Y8w|Dp6Eql4yPaL0Lx38xd7#j<@ z#rH*@j0@iYH2TaN#!cIfyggk544n`1|K#JJr0;7geQ~q-@n(O!S=EXR3>R+SxM6;7 zPG$1d;}tgR64tKOjmw_=GUcMPj>W!PKToD?++S}M`=b=7GUAWwmqY*l{yu)*{_loY z$v~U9t90rZfo`A2gVpgQ3i=$ENdA0kD<)= literal 0 HcmV?d00001 diff --git a/test/src/components/search_bar/golden/search_bar_small.png b/test/src/components/search_bar/golden/search_bar_small.png new file mode 100644 index 0000000000000000000000000000000000000000..d5e52b4db0c8b78f3765dbc0830f4c8da358e512 GIT binary patch literal 3920 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefr0Orr;B4q#hkZy&gRVtmp$+>x%!Qxr`k3phY-<;T(K8-H+XHxFkcaV zut`^ldz#182t}4`vpWuv4nG5~R%_&NHBJed;ud-=dAV%;5uFk2l85<6~fGa8Ic__pZZ(|wrf2Q% z@Amt4{QcMd_|{eZp1(J*8qR%}SJltJa3DBor;Y6AqaQ7-{-xZh`RASdTK@l^4@o`U zAD`;Wdn+9PyILNe{z0)`JFwL#cwMa80_}z z>FFIyD%^7EOio#DPHyhnJ=eVMNAQcgKW?}G_0fy_&!6S%`|-e?9y0xBZ_&AT#dQv5Mz&?Q?VfKA-pd)Q<o}bU&hs~<|dNur5$*%36qShqodSqH+QY+zAfvGjgNJyEByX_{rLL2pWR=>n1GSwQC(gAcD`xKR+s*~Xnws>HM{n0-$K=)9Z{Vmhb+i8XXb1<{h*Xn>3c2>t?T zG=+?&kkJ$ZY_^PMgwc#Jnh{1b0%n_iv}7QrWcbgvIN)M}w{!0^U^||{)78&qol`;+ E0Od(aq5uE@ literal 0 HcmV?d00001 diff --git a/test/src/components/search_bar/search_bar_test.dart b/test/src/components/search_bar/search_bar_test.dart new file mode 100644 index 00000000..97ab79b0 --- /dev/null +++ b/test/src/components/search_bar/search_bar_test.dart @@ -0,0 +1,322 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.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'; +import 'search_bar_test.mocks.dart'; + +abstract class ISearchBarEvents { + // ignore: unreachable_from_main + void onChange(String? text); + + // ignore: unreachable_from_main + void onSubmit(String text); + + // ignore: unreachable_from_main + Future onSpeech(); +} + +@GenerateNiceMocks([ + MockSpec(), +]) +void main() { + late MockISearchBarEvents callbacks; + + setUpAll(() { + final testUri = Uri.parse(getCurrentPath('search_bar')); + goldenFileComparator = TolerantComparator(testUri, tolerance: 0.01); + }); + + setUp(() { + callbacks = MockISearchBarEvents(); + }); + + group('ZetaSearchBar', () { + testWidgets('renders with default parameters', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: Scaffold( + body: ZetaSearchBar(), + ), + ), + ); + + await tester.pumpAndSettle(); + expect(find.byType(TextFormField), findsOneWidget); + }); + + testWidgets('golden: renders initializes correctly', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaSearchBar(), + ), + ); + expect(find.byType(ZetaSearchBar), findsOneWidget); + + await expectLater( + find.byType(ZetaSearchBar), + matchesGoldenFile(join(getCurrentPath('search_bar'), 'search_bar_default.png')), + ); + }); + + testWidgets('golden: renders size medium correctly', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaSearchBar( + size: ZetaWidgetSize.medium, + ), + ), + ); + expect(find.byType(ZetaSearchBar), findsOneWidget); + + await expectLater( + find.byType(ZetaSearchBar), + matchesGoldenFile(join(getCurrentPath('search_bar'), 'search_bar_medium.png')), + ); + }); + + testWidgets('golden: renders size small correctly', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaSearchBar( + size: ZetaWidgetSize.small, + ), + ), + ); + expect(find.byType(ZetaSearchBar), findsOneWidget); + + await expectLater( + find.byType(ZetaSearchBar), + matchesGoldenFile(join(getCurrentPath('search_bar'), 'search_bar_small.png')), + ); + }); + + testWidgets('golden: renders shape full correctly', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaSearchBar( + shape: ZetaWidgetBorder.full, + ), + ), + ); + expect(find.byType(ZetaSearchBar), findsOneWidget); + + await expectLater( + find.byType(ZetaSearchBar), + matchesGoldenFile(join(getCurrentPath('search_bar'), 'search_bar_full.png')), + ); + }); + + testWidgets('golden: renders shape sharp correctly', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaSearchBar( + shape: ZetaWidgetBorder.sharp, + ), + ), + ); + expect(find.byType(ZetaSearchBar), findsOneWidget); + + await expectLater( + find.byType(ZetaSearchBar), + matchesGoldenFile(join(getCurrentPath('search_bar'), 'search_bar_sharp.png')), + ); + }); + + testWidgets('sets initial value correctly', (WidgetTester tester) async { + const initialValue = 'Initial value'; + + await tester.pumpWidget( + const TestApp( + home: Scaffold( + body: ZetaSearchBar(initialValue: initialValue), + ), + ), + ); + + await tester.pumpAndSettle(); + expect(find.text(initialValue), findsOneWidget); + }); + + testWidgets('sets updated initial value correctly', (WidgetTester tester) async { + const initialValue = 'Initial value'; + const updatedValue = 'Updated value'; + + await tester.pumpWidget( + const TestApp( + home: Scaffold( + body: ZetaSearchBar(initialValue: initialValue), + ), + ), + ); + + await tester.pumpAndSettle(); + expect(find.text(initialValue), findsOneWidget); + + await tester.pumpWidget( + const TestApp( + home: Scaffold( + body: ZetaSearchBar(initialValue: updatedValue), + ), + ), + ); + + await tester.pumpAndSettle(); + expect(find.text(updatedValue), findsOneWidget); + }); + + testWidgets('triggers onChanged callback when text is entered', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: Scaffold( + body: ZetaSearchBar(onChanged: callbacks.onChange), + ), + ), + ); + + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextFormField), 'New text'); + await tester.pump(); + + verify(callbacks.onChange.call('New text')).called(1); + }); + + testWidgets('triggers onSubmit callback when submit action is performed', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: Scaffold( + body: ZetaSearchBar(onSubmit: callbacks.onSubmit), + ), + ), + ); + + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextFormField), 'Submit text'); + await tester.testTextInput.receiveAction(TextInputAction.done); + await tester.pump(); + + verify(callbacks.onSubmit.call('Submit text')).called(1); + }); + + testWidgets('triggers onSpeechToText callback when microphone button is pressed', (WidgetTester tester) async { + when(callbacks.onSpeech.call()).thenAnswer((_) async => 'Speech to text result'); + + await tester.pumpWidget( + TestApp( + home: Scaffold( + body: ZetaSearchBar( + onSpeechToText: callbacks.onSpeech, + ), + ), + ), + ); + + await tester.pumpAndSettle(); + await tester.tap(find.byKey(const ValueKey('speech-to-text-btn'))); + await tester.pump(); + + verify(callbacks.onSpeech.call()).called(1); + }); + + testWidgets('does not allow text input when disabled', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: Scaffold( + body: ZetaSearchBar(disabled: true), + ), + ), + ); + + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextFormField), 'Disabled input'); + await tester.pump(); + + expect(find.text('Disabled input'), findsNothing); + }); + + testWidgets('leading icon and speech-to-text button visibility', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: Scaffold( + body: ZetaSearchBar( + showLeadingIcon: false, + 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( + home: Scaffold( + body: ZetaSearchBar(onChanged: callbacks.onChange), + ), + ), + ); + + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextFormField), 'New text'); + await tester.pump(); + + verify(callbacks.onChange.call('New text')).called(1); + + await tester.tap(find.byKey(const ValueKey('search-clear-btn'))); + await tester.pump(); + + verify(callbacks.onChange.call('')).called(1); + }); + + test('debugFillProperties sets the correct properties', () { + const size = ZetaWidgetSize.medium; + const shape = ZetaWidgetBorder.rounded; + const hint = 'Search here'; + const initialValue = 'Initial value'; + const disabled = true; + const showLeadingIcon = false; + const showSpeechToText = false; + const textInputAction = TextInputAction.search; + + final widget = ZetaSearchBar( + size: size, + shape: shape, + hint: hint, + initialValue: initialValue, + onChanged: callbacks.onChange, + onSubmit: callbacks.onSubmit, + onSpeechToText: callbacks.onSpeech, + disabled: disabled, + showLeadingIcon: showLeadingIcon, + showSpeechToText: showSpeechToText, + textInputAction: textInputAction, + ); + + final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); + widget.debugFillProperties(builder); + + expect(builder.findProperty('size'), size); + expect(builder.findProperty('shape'), shape); + expect(builder.findProperty('hint'), hint); + expect(builder.findProperty('enabled'), disabled); + expect(builder.findProperty('initialValue'), initialValue); + expect(builder.findProperty('showLeadingIcon'), showLeadingIcon); + expect(builder.findProperty('showSpeechToText'), showSpeechToText); + expect(builder.findProperty('textInputAction'), textInputAction); + expect(builder.findProperty('focusNode'), null); + expect(builder.findProperty('onChanged'), callbacks.onChange); + expect(builder.findProperty('onSpeechToText'), callbacks.onSpeech); + expect(builder.findProperty('onSubmit'), callbacks.onSubmit); + }); + }); +} diff --git a/test/src/components/search_bar/search_bar_test.mocks.dart b/test/src/components/search_bar/search_bar_test.mocks.dart new file mode 100644 index 00000000..53b0b12b --- /dev/null +++ b/test/src/components/search_bar/search_bar_test.mocks.dart @@ -0,0 +1,56 @@ +// Mocks generated by Mockito 5.4.4 from annotations +// in zeta_flutter/test/src/components/search_bar/search_bar_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; + +import 'search_bar_test.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +/// A class which mocks [ISearchBarEvents]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockISearchBarEvents extends _i1.Mock implements _i2.ISearchBarEvents { + @override + void onChange(String? text) => super.noSuchMethod( + Invocation.method( + #onChange, + [text], + ), + returnValueForMissingStub: null, + ); + + @override + void onSubmit(String? text) => super.noSuchMethod( + Invocation.method( + #onSubmit, + [text], + ), + returnValueForMissingStub: null, + ); + + @override + _i3.Future onSpeech() => (super.noSuchMethod( + Invocation.method( + #onSpeech, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); +} diff --git a/test/src/utils/extensions_test.mocks.dart b/test/src/utils/extensions_test.mocks.dart index 15ccab50..c3b1cbd4 100644 --- a/test/src/utils/extensions_test.mocks.dart +++ b/test/src/utils/extensions_test.mocks.dart @@ -1495,6 +1495,13 @@ class MockZeta extends _i1.Mock implements _i10.Zeta { ), ) as _i6.ZetaThemeData); + @override + bool get rounded => (super.noSuchMethod( + Invocation.getter(#rounded), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); + @override _i6.ZetaColors get colors => (super.noSuchMethod( Invocation.getter(#colors), diff --git a/test/test_utils/utils.dart b/test/test_utils/utils.dart index 21ea3356..1afb1742 100644 --- a/test/test_utils/utils.dart +++ b/test/test_utils/utils.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; import 'package:path/path.dart'; @@ -9,6 +10,10 @@ String getCurrentPath(String component, {String type = 'components'}) { extension Util on DiagnosticPropertiesBuilder { dynamic finder(String finder) { - return properties.where((p) => p.name == finder).map((p) => p.toDescription()).first; + return properties.where((p) => p.name == finder).map((p) => p.toDescription()).firstOrNull; + } + + dynamic findProperty(String propertyName) { + return properties.firstWhereOrNull((p) => p.name == propertyName)?.value; } }