Directories - ripplearc/construculator-app GitHub Wiki
This document outlines our testing structure and conventions. Following these guidelines ensures your tests are picked up by CI/CD pipelines and local scripts.
All tests must be placed under either test/features/ or test/libraries/ following this structure:
test/
βββ features/
β βββ <feature_name>/
β βββ units/ # Unit tests (blocs, providers, etc.)
β βββ widgets/ # Widget tests
β βββ screenshots/ # Golden/screenshot tests
β βββ mutations/ # Mutation test configs (.xml)
βββ libraries/
βββ <library_name>/
βββ units/ # Unit tests
βββ mutations/ # Mutation test configs (.xml)
test/features/auth/widgets/widgets/auth_footer_test.dart
test/features/auth/screenshots/auth_header_screenshot_test.dart
test/features/auth/mutations/create_account_bloc.xml
test/libraries/config/units/app_config_test.dart
test/libraries/supabase/mutations/fake_supabase_wrapper.xml
Rule: Mirror your implementation structure as much as possible. If your feature has data/, domain/, and presentation/ layers, your tests should follow the same structure.
units/
βββ data/
β βββ data_source/ # Remote/local data source tests
β βββ models/ # DTO/model tests
β βββ repositories/ # Repository implementation tests
βββ domain/
β βββ entities/ # Entity tests
β βββ usecases/ # Use case tests
β βββ validation/ # Domain validation logic tests
βββ presentation/ # Non-widget presentation logic
βββ blocs/ # Bloc/Cubit tests
|__ fakes/ # Fake implementations for testing
Estimations Feature (Clean Architecture):
test/features/estimations/units/
βββ blocs/
β βββ add_cost_estimation_bloc_test.dart
β βββ cost_estimation_list_bloc_test.dart
β βββ delete_cost_estimation_bloc_test.dart
βββ data/
β βββ data_source/
β β βββ remote_cost_estimation_data_source_test.dart
β βββ models/
β β βββ cost_estimate_dto_test.dart
β βββ repositories/
β βββ cost_estimation_repository_impl_test.dart
βββ domain/
β βββ entities/
β βββ usecases/
β βββ add_cost_estimation_usecase_test.dart
βββ fakes/
βββ fake_cost_estimation_repository_test.dart
This mirrors:
lib/features/estimation/
βββ data/
β βββ data_source/
β βββ models/
β βββ repositories/
βββ domain/
β βββ entities/
β βββ usecases/
βββ presentation/
βββ bloc/
Project Feature (presentation layer):
test/features/project/units/
βββ blocs/
β βββ get_project_bloc_test.dart
βββ presentation/
βββ project_ui_provider_impl_test.dart
Auth Library (library example):
test/libraries/auth/units/
βββ data/
β βββ models/
β βββ auth_user_test.dart
β βββ auth_credential_test.dart
βββ domain/
β βββ validation/
β βββ auth_validation_test.dart
βββ repositories/
β βββ supabase_auth_repository_test.dart
βββ fakes/
β βββ fake_auth_manager_test.dart
β βββ fake_auth_repository_test.dart
β βββ fake_auth_notifier_test.dart
βββ auth_manager_test.dart
βββ auth_notifier_test.dart
Key Principle: If you're testing lib/features/estimation/data/repositories/foo.dart, the test goes in test/features/estimations/units/data/repositories/foo_test.dart.
Widget tests are organized by widget type.
widgets/
βββ pages/ # Full page widgets
βββ widgets/ # Reusable component widgets
Auth Feature:
test/features/auth/widgets/
βββ pages/
β βββ create_account_page_test.dart
β βββ enter_password_page_test.dart
β βββ forgot_password_page_test.dart
β βββ login_with_email_page_test.dart
β βββ register_with_email_page_test.dart
β βββ set_new_password_page_test.dart
βββ widgets/
βββ auth_footer_test.dart
βββ auth_header_test.dart
βββ auth_provider_buttons_test.dart
βββ error_widget_builder_test.dart
βββ otp_verification_sheet_test.dart
βββ terms_and_conditions_section_test.dart
This tests widgets in:
lib/features/auth/presentation/
βββ pages/ # Page-level widgets
βββ widgets/ # Smaller reusable widgets
Screenshot tests are flat - no subfolders. All golden tests for a feature live directly in the screenshots directory.
test/features/auth/screenshots/
βββ auth_footer_screenshot_test.dart
βββ auth_header_screenshot_test.dart
βββ auth_provider_buttons_screenshot_test.dart
βββ error_widget_builder_screenshot_test.dart
βββ forgot_password_header_screenshot_test.dart
βββ otp_verification_sheet_screenshot_test.dart
βββ terms_and_conditions_section_screenshot_test.dart
Golden files are stored alongside tests:
test/features/project/screenshots/
βββ goldens/
β βββ project_header_app_bar/
β βββ 390.0x56.0/
β βββ project_header_app_bar_long_name.png
β βββ project_header_app_bar_no_avatar.png
β βββ project_header_app_bar_normal.png
βββ project_header_app_bar_screenshot_test.dart
Mutation configs are flat - no subfolders. All .xml configs live directly in the mutations directory.
test/features/auth/mutations/
βββ create_account_bloc.xml
βββ create_account_page_mutations.xml
βββ enter_password_bloc.xml
βββ enter_password_page_mutations.xml
βββ forgot_password_bloc.xml
βββ login_with_email_bloc.xml
βββ ...
Why flat? Mutation testing runs on specific files, and we don't need complex organization since configs are named descriptively.
Note: Test files usually shoulld follow Flutter conventions:
- Units and widgets: Test file name = source file name +
_test.dart - Example:
auth_footer.dartβauth_footer_test.dart - Screenshots: Test file name = source file name +
_screenshot_test.dart - Example:
auth_footer.dartβauth_footer_screenshot_test.dart - Mutation configs: Test file name = source file name +
_mutations.xml - Example:
auth_footer.dartβauth_footer_mutations.xml
Our scripts and CI/CD (scripts/run_check.sh and codemagic.yaml) are configured to find tests in these specific locations:
# Pre-check runs only changed tests
test/features/**/units/*.dart
test/features/**/widgets/*.dart
test/libraries/**/units/*.dart
# Comprehensive check runs all tests
test/features/**/screenshots/*.dart
test/features/**/mutations/*.xml
test/libraries/**/mutations/*.xml- Business logic and state management
- Pure Dart logic tests
- Common subfolders: data/, domain/, presentation/, blocs/, fakes/, helpers/
- Key Principle: Mirror your implementation structure
- Widget behavior and interaction
- Widget state changes
- Basic UI logic without golden comparison
- Subfolders: pages/ and widgets/
- Golden file comparisons
- Visual regression testing
- Use
--update-goldensflag to update reference images - Flat structure (no subfolders)
- Shows golden file organization
Important Notes:
- Screenshot tests do not contribute to code coverage metrics
- Test specific UI states and variations (e.g., loading, error, empty states)
- Avoid full-page screenshotsβisolate the critical user journey (CUJ) of individual widgets
- Don't overtest, one screenshot per widget state + some edge cases is sufficient (no need for multiple redundant tests)
- XML config files for mutation testing
- Tests run only when mutation configs change
- Validates test suite quality
- Flat structure with descriptive names
- Target: 95% code coverage (
ARC_CODE_COVERAGE_TARGET=95) - Excludes generated files (
*.g.dart,*.freezed.dart,l10n/**) - Both pre-check and comprehensive-check enforce this threshold
- Calculated based on unit and widget tests
# Pre-check (changed files only)
./scripts/run_check.sh --pre
# Comprehensive check (all tests + builds)
./scripts/run_check.sh --comp
# Both checks
./scripts/run_check.sh --all
# Mutation tests only
./scripts/run_check.sh --mutations
# Specify target branch
./scripts/run_check.sh --pre --target develop