diff --git a/lib/src/data_classes/directus_error.dart b/lib/src/data_classes/directus_error.dart index 25da0d5..b0aa45a 100644 --- a/lib/src/data_classes/directus_error.dart +++ b/lib/src/data_classes/directus_error.dart @@ -19,6 +19,9 @@ class DirectusError implements Exception { /// Additional info that can be provided to error. late final Map? additionalInfo; + /// Original DioError from error. + late final DioError? dioError; + /// Constructor DirectusError({ required this.message, @@ -56,5 +59,6 @@ class DirectusError implements Exception { 'codeMessage': error.response?.statusMessage ?? 'Error', 'response': error.response }; + dioError = error; } } diff --git a/lib/src/modules/auth/auth_handler.dart b/lib/src/modules/auth/auth_handler.dart index a22f4e7..6f14f28 100644 --- a/lib/src/modules/auth/auth_handler.dart +++ b/lib/src/modules/auth/auth_handler.dart @@ -171,11 +171,15 @@ class AuthHandler with StaticToken { return handler.next(options); } - final response = await manuallyRefresh(); - if (response?.accessToken != null) { - options.headers['Authorization'] = response!.accessToken; - } else { - options.headers.remove('Authorization'); + try { + final response = await manuallyRefresh(); + if (response?.accessToken != null) { + options.headers['Authorization'] = response!.accessToken; + } else { + options.headers.remove('Authorization'); + } + } on DirectusError catch (e) { + return handler.reject(e.dioError!); } return handler.next(options); diff --git a/test/src/data_classes/directus_error_test.dart b/test/src/data_classes/directus_error_test.dart index 8ed7c6f..b2f05b9 100644 --- a/test/src/data_classes/directus_error_test.dart +++ b/test/src/data_classes/directus_error_test.dart @@ -30,4 +30,23 @@ void main() { expect(error.code, 400); expect(error.message, 'API message'); }); + + test('that DirectusError will keep the original DioError', () { + final dioError = DioError( + requestOptions: RequestOptions(path: '/'), + response: Response( + requestOptions: RequestOptions(path: '/'), + data: { + 'errors': [ + {'message': 'API message'} + ] + }, + statusCode: 400, + statusMessage: 'Bad Request', + ), + ); + final error = DirectusError.fromDio(dioError); + + expect(error.dioError, dioError); + }); } diff --git a/test/src/modules/auth/auth_handler_test.dart b/test/src/modules/auth/auth_handler_test.dart index 706cbee..f343642 100644 --- a/test/src/modules/auth/auth_handler_test.dart +++ b/test/src/modules/auth/auth_handler_test.dart @@ -290,6 +290,36 @@ void main() { verify(interceptorHandler.next(any)).called(1); }); + test('refreshing token rethrows DioError when manuallyRefresh failed', + () async { + final dioError = DioError( + requestOptions: RequestOptions(path: '/'), + response: Response( + requestOptions: RequestOptions(path: '/'), + data: 'error', + )); + final interceptorHandler = MockRequestInterceptorHandler(); + + when(refreshClient.post(any, data: anyNamed('data'))).thenAnswer( + (realInvocation) { + throw dioError; + }, + ); + + // Setup for forcing refresh token + auth.tokens = mockAuthResponse(); + auth.tokens!.accessTokenExpiresAt = + DateTime.now().add(Duration(seconds: 4)); + + await auth.refreshExpiredTokenInterceptor( + RequestOptions(path: '/'), + interceptorHandler, + ); + + // Check for the same dioError is thrown + verify(interceptorHandler.reject(dioError)).called(1); + }); + test('client is unlocked if refresh throws an error', () async { when(refreshClient.post(any, data: anyNamed('data'))) .thenAnswer((realInvocation) {