Skip to content

Commit

Permalink
feat: added chopper tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jhomlala committed Jul 9, 2024
1 parent d7b3d4d commit 62c2b3b
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/alice_chopper/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

* Added lint for trailing commas.
* General refactor of code base.
* Added support for form data.
* Added tests.

# 1.0.5

Expand Down
4 changes: 4 additions & 0 deletions packages/alice_chopper/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ dev_dependencies:
test: ^1.25.2
alice_test: ^1.0.0
mocktail: ^1.0.4
build_runner: ^2.4.9
chopper_generator: ^8.0.0
json_serializable: ^6.8.0
json_annotation: ^4.9.0
80 changes: 80 additions & 0 deletions packages/alice_chopper/test/alice_chopper_adapter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import 'package:mocktail/mocktail.dart';
import 'package:test/test.dart';
import 'package:http/http.dart' as http;

import 'invalid_model.dart';
import 'invalid_service.dart';
import 'json_serializable_converter.dart';

void main() {
final baseUrl = Uri.parse('https://test.com');
late AliceCore aliceCore;
Expand Down Expand Up @@ -366,5 +370,81 @@ void main() {

verify(() => aliceCore.addError(any(that: errorMatcher), any()));
});

test("should handle call with error when model fails", () async {
final mockClient = MockClient((request) async {
return http.Response(
'{"id": 0}',
200,
headers: {'content-type': 'application/json'},
);
});

chopperClient = ChopperClient(
baseUrl: baseUrl,
client: mockClient,
interceptors: [aliceChopperAdapter],
services: [InvalidService.create()],
converter: const JsonSerializableConverter(
{InvalidModel: InvalidModel.fromJson},
),
);

final service = chopperClient.getService<InvalidService>();
try {
await service.get(0);
} catch (_) {}

final requestMatcher = buildRequestMatcher(
checkTime: true,
);

final responseMatcher = buildResponseMatcher(checkTime: true);

final callMatcher = buildCallMatcher(
checkId: true,
checkTime: true,
secured: true,
loading: true,
client: 'Chopper',
method: 'GET',
endpoint: '/posts/0',
server: 'test.com',
uri: 'https://test.com/posts/0',
duration: 0,
request: requestMatcher,
response: responseMatcher,
);

verify(() => aliceCore.addCall(any(that: callMatcher)));

final nextResponseMatcher = buildResponseMatcher(
status: -1,
size: 0,
checkTime: true,
);

verify(
() => aliceCore.addResponse(
any(that: nextResponseMatcher),
any(),
),
);

final errorMatcher = buildErrorMatcher(
checkError: true,
checkStacktrace: true,
);

verify(() => aliceCore.addError(any(that: errorMatcher), any()));

final logMatcher = buildLogMatcher(
checkMessage: true,
checkError: true,
checkStacktrace: true,
checkTime: true,
);
verify(() => aliceCore.addLog(any(that: logMatcher)));
});
});
}
31 changes: 31 additions & 0 deletions packages/alice_chopper/test/invalid_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';

part 'invalid_model.g.dart';

@JsonSerializable()
class InvalidModel with EquatableMixin {
const InvalidModel({
this.id,
});

// should be `int?` but we want to test the error
final String? id;

InvalidModel copyWith({
String? id,
}) =>
InvalidModel(
id: id ?? this.id,
);

factory InvalidModel.fromJson(Map<String, dynamic> json) =>
_$InvalidModelFromJson(json);

Map<String, dynamic> toJson() => _$InvalidModelToJson(this);

@override
List<Object?> get props => [
id,
];
}
16 changes: 16 additions & 0 deletions packages/alice_chopper/test/invalid_model.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions packages/alice_chopper/test/invalid_service.chopper.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions packages/alice_chopper/test/invalid_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:chopper/chopper.dart';

import 'invalid_model.dart';

part 'invalid_service.chopper.dart';

@ChopperApi(baseUrl: '/posts')
abstract class InvalidService extends ChopperService {
static InvalidService create([ChopperClient? client]) =>
_$InvalidService(client);

@Get(path: '/{id}', timeout: Duration(seconds: 10))
Future<Response<InvalidModel?>> get(@Path() int id);
}
49 changes: 49 additions & 0 deletions packages/alice_chopper/test/json_serializable_converter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'dart:async' show FutureOr;

import 'package:chopper/chopper.dart';

typedef JsonFactory<T> = T Function(Map<String, dynamic> json);

class JsonSerializableConverter extends JsonConverter {
final Map<Type, JsonFactory> factories;

const JsonSerializableConverter(this.factories);

T? _decodeMap<T>(Map<String, dynamic> values) {
/// Get jsonFactory using Type parameters
/// if not found or invalid, throw error or return null
final jsonFactory = factories[T];
if (jsonFactory == null || jsonFactory is! JsonFactory<T>) {
/// throw serializer not found error;
return null;
}

return jsonFactory(values);
}

List<T> _decodeList<T>(Iterable values) =>
values.where((v) => v != null).map<T>((v) => _decode<T>(v)).toList();

dynamic _decode<T>(entity) {
if (entity is Iterable) return _decodeList<T>(entity as List);

if (entity is Map) return _decodeMap<T>(entity as Map<String, dynamic>);

return entity;
}

@override
FutureOr<Response<ResultType>> convertResponse<ResultType, Item>(
Response response,
) async {
// use [JsonConverter] to decode json
final jsonRes = await super.convertResponse(response);

return jsonRes.copyWith<ResultType>(body: _decode<Item>(jsonRes.body));
}

@override
// all objects should implements toJson method
// ignore: unnecessary_overrides
Request convertRequest(Request request) => super.convertRequest(request);
}

0 comments on commit 62c2b3b

Please sign in to comment.