I'm trying to create widget tests for a flutter application using GraphQL. What I want to do is to test the behaviour of the app which depends on the result of a GraphQL Mutation on a user action.
This is a very simple example of the app:
class FirstScreen extends StatelessWidget {
@override
Widget return Container(
child: Mutation(
options: myMutationOptions,
onCompleted: (dynamic result) {
final bool myBool = result['bool'] as bool;
if (myBool) {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => SecondScreen()));
} else {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ThirdScreen()));
}
},
builder: (RunMutation runMutation, QueryResult queryResult) {
return FlatButton(
child: Text('Button'),
onPressed: () async {
await runMutation(myParameters).networkResult;
},
);
},
),
);
}
What I would like to do is to mock the result of the mutation so in my widget tests, I can test that the button redirects to the SecondScreen
or ThirdScreen
depending of the result myBool
.
How can I do that ?
I finally managed to successfully mock a GraphQL Mutation. Here is how I did it, it is inspired from @Gpack's comment but I had to add some modifications and details to it.
To make it easy to use I created a wrapper widget GraphQLMutationMocker
:
class MockClient extends Mock implements Client {
MockClient({
this.mockedResult,
this.mockedStatus = 200,
});
final Map<String, dynamic> mockedResult;
final int mockedStatus;
@override
Future<StreamedResponse> send(BaseRequest request) {
return Future<StreamedResponse>.value(
StreamedResponse(
Stream.value(utf8.encode(jsonEncode(mockedResult))),
mockedStatus,
),
);
}
}
class GraphQLMutationMocker extends StatelessWidget {
const GraphQLMutationMocker({
@required this.child,
this.mockedResult = const {},
this.mockedStatus = 200,
this.url = 'http://url',
this.storagePrefix = 'test',
});
final Widget child;
final Map<String, dynamic> mockedResult;
final int mockedStatus;
final String url;
final String storagePrefix;
@override
Widget build(BuildContext context) {
final mockClient = MockClient(
mockedResult: mockedResult,
mockedStatus: mockedStatus,
);
final httpLink = HttpLink(
uri: url,
httpClient: mockClient,
);
final graphQLClient = ValueNotifier(
GraphQLClient(
cache: InMemoryCache(storagePrefix: storagePrefix),
link: httpLink,
),
);
return GraphQLProvider(
client: graphQLClient,
child: child,
);
}
}
Then it was pretty easy to write the tests
group('Test mutation', () {
testWidgets('It should redirect to SecondScreen', (WidgetTester tester) async {
await tester.pumpWidget(GraphQLMutationMocker(
mockedResult: <String, dynamic>{
'data': {
'bool': true,
},
},
child: FirstScreen(),
));
// Click on button
await tester.tap(find.text('Button'));
await tester.pumpAndSettle();
// Check I'm on the right screen
expect(find.byType(SecondScreen), findsOneWidget);
expect(find.byType(ThirdScreen), findsNothing);
});
testWidgets('It should redirect to ThirdScreen', (WidgetTester tester) async {
await tester.pumpWidget(GraphQLMutationMocker(
mockedResult: <String, dynamic>{
'data': {
'bool': false,
},
},
child: FirstScreen(),
));
// Click on button
await tester.tap(find.text('Button'));
await tester.pumpAndSettle();
// Check I'm on the right screen
expect(find.byType(SecondScreen), findsNothing);
expect(find.byType(ThirdScreen), findsOneWidget);
});
})