diff --git a/docs/NFRs.md b/docs/NFRs.md index 1b89a97..c7e77e3 100644 --- a/docs/NFRs.md +++ b/docs/NFRs.md @@ -1,4 +1,5 @@ # Non-Functional Requirements -* Package structure - * plz follow official [Package structure](https://docs.flutter.dev/app-architecture/case-study#package-structure) with a slight modification, put each `/`s in `features/` sub-directory under `ui/`. +* support multiple platforms (windows, linux, android, web) +* only FOSS libs can use +* recommend no more than 300 lines of code per file diff --git a/docs/meta-arch.md b/docs/meta-arch.md index 996293f..c4db672 100644 --- a/docs/meta-arch.md +++ b/docs/meta-arch.md @@ -2,3 +2,10 @@ * [MVVM](https://docs.flutter.dev/app-architecture/guide) +## Package structure + +The repo structure follows official [Package structure](https://docs.flutter.dev/app-architecture/case-study#package-structure) with slight modifications. + +* put each `/`s in `features/` sub-directory under `ui/`. +* `test/features/` contains BDD unit tests for each feature. It focuses on pure logic, therefore will not access `View` but `ViewModel` and `Model`. +* `test/widget/` contains UI widget(component) tests which focus on `View` of MVVM only. diff --git a/test/features/app_preferences.feature b/test/features/app_preferences.feature index e843eda..11de0f9 100644 --- a/test/features/app_preferences.feature +++ b/test/features/app_preferences.feature @@ -4,7 +4,7 @@ Feature: App preferences Given the settings screen is open When the user selects the "" theme Then the app UI updates to use the "" theme - And the preference {theme} is saved as {""} + And the preference {'theme'} is saved as Examples: | theme | @@ -16,7 +16,7 @@ Feature: App preferences Given the settings screen is open When the user selects a supported language "" Then all visible texts are displayed in "" - And the preference {language} is saved as {""} + And the preference {'language'} is saved as Examples: | language | diff --git a/test/features/internationalizing.feature b/test/features/internationalizing.feature index 18f1d13..759a4ab 100644 --- a/test/features/internationalizing.feature +++ b/test/features/internationalizing.feature @@ -10,4 +10,7 @@ Feature: internationalizing Then the language falls back to the device locale Scenario: Supported languages are available - Then the app supports languages {en, zh-TW, es} + Then the app supports languages + | 'en' | + | 'zh-TW' | + | 'es' | diff --git a/test/features/step/a_signature_image_is_selected.dart b/test/features/step/a_signature_image_is_selected.dart index e234b2c..99380b4 100644 --- a/test/features/step/a_signature_image_is_selected.dart +++ b/test/features/step/a_signature_image_is_selected.dart @@ -17,4 +17,11 @@ Future aSignatureImageIsSelected(WidgetTester tester) async { .setImageBytes(Uint8List.fromList([1, 2, 3])); // Allow provider scheduler to process queued updates fully await tester.pumpAndSettle(); + // Extra pump with a non-zero duration to flush zero-delay timers + await tester.pump(const Duration(milliseconds: 1)); + // Teardown to avoid pending timers from Riverpod's scheduler + addTearDown(() { + TestWorld.container?.dispose(); + TestWorld.container = null; + }); } diff --git a/test/features/step/the_app_supports_languages.dart b/test/features/step/the_app_supports_languages.dart index 1ba9e1e..3bfd9fa 100644 --- a/test/features/step/the_app_supports_languages.dart +++ b/test/features/step/the_app_supports_languages.dart @@ -1,17 +1,33 @@ +import 'package:bdd_widget_test/data_table.dart' as bdd; import 'package:flutter_test/flutter_test.dart'; -/// Usage: the app supports languages {en, zh-TW, es} +/// Usage: the app supports languages +/// | 'en' | +/// | 'zh-TW' | +/// | 'es' | Future theAppSupportsLanguages( WidgetTester tester, - String languages, + dynamic languages, ) async { - // Normalize the example token string "{en, zh-TW, es}" into a set - final raw = languages.trim(); - final inner = - raw.startsWith('{') && raw.endsWith('}') - ? raw.substring(1, raw.length - 1) - : raw; - final expected = inner.split(',').map((s) => s.trim()).toSet(); + // Accept either a DataTable from bdd_widget_test or a string like "{en, zh-TW, es}" + final Set expected; + if (languages is bdd.DataTable) { + final lists = languages.asLists(); + // Flatten ignoring header rows if any + final items = lists + .skipWhile((row) => row.any((e) => e.toString().contains('artist') || e.toString().contains('name'))) + .expand((row) => row) + .map((e) => e.toString().replaceAll("'", '').trim()) + .where((e) => e.isNotEmpty) + .toSet(); + expected = items; + } else { + final raw = languages.toString().trim(); + final inner = raw.startsWith('{') && raw.endsWith('}') + ? raw.substring(1, raw.length - 1) + : raw; + expected = inner.split(',').map((s) => s.trim().replaceAll("'", '')).toSet(); + } // Keep this in sync with the app's supported locales const actual = {'en', 'zh-TW', 'es'}; diff --git a/test/features/step/the_preference_is_saved_as.dart b/test/features/step/the_preference_is_saved_as.dart index 4fc6a36..ff1a2e6 100644 --- a/test/features/step/the_preference_is_saved_as.dart +++ b/test/features/step/the_preference_is_saved_as.dart @@ -1,5 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; import '_world.dart'; +// Re-export tokens so tests that import this step have access to token symbols +export '_tokens.dart'; /// Usage: the preference {language} is saved as {""} Future thePreferenceIsSavedAs(