Skip to content

Commit

Permalink
feat: adds reset api call (#319)
Browse files Browse the repository at this point in the history
  • Loading branch information
AyadLaouissi authored Apr 18, 2024
1 parent 385750a commit ed087da
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 0 deletions.
29 changes: 29 additions & 0 deletions api/routes/game/reset_streak.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import 'dart:async';
import 'dart:io';

import 'package:dart_frog/dart_frog.dart';
import 'package:jwt_middleware/jwt_middleware.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart';
import 'package:logging/logging.dart';

FutureOr<Response> onRequest(RequestContext context) async {
if (context.request.method == HttpMethod.post) {
return _onPost(context);
}
return Response(statusCode: HttpStatus.methodNotAllowed);
}

Future<Response> _onPost(RequestContext context) async {
final leaderboardRepository = context.read<LeaderboardRepository>();

final user = context.read<AuthenticatedUser>();

try {
await leaderboardRepository.resetStreak(user.id);
} catch (e, s) {
context.read<Logger>().severe('Error resetting the streak', e, s);
rethrow;
}

return Response();
}
95 changes: 95 additions & 0 deletions api/test/routes/game/reset_streak_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// ignore_for_file: prefer_const_constructors

import 'dart:io';

import 'package:dart_frog/dart_frog.dart';
import 'package:jwt_middleware/jwt_middleware.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart';
import 'package:logging/logging.dart';
import 'package:mocktail/mocktail.dart';
import 'package:test/test.dart';

import '../../../routes/game/reset_streak.dart' as route;

class _MockLeaderboardRepository extends Mock
implements LeaderboardRepository {}

class _MockRequest extends Mock implements Request {}

class _MockRequestContext extends Mock implements RequestContext {}

class _MockLogger extends Mock implements Logger {}

void main() {
late LeaderboardRepository leaderboardRepository;
late Request request;
late RequestContext context;
late Logger logger;

setUp(() {
leaderboardRepository = _MockLeaderboardRepository();
request = _MockRequest();
logger = _MockLogger();

context = _MockRequestContext();
when(() => context.request).thenReturn(request);
when(() => context.read<LeaderboardRepository>())
.thenReturn(leaderboardRepository);
when(() => context.read<Logger>()).thenReturn(logger);
when(() => context.read<AuthenticatedUser>())
.thenReturn(AuthenticatedUser('id'));
});

for (final method in HttpMethod.values.toList()..remove(HttpMethod.post)) {
test(
'responds with a ${HttpStatus.methodNotAllowed} status with $method',
() async {
when(() => request.method).thenReturn(method);
when(() => leaderboardRepository.resetStreak('id'))
.thenAnswer((_) async {});

final response = await route.onRequest(context);
expect(response.statusCode, equals(HttpStatus.methodNotAllowed));
},
);
}

group('POST', () {
test(
'responds with a HttpStatus.created status when reset is correct',
() async {
when(() => request.method).thenReturn(HttpMethod.post);
when(() => leaderboardRepository.resetStreak('id'))
.thenAnswer((_) async {});

final response = await route.onRequest(context);
expect(response.statusCode, equals(HttpStatus.ok));
},
);

test(
'calls resetStreak with the user id',
() async {
when(() => request.method).thenReturn(HttpMethod.post);
when(() => leaderboardRepository.resetStreak('id'))
.thenAnswer((_) async {});

await route.onRequest(context);

verify(() => leaderboardRepository.resetStreak('id')).called(1);
},
);

test(
'throws error when resetStreak throws exception',
() async {
when(() => request.method).thenReturn(HttpMethod.post);
when(() => leaderboardRepository.resetStreak('id'))
.thenThrow(Exception());

final response = route.onRequest(context);
expect(response, throwsA(isA<Exception>()));
},
);
});
}
16 changes: 16 additions & 0 deletions packages/api_client/lib/src/resources/leaderboard_resource.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,20 @@ class LeaderboardResource {
);
}
}

/// Post /game/reset_streak
Future<void> resetStreak() async {
final response = await _apiClient.post(
'/game/reset_streak',
);

if (response.statusCode != HttpStatus.ok) {
throw ApiClientError(
'POST /game/reset_streak returned status '
'${response.statusCode} with the following response: '
'"${response.body}"',
StackTrace.current,
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,42 @@ void main() {
);
});
});

group('resetStreak', () {
setUp(() {
when(() => apiClient.post(any())).thenAnswer((_) async => response);
});

test('makes the correct call', () async {
when(() => response.statusCode).thenReturn(HttpStatus.ok);
await resource.resetStreak();

verify(
() => apiClient.post(
'/game/reset_streak',
),
).called(1);
});

test('throws ApiClientError when request fails', () async {
when(() => response.statusCode)
.thenReturn(HttpStatus.internalServerError);
when(() => response.body).thenReturn('Oops');

await expectLater(
() => resource.resetStreak(),
throwsA(
isA<ApiClientError>().having(
(e) => e.cause,
'cause',
equals(
'POST /game/reset_streak returned status 500 '
'with the following response: "Oops"',
),
),
),
);
});
});
});
}

0 comments on commit ed087da

Please sign in to comment.