Skip to content

Instantly share code, notes, and snippets.

@tomaszpolanski
Last active March 25, 2025 14:04
Show Gist options
  • Save tomaszpolanski/8c43760bf73cfd06c471c8dc5406b678 to your computer and use it in GitHub Desktop.
Save tomaszpolanski/8c43760bf73cfd06c471c8dc5406b678 to your computer and use it in GitHub Desktop.
ArrangeBuilder with widget tests
/// 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();
}
/// 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 {}
/// 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');
}
},
);
}
/// 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