Skip to content

Commit 4a03405

Browse files
authored
chore(api): added unit test for GraphQL custom types (#4892)
1 parent 96e646d commit 4a03405

File tree

6 files changed

+454
-105
lines changed

6 files changed

+454
-105
lines changed

packages/amplify_datastore/example/lib/models/CustomTypeWithAppsyncScalarTypes.dart

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919

2020
// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, override_on_non_overriding_member, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously
2121

22-
import 'ModelProvider.dart';
2322
import 'package:amplify_core/amplify_core.dart' as amplify_core;
2423
import 'package:collection/collection.dart';
2524

25+
import 'ModelProvider.dart';
26+
2627
/** This is an auto generated class representing the CustomTypeWithAppsyncScalarTypes type in your schema. */
2728
class CustomTypeWithAppsyncScalarTypes {
2829
final String? _stringValue;
@@ -738,14 +739,17 @@ class CustomTypeWithAppsyncScalarTypes {
738739
.toList()
739740
: null,
740741
_customTypeValue = json['customTypeValue'] != null
741-
? SimpleCustomType.fromJson(
742-
new Map<String, dynamic>.from(json['customTypeValue']))
742+
? json['customTypeValue']['serializedData'] != null
743+
? SimpleCustomType.fromJson(new Map<String, dynamic>.from(
744+
json['customTypeValue']['serializedData']))
745+
: SimpleCustomType.fromJson(
746+
new Map<String, dynamic>.from(json['customTypeValue']))
743747
: null,
744748
_listOfCustomTypeValue = json['listOfCustomTypeValue'] is List
745749
? (json['listOfCustomTypeValue'] as List)
746750
.where((e) => e != null)
747-
.map((e) =>
748-
SimpleCustomType.fromJson(new Map<String, dynamic>.from(e)))
751+
.map((e) => SimpleCustomType.fromJson(
752+
new Map<String, dynamic>.from(e['serializedData'] ?? e)))
749753
.toList()
750754
: null;
751755

packages/amplify_datastore/example/lib/models/ModelWithCustomType.dart

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919

2020
// ignore_for_file: public_member_api_docs, annotate_overrides, dead_code, dead_codepublic_member_api_docs, depend_on_referenced_packages, file_names, library_private_types_in_public_api, no_leading_underscores_for_library_prefixes, no_leading_underscores_for_local_identifiers, non_constant_identifier_names, null_check_on_nullable_type_parameter, override_on_non_overriding_member, prefer_adjacent_string_concatenation, prefer_const_constructors, prefer_if_null_operators, prefer_interpolation_to_compose_strings, slash_for_doc_comments, sort_child_properties_last, unnecessary_const, unnecessary_constructor_name, unnecessary_late, unnecessary_new, unnecessary_null_aware_assignments, unnecessary_nullable_for_final_variable_declarations, unnecessary_string_interpolations, use_build_context_synchronously
2121

22-
import 'ModelProvider.dart';
2322
import 'package:amplify_core/amplify_core.dart' as amplify_core;
2423
import 'package:collection/collection.dart';
2524

25+
import 'ModelProvider.dart';
26+
2627
/** This is an auto generated class representing the ModelWithCustomType type in your schema. */
2728
class ModelWithCustomType extends amplify_core.Model {
2829
static const classType = const _ModelWithCustomTypeModelType();
@@ -152,14 +153,18 @@ class ModelWithCustomType extends amplify_core.Model {
152153
ModelWithCustomType.fromJson(Map<String, dynamic> json)
153154
: id = json['id'],
154155
_customTypeValue = json['customTypeValue'] != null
155-
? CustomTypeWithAppsyncScalarTypes.fromJson(
156-
new Map<String, dynamic>.from(json['customTypeValue']))
156+
? json['customTypeValue']['serializedData'] != null
157+
? CustomTypeWithAppsyncScalarTypes.fromJson(
158+
new Map<String, dynamic>.from(
159+
json['customTypeValue']['serializedData']))
160+
: CustomTypeWithAppsyncScalarTypes.fromJson(
161+
new Map<String, dynamic>.from(json['customTypeValue']))
157162
: null,
158163
_listOfCustomTypeValue = json['listOfCustomTypeValue'] is List
159164
? (json['listOfCustomTypeValue'] as List)
160165
.where((e) => e != null)
161166
.map((e) => CustomTypeWithAppsyncScalarTypes.fromJson(
162-
new Map<String, dynamic>.from(e)))
167+
new Map<String, dynamic>.from(e['serializedData'] ?? e)))
163168
.toList()
164169
: null,
165170
_createdAt = json['createdAt'] != null

packages/api/amplify_api_dart/test/graphql_test.dart

Lines changed: 75 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -14,92 +14,21 @@ import 'package:aws_common/testing.dart';
1414
import 'package:collection/collection.dart';
1515
import 'package:test/test.dart';
1616

17+
import 'mocks.dart';
1718
import 'test_data/fake_amplify_configuration.dart';
1819
import 'test_models/ModelProvider.dart';
1920
import 'util.dart';
2021

2122
final _deepEquals = const DeepCollectionEquality().equals;
2223

23-
// Success Mocks
24-
const _expectedQuerySuccessResponseBody = {
25-
'data': {
26-
'listBlogs': {
27-
'items': [
28-
{
29-
'id': 'TEST_ID',
30-
'name': 'Test App Blog',
31-
'createdAt': '2022-06-28T17:36:52.460Z',
32-
}
33-
],
34-
},
35-
},
36-
};
37-
38-
final _modelQueryId = uuid();
39-
final _expectedModelQueryResult = {
40-
'data': {
41-
'getBlog': {
42-
'createdAt': '2021-07-21T22:23:33.707Z',
43-
'id': _modelQueryId,
44-
'name': 'Test App Blog',
45-
},
46-
},
47-
};
48-
const _expectedMutateSuccessResponseBody = {
49-
'data': {
50-
'createBlog': {
51-
'id': 'TEST_ID',
52-
'name': 'Test App Blog',
53-
'createdAt': '2022-07-06T18:42:26.126Z',
54-
},
55-
},
56-
};
57-
58-
// Error Mocks
59-
const _errorMessage = 'Unable to parse GraphQL query.';
60-
const _errorLocations = [
61-
{'line': 2, 'column': 3},
62-
{'line': 4, 'column': 5},
63-
];
64-
const _errorPath = ['a', 1, 'b'];
65-
const _errorExtensions = {
66-
'a': 'blah',
67-
'b': {'c': 'd'},
68-
};
69-
const _errorType = 'DynamoDB:ConditionalCheckFailedException';
70-
const _errorInfo = {'a': 'b'};
71-
const _expectedErrorResponseBody = {
72-
'data': null,
73-
'errors': [
74-
{
75-
'message': _errorMessage,
76-
'locations': _errorLocations,
77-
'path': _errorPath,
78-
'extensions': _errorExtensions,
79-
'errorType': _errorType,
80-
'errorInfo': _errorInfo,
81-
},
82-
],
83-
};
84-
85-
const _authErrorMessage = 'Not authorized';
86-
const _expectedAuthErrorResponseBody = {
87-
'data': null,
88-
'errors': [
89-
{
90-
'message': _authErrorMessage,
91-
},
92-
],
93-
};
94-
9524
final mockHttpClient = MockAWSHttpClient((request, _) async {
9625
if (request.headers[xApiKey] != 'abc123' &&
9726
request.headers[AWSHeaders.authorization] == testFunctionToken) {
9827
// Not authorized w API key but has lambda auth token, mock that auth mode
9928
// does not work for this query.
10029
return AWSHttpResponse(
10130
statusCode: 401,
102-
body: utf8.encode(json.encode(_expectedAuthErrorResponseBody)),
31+
body: utf8.encode(json.encode(expectedAuthErrorResponseBody)),
10332
);
10433
}
10534
if (request.headers[xApiKey] != 'abc123') {
@@ -110,25 +39,32 @@ final mockHttpClient = MockAWSHttpClient((request, _) async {
11039
if (body.contains('getBlog')) {
11140
return AWSHttpResponse(
11241
statusCode: 200,
113-
body: utf8.encode(json.encode(_expectedModelQueryResult)),
42+
body: utf8.encode(json.encode(expectedModelQueryResult)),
11443
);
11544
}
11645
if (body.contains('TestMutate')) {
11746
return AWSHttpResponse(
11847
statusCode: 400,
119-
body: utf8.encode(json.encode(_expectedMutateSuccessResponseBody)),
48+
body: utf8.encode(json.encode(expectedMutateSuccessResponseBody)),
12049
);
12150
}
12251
if (body.contains('TestError')) {
12352
return AWSHttpResponse(
12453
statusCode: 400,
125-
body: utf8.encode(json.encode(_expectedErrorResponseBody)),
54+
body: utf8.encode(json.encode(expectedErrorResponseBody)),
55+
);
56+
}
57+
if (body.contains('createModelWithCustomType')) {
58+
return AWSHttpResponse(
59+
statusCode: 200,
60+
body: utf8
61+
.encode(json.encode(expectedModelWithCustomTypeSuccessResponseBody)),
12662
);
12763
}
12864

12965
return AWSHttpResponse(
13066
statusCode: 400,
131-
body: utf8.encode((json.encode(_expectedQuerySuccessResponseBody))),
67+
body: utf8.encode((json.encode(expectedQuerySuccessResponseBody))),
13268
);
13369
});
13470

@@ -195,7 +131,7 @@ void main() {
195131
final operation = Amplify.API.query(request: req);
196132
final res = await operation.response;
197133

198-
final expected = json.encode(_expectedQuerySuccessResponseBody['data']);
134+
final expected = json.encode(expectedQuerySuccessResponseBody['data']);
199135

200136
expect(res.data, equals(expected));
201137
expect(res.errors, isEmpty);
@@ -219,7 +155,7 @@ void main() {
219155
final operation = Amplify.API.query(request: req);
220156
final res = await operation.response;
221157

222-
final expected = json.encode(_expectedQuerySuccessResponseBody['data']);
158+
final expected = json.encode(expectedQuerySuccessResponseBody['data']);
223159

224160
expect(res.data, equals(expected));
225161
expect(res.errors, isEmpty);
@@ -242,7 +178,23 @@ void main() {
242178
final operation = Amplify.API.mutate(request: req);
243179
final res = await operation.response;
244180

245-
final expected = json.encode(_expectedMutateSuccessResponseBody['data']);
181+
final expected = json.encode(expectedMutateSuccessResponseBody['data']);
182+
183+
expect(res.data, equals(expected));
184+
expect(res.errors, isEmpty);
185+
});
186+
187+
test('Mutate returns proper response.data for custom types', () async {
188+
final req = GraphQLRequest<String>(
189+
document: modelWithCustomTypeDocument,
190+
variables: modelWithCustomTypeVariables,
191+
);
192+
193+
final operation = Amplify.API.mutate(request: req);
194+
final res = await operation.response;
195+
196+
final expected =
197+
json.encode(expectedModelWithCustomTypeSuccessResponseBody['data']);
246198

247199
expect(res.data, equals(expected));
248200
expect(res.errors, isEmpty);
@@ -255,23 +207,57 @@ void main() {
255207
const expectedDoc =
256208
'query getBlog(\$id: ID!) { getBlog(id: \$id) { $blogSelectionSet } }';
257209
const decodePath = 'getBlog';
258-
final blog = Blog(id: _modelQueryId, name: 'Lorem ipsum $_modelQueryId');
210+
final blog = Blog(id: modelQueryId, name: 'Lorem ipsum $modelQueryId');
259211
final req = ModelQueries.get<Blog>(Blog.classType, blog.modelIdentifier);
260212

261213
final operation = Amplify.API.query(request: req);
262214
final res = await operation.response;
263215

264216
// request asserts
265217
expect(req.document, expectedDoc);
266-
expect(_deepEquals(req.variables, {'id': _modelQueryId}), isTrue);
218+
expect(_deepEquals(req.variables, {'id': modelQueryId}), isTrue);
267219
expect(req.modelType, Blog.classType);
268220
expect(req.decodePath, decodePath);
269221
// response asserts
270222
expect(res.data, isA<Blog>());
271-
expect(res.data?.id, _modelQueryId);
223+
expect(res.data?.id, modelQueryId);
224+
expect(res.errors, isEmpty);
225+
});
226+
227+
test(
228+
'Mutation.create returns proper response.data for Models with custom types',
229+
() async {
230+
const expectedDoc = modelWithCustomTypeDocument;
231+
const decodePath = 'createModelWithCustomType';
232+
final req = ModelMutations.create<ModelWithCustomType>(
233+
modelWithCustomType,
234+
);
235+
236+
final operation = Amplify.API.query(request: req);
237+
final res = await operation.response;
238+
239+
// request asserts
240+
expect(req.document, expectedDoc);
241+
expect(_deepEquals(req.variables, modelWithCustomTypeVariables), isTrue);
242+
expect(req.modelType, ModelWithCustomType.classType);
243+
expect(req.decodePath, decodePath);
244+
// response asserts
245+
expect(res.data, isA<ModelWithCustomType>());
246+
expect(res.data?.id, modelCustomTypeId);
247+
248+
final data = res.data!;
249+
expect(
250+
data.customTypeValue,
251+
equals(modelWithCustomType.customTypeValue),
252+
);
253+
expect(
254+
data.listOfCustomTypeValue,
255+
equals(modelWithCustomType.listOfCustomTypeValue),
256+
);
272257
expect(res.errors, isEmpty);
273258
});
274259
});
260+
275261
const graphQLDocument = '''subscription MySubscription {
276262
onCreateBlog {
277263
id
@@ -550,15 +536,15 @@ void main() {
550536
final res = await operation.response;
551537

552538
const errorExpected = GraphQLResponseError(
553-
message: _errorMessage,
539+
message: errorMessage,
554540
locations: [
555541
GraphQLResponseErrorLocation(2, 3),
556542
GraphQLResponseErrorLocation(4, 5),
557543
],
558-
path: <dynamic>[..._errorPath],
559-
extensions: <String, dynamic>{..._errorExtensions},
560-
errorType: _errorType,
561-
errorInfo: _errorInfo,
544+
path: <dynamic>[...errorPath],
545+
extensions: <String, dynamic>{...errorExtensions},
546+
errorType: errorType,
547+
errorInfo: errorInfo,
562548
);
563549

564550
expect(res.data, equals(null));
@@ -585,7 +571,7 @@ void main() {
585571
final res = await operation.response;
586572

587573
const errorExpected = GraphQLResponseError(
588-
message: _authErrorMessage,
574+
message: authErrorMessage,
589575
);
590576

591577
expect(res.data, equals(null));

0 commit comments

Comments
 (0)