Last active
March 25, 2025 14:04
-
-
Save tomaszpolanski/8c43760bf73cfd06c471c8dc5406b678 to your computer and use it in GitHub Desktop.
ArrangeBuilder with widget tests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Please first check out how ArrangeBuilder should be used in a simpler example: | |
/// https://gist.github.com/tomaszpolanski/abd4725d4e07ba637d5540b5fe10aa1e | |
abstract class ExampleUsecase { | |
Future<String> fetchMessage(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Please first check out how ArrangeBuilder should be used in a simpler example: | |
/// https://gist.github.com/tomaszpolanski/abd4725d4e07ba637d5540b5fe10aa1e | |
import 'package:flutter/cupertino.dart'; | |
import 'example.dart'; | |
import 'package:mocktail/mocktail.dart'; | |
/// An example of a mixing that needs to be implemented once and can be used | |
/// in multiple tests without doing `when(() => ...)` in every test file | |
mixin ExampleUsecaseMixin { | |
ExampleUsecase exampleUsecase = _MockExampleUsecase(); | |
/// Function that prepares the mixin to be in a usable state. | |
/// This would be mixin's constructor if mixins would support constructor | |
void arrangeExampleUsecase() { | |
withExampleUsecaseFetchMessage(); | |
} | |
void withExampleUsecaseFetchMessage([ValueGetter<Future<String>>? message]) { | |
when(() => exampleUsecase.fetchMessage()).thenAnswer( | |
(_) => message != null ? message.call() : Future.value('empty')); | |
} | |
} | |
class _MockExampleUsecase extends Mock implements ExampleUsecase {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Please first check out how ArrangeBuilder should be used in a simpler example: | |
/// https://gist.github.com/tomaszpolanski/abd4725d4e07ba637d5540b5fe10aa1e | |
import 'package:flutter/widgets.dart'; | |
import 'example.dart'; | |
class Example extends StatefulWidget { | |
const Example({ | |
super.key, | |
required this.usecase, | |
}); | |
/// This usually would come as injection of some sort, not a parameter for a widget | |
final ExampleUsecase usecase; | |
@override | |
State<Example> createState() => _ExampleState(); | |
} | |
class _ExampleState extends State<Example> { | |
late final _fetch = widget.usecase.fetchMessage(); | |
@override | |
Widget build(BuildContext context) => FutureBuilder( | |
future: _fetch, | |
builder: (_, snapshot) { | |
if (snapshot.hasError) { | |
return const Text('Something went wrong'); | |
} else if (snapshot.hasData) { | |
return const Text('some message'); | |
} else { | |
return const Text('Loading'); | |
} | |
}, | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Please first check out how ArrangeBuilder should be used in a simpler example: | |
/// https://gist.github.com/tomaszpolanski/abd4725d4e07ba637d5540b5fe10aa1e | |
import 'dart:async'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_test/flutter_test.dart'; | |
import 'example_usecase_mixin.dart'; | |
import 'example_widget.dart'; | |
late _ArrangeBuilder _builder; | |
void main() { | |
setUp(() { | |
_builder = _ArrangeBuilder(); | |
}); | |
testWidgets('when loaded then show the message', (tester) async { | |
const expected = 'some message'; | |
_builder.withExampleUsecaseFetchMessage(() => Future.value(expected)); | |
await tester.pumpTested(); | |
await tester.pumpAndSettle(); | |
expect(find.text(expected), findsOneWidget); | |
}); | |
testWidgets('when failed then show error message', (tester) async { | |
final message = () => Future<String>.error(Exception('error')); | |
_builder.withExampleUsecaseFetchMessage(message); | |
await tester.pumpTested(); | |
await tester.pumpAndSettle(); | |
expect(find.text('Something went wrong'), findsOneWidget); | |
}); | |
testWidgets('when not completed then show loading message', (tester) async { | |
final message = () => Completer<String>().future; | |
_builder.withExampleUsecaseFetchMessage(message); | |
await tester.pumpTested(); | |
await tester.pumpAndSettle(); | |
expect(find.text('Loading'), findsOneWidget); | |
}); | |
} | |
extension on WidgetTester { | |
Future<void> pumpTested() => pumpWidget( | |
Directionality( | |
textDirection: TextDirection.ltr, | |
child: Example(usecase: _builder.exampleUsecase), | |
), | |
); | |
} | |
/// ArrangeBuilder can use multiple mixins | |
class _ArrangeBuilder with ExampleUsecaseMixin { | |
_ArrangeBuilder() { | |
arrangeExampleUsecase(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment