blooming_flutter_test 0.2.4
blooming_flutter_test: ^0.2.4 copied to clipboard
Unified Flutter widget testing harness and state mocking system for the Blooming Flutter reactive framework.
blooming_flutter_test #
Unified Flutter testing harness and hierarchical widget state mocking system for the blooming_flutter reactive UI framework.
Features #
- Full
blooming_testRe-export: Importblooming_flutter_testto access both pure Dart unit testing utilities (bloomTest,isDormant,hasGlitchFreedom,isData,isEmptyState,isErrorState) and Flutter widget testing APIs in a single package. - Hierarchical Widget Mocking (
BloomTestScope&BloomOverride): Declaratively inject mock nodes, static constants, empty placeholders, or simulated errors into the widget hierarchy viaBloomProvider. - Declarative Widget Runner (
bloomWidgetTest): Run widget tests with automatic scoped override injection and clean environment setup. - Convenient Scoped Pump (
pumpScopedWidget): Direct extension onWidgetTesterto pump any UI subtree pre-configured with active overrides.
Installation #
Add blooming_flutter_test to your dev_dependencies in pubspec.yaml:
dev_dependencies:
flutter_test:
sdk: flutter
blooming_flutter_test: ^0.2.4
Usage #
1. Unified Imports #
package:blooming_flutter_test/blooming_flutter_test.dart exposes everything you need:
import 'package:flutter/material.dart';
import 'package:blooming_flutter/blooming_flutter.dart';
import 'package:blooming_flutter_test/blooming_flutter_test.dart';
2. Declarative Widget Testing with bloomWidgetTest #
void main() {
final counterBloom = blooming(0).bloom;
bloomWidgetTest(
'renders counter with injected override value',
overrides: [
counterBloom.overrideWithValue(42),
],
test: (tester) async {
await tester.pumpScopedWidget(
MaterialApp(
home: composed((context, via) => Text('Count: ${via.of<int>(context)}')),
),
);
expect(find.text('Count: 42'), findsOneWidget);
},
);
}
3. Tree-Level State Overrides with BloomTestScope #
Override dependencies with custom mock nodes, errors, or empty states without touching production business logic:
testWidgets('renders fallback when service emits error', (tester) async {
final userBloom = blooming<String>('Alice').bloom;
await tester.pumpWidget(
MaterialApp(
home: BloomTestScope(
overrides: [
userBloom.overrideWithError(Exception('No Internet')),
],
child: composed((context, via) {
final state = via.state(context.bloomOf<String>());
return Text(state.hasError ? 'Offline' : 'User: ${state.data}');
}),
),
),
);
expect(find.text('Offline'), findsOneWidget);
});
4. Dynamic Reactive Mutations in Widget Tests #
Verify 2-Phase LPDAG widget rebuild cycles on user interaction or state mutation:
bloomWidgetTest(
'increments display when controller mutates',
test: (tester) async {
final counter = blooming(0);
await tester.pumpScopedWidget(
MaterialApp(
home: BloomProvider<int>(
bloom: counter.bloom,
child: composed((context, via) => Text('Count: ${via.of<int>(context)}')),
),
),
);
expect(find.text('Count: 0'), findsOneWidget);
// Mutate state
counter.data = 1;
await tester.pump();
expect(find.text('Count: 1'), findsOneWidget);
},
);
5. Running Pure Unit Tests #
Because blooming_flutter_test re-exports blooming_test, your unit tests and widget tests share the same toolset:
bloomTest<BloomController<int>>(
'pure business logic unit test',
build: () => blooming(10),
target: (ctrl) => ctrl.bloom,
act: (ctrl) => ctrl.data = 20,
expect: () => [10, 20],
);
Complete Executable Example #
Check out the full, runnable widget showcase at example/blooming_flutter_test_example.dart. Run it directly via:
flutter test example/blooming_flutter_test_example.dart
License #
Apache License 2.0. Copyright 2023-2026 Youngjune Jeon.