diff --git a/packages/graphql_flutter/lib/src/widgets/query.dart b/packages/graphql_flutter/lib/src/widgets/query.dart index 67eda989..01beeae8 100644 --- a/packages/graphql_flutter/lib/src/widgets/query.dart +++ b/packages/graphql_flutter/lib/src/widgets/query.dart @@ -72,7 +72,13 @@ class QueryState extends State { void didUpdateWidget(Query oldWidget) { super.didUpdateWidget(oldWidget); - if (!observableQuery.options.areEqualTo(_options)) { + final GraphQLClient client = GraphQLProvider.of(context).value; + + final optionsWithOverrides = _options; + optionsWithOverrides.policies = client.defaultPolicies.watchQuery + .withOverrides(optionsWithOverrides.policies); + + if (!observableQuery.options.areEqualTo(optionsWithOverrides)) { _initQuery(); } } diff --git a/packages/graphql_flutter/test/widgets/query_test.dart b/packages/graphql_flutter/test/widgets/query_test.dart new file mode 100644 index 00000000..a727dc1c --- /dev/null +++ b/packages/graphql_flutter/test/widgets/query_test.dart @@ -0,0 +1,227 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; +import 'package:graphql_flutter/src/widgets/query.dart'; +import 'package:http/http.dart'; +import 'package:mockito/mockito.dart'; + +class MockHttpClient extends Mock implements Client {} + +final query = gql(""" + query Foo { + foo + } +"""); + +class Page extends StatefulWidget { + final Map variables; + final FetchPolicy fetchPolicy; + final ErrorPolicy errorPolicy; + + Page({ + Key key, + this.variables, + this.fetchPolicy, + this.errorPolicy, + }): super(key: key); + + @override + State createState() => PageState(); +} + +class PageState extends State { + Map variables; + FetchPolicy fetchPolicy; + ErrorPolicy errorPolicy; + + @override + void initState() { + super.initState(); + variables = widget.variables; + fetchPolicy = widget.fetchPolicy; + errorPolicy = widget.errorPolicy; + } + + setVariables(Map newVariables) { + setState(() { + variables = newVariables; + }); + } + + setFetchPolicy(FetchPolicy newFetchPolicy) { + setState(() { + fetchPolicy = newFetchPolicy; + }); + } + + setErrorPolicy(ErrorPolicy newErrorPolicy) { + setState(() { + errorPolicy = newErrorPolicy; + }); + } + + @override + Widget build(BuildContext context) { + return Query( + options: QueryOptions( + documentNode: query, + variables: variables, + fetchPolicy: fetchPolicy, + errorPolicy: errorPolicy, + ), + builder: (QueryResult result, { + Refetch refetch, + FetchMore fetchMore + }) => Container(), + ); + } +} + +void main() { + group('Query', () { + MockHttpClient mockHttpClient; + HttpLink httpLink; + ValueNotifier client; + + setUp(() async { + mockHttpClient = MockHttpClient(); + httpLink = HttpLink( + uri: 'https://unused/graphql', + httpClient: mockHttpClient, + ); + client = ValueNotifier( + GraphQLClient( + cache: InMemoryCache(storagePrefix: 'test'), + link: httpLink, + ), + ); + }); + + testWidgets('does not issue network request on same options', + (WidgetTester tester) async { + final page = Page( + variables: { + 'foo': 1, + }, + fetchPolicy: FetchPolicy.networkOnly, + errorPolicy: ErrorPolicy.ignore, + ); + + await tester.pumpWidget(GraphQLProvider( + client: client, + child: page, + )); + + verify(mockHttpClient.send(any)).called(1); + + tester.state(find.byWidget(page)) + ..setVariables({'foo': 1}) + ..setFetchPolicy(FetchPolicy.networkOnly) + ..setErrorPolicy(ErrorPolicy.ignore); + await tester.pump(); + verifyNoMoreInteractions(mockHttpClient); + }); + + testWidgets('does not issue network request when policies stays null', + (WidgetTester tester) async { + final page = Page( + variables: { + 'foo': 1, + }, + ); + + await tester.pumpWidget(GraphQLProvider( + client: client, + child: page, + )); + + verify(mockHttpClient.send(any)).called(1); + + tester.state(find.byWidget(page)) + ..setFetchPolicy(null) + ..setErrorPolicy(null); + await tester.pump(); + verifyNoMoreInteractions(mockHttpClient); + }); + + testWidgets('issues a new network request when variables change', + (WidgetTester tester) async { + final page = Page( + variables: { + 'foo': 1, + }, + ); + + await tester.pumpWidget(GraphQLProvider( + client: client, + child: page, + )); + + verify(mockHttpClient.send(any)).called(1); + + tester.state(find.byWidget(page)) + .setVariables({'foo': 2}); + await tester.pump(); + verify(mockHttpClient.send(any)).called(1); + }); + + testWidgets('issues a new network request when fetch policy changes', + (WidgetTester tester) async { + final page = Page( + fetchPolicy: FetchPolicy.networkOnly, + ); + + await tester.pumpWidget(GraphQLProvider( + client: client, + child: page, + )); + + verify(mockHttpClient.send(any)).called(1); + + tester.state(find.byWidget(page)) + .setFetchPolicy(FetchPolicy.cacheFirst); + await tester.pump(); + verify(mockHttpClient.send(any)).called(1); + }); + + testWidgets('issues a new network request when error policy changes', + (WidgetTester tester) async { + final page = Page( + errorPolicy: ErrorPolicy.all, + ); + + await tester.pumpWidget(GraphQLProvider( + client: client, + child: page, + )); + + verify(mockHttpClient.send(any)).called(1); + + tester.state(find.byWidget(page)) + .setErrorPolicy(ErrorPolicy.none); + await tester.pump(); + verify(mockHttpClient.send(any)).called(1); + }); + + testWidgets('does not issues new network request when policies are effectively unchanged', + (WidgetTester tester) async { + final page = Page( + fetchPolicy: FetchPolicy.cacheAndNetwork, + errorPolicy: null, + ); + + await tester.pumpWidget(GraphQLProvider( + client: client, + child: page, + )); + + verify(mockHttpClient.send(any)).called(1); + + tester.state(find.byWidget(page)) + ..setFetchPolicy(null) + ..setErrorPolicy(ErrorPolicy.none); + await tester.pump(); + verifyNoMoreInteractions(mockHttpClient); + }); + }); +}