149 lines
4.8 KiB
Dart
149 lines
4.8 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:dio/dio.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:marianum_mobile/api/api_error.dart';
|
|
import 'package:marianum_mobile/api/errors/auth_exception.dart';
|
|
import 'package:marianum_mobile/api/errors/error_mapper.dart';
|
|
import 'package:marianum_mobile/api/errors/network_exception.dart';
|
|
import 'package:marianum_mobile/api/errors/parse_exception.dart';
|
|
|
|
void main() {
|
|
group('errorToUserMessage', () {
|
|
test('null falls back to the default message', () {
|
|
expect(errorToUserMessage(null), contains('Etwas ist schiefgelaufen'));
|
|
});
|
|
|
|
test('AppException returns its own userMessage', () {
|
|
final exception = AuthException.unauthorized();
|
|
expect(errorToUserMessage(exception), exception.userMessage);
|
|
});
|
|
|
|
test('SocketException maps to NetworkException message', () {
|
|
expect(
|
|
errorToUserMessage(const SocketException('boom')),
|
|
const NetworkException().userMessage,
|
|
);
|
|
});
|
|
|
|
test(
|
|
'TimeoutException maps to the timeout-specific NetworkException message',
|
|
() {
|
|
expect(
|
|
errorToUserMessage(TimeoutException('slow')),
|
|
NetworkException.timeout().userMessage,
|
|
);
|
|
},
|
|
);
|
|
|
|
test('http.ClientException maps to NetworkException message', () {
|
|
expect(
|
|
errorToUserMessage(http.ClientException('failed')),
|
|
const NetworkException().userMessage,
|
|
);
|
|
});
|
|
|
|
test('HandshakeException maps to a TLS-specific message', () {
|
|
final message = errorToUserMessage(const HandshakeException('bad cert'));
|
|
expect(message, contains('sichere Verbindung'));
|
|
expect(message, contains('Geräte-Uhrzeit'));
|
|
});
|
|
|
|
test('FormatException maps to ParseException message', () {
|
|
expect(
|
|
errorToUserMessage(const FormatException('bad json')),
|
|
const ParseException().userMessage,
|
|
);
|
|
});
|
|
|
|
test('ApiError surfaces only the first line of its message', () {
|
|
final err = ApiError('Boom\nGET https://example.com/foo');
|
|
expect(errorToUserMessage(err), 'Boom');
|
|
});
|
|
|
|
test('ApiError with empty message falls back to default', () {
|
|
final err = ApiError('');
|
|
expect(errorToUserMessage(err), contains('Etwas ist schiefgelaufen'));
|
|
});
|
|
|
|
test('unknown error type falls back', () {
|
|
expect(
|
|
errorToUserMessage(StateError('weird')),
|
|
contains('Etwas ist schiefgelaufen'),
|
|
);
|
|
});
|
|
|
|
test('custom fallback overrides the default', () {
|
|
expect(errorToUserMessage(null, fallback: 'meins'), 'meins');
|
|
});
|
|
|
|
test('DioException connectionTimeout maps to timeout NetworkException', () {
|
|
final ex = DioException(
|
|
requestOptions: RequestOptions(path: '/x'),
|
|
type: DioExceptionType.connectionTimeout,
|
|
);
|
|
expect(errorToUserMessage(ex), NetworkException.timeout().userMessage);
|
|
});
|
|
|
|
test('DioException connectionError maps to NetworkException', () {
|
|
final ex = DioException(
|
|
requestOptions: RequestOptions(path: '/x'),
|
|
type: DioExceptionType.connectionError,
|
|
);
|
|
expect(errorToUserMessage(ex), const NetworkException().userMessage);
|
|
});
|
|
|
|
test('DioException badResponse maps to a server status message', () {
|
|
final ex = DioException(
|
|
requestOptions: RequestOptions(path: '/x'),
|
|
type: DioExceptionType.badResponse,
|
|
response: Response(
|
|
requestOptions: RequestOptions(path: '/x'),
|
|
statusCode: 503,
|
|
),
|
|
);
|
|
expect(errorToUserMessage(ex), contains('503'));
|
|
});
|
|
});
|
|
|
|
group('errorToTechnicalDetails', () {
|
|
test('null returns null', () {
|
|
expect(errorToTechnicalDetails(null), isNull);
|
|
});
|
|
|
|
test('AppException uses its technicalDetails when set', () {
|
|
final ex = AuthException.unauthorized(technicalDetails: 'http 401, foo');
|
|
expect(errorToTechnicalDetails(ex), 'http 401, foo');
|
|
});
|
|
|
|
test('AppException without details falls back to toString()', () {
|
|
final ex = AuthException.unauthorized();
|
|
expect(errorToTechnicalDetails(ex), ex.toString());
|
|
});
|
|
|
|
test('arbitrary object stringifies', () {
|
|
expect(errorToTechnicalDetails(StateError('x')), contains('x'));
|
|
});
|
|
});
|
|
|
|
group('errorAllowsRetry', () {
|
|
test('null allows retry by default', () {
|
|
expect(errorAllowsRetry(null), isTrue);
|
|
});
|
|
|
|
test('AuthException disallows retry (allowRetry=false)', () {
|
|
expect(errorAllowsRetry(AuthException.unauthorized()), isFalse);
|
|
});
|
|
|
|
test('NetworkException allows retry (allowRetry=true)', () {
|
|
expect(errorAllowsRetry(const NetworkException()), isTrue);
|
|
});
|
|
|
|
test('non-AppException allows retry by default', () {
|
|
expect(errorAllowsRetry(StateError('x')), isTrue);
|
|
});
|
|
});
|
|
}
|