···
// Mock successful API response
mockVoteService.createVote(
(_) async => const VoteResponse(
-
uri: 'at://did:plc:test/social.coves.interaction.vote/456',
···
// Vote state should be correct
final voteState = voteProvider.getVoteState(testPostUri);
expect(voteState?.direction, 'up');
-
expect(voteState?.uri, 'at://did:plc:test/social.coves.interaction.vote/456');
expect(voteState?.deleted, false);
···
voteProvider.setInitialVoteState(
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
···
// Mock API response for toggling off
mockVoteService.createVote(
(_) async => const VoteResponse(deleted: true),
···
mockVoteService.createVote(
ApiException('Network error', statusCode: 500),
···
voteProvider.setInitialVoteState(
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
final initialState = voteProvider.getVoteState(testPostUri);
···
// Mock API failure when trying to toggle off
mockVoteService.createVote(
NetworkException('Connection failed'),
···
// Mock slow API response
mockVoteService.createVote(
await Future.delayed(const Duration(milliseconds: 100));
return const VoteResponse(
-
uri: 'at://did:plc:test/social.coves.interaction.vote/456',
···
// Should have only called API once
mockVoteService.createVote(
···
test('should handle downvote direction', () async {
mockVoteService.createVote(
(_) async => const VoteResponse(
-
uri: 'at://did:plc:test/social.coves.interaction.vote/456',
···
voteProvider.setInitialVoteState(
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
final voteState = voteProvider.getVoteState(testPostUri);
expect(voteState?.direction, 'up');
-
expect(voteState?.uri, 'at://did:plc:test/social.coves.interaction.vote/456');
expect(voteState?.deleted, false);
···
voteProvider.setInitialVoteState(
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
···
voteProvider.setInitialVoteState(
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
// Should NOT notify listeners (silent initialization)
···
voteProvider.setInitialVoteState(
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/1',
voteProvider.setInitialVoteState(
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/2',
expect(voteProvider.isLiked(post1), true);
···
// Mock slow API response
mockVoteService.createVote(
await Future.delayed(const Duration(milliseconds: 50));
return const VoteResponse(
-
uri: 'at://did:plc:test/social.coves.interaction.vote/456',
···
group('Auth state listener', () {
test('should clear votes when user signs out', () {
const testPostUri = 'at://did:plc:test/social.coves.post.record/123';
···
voteProvider.setInitialVoteState(
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
···
voteProvider.setInitialVoteState(
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
···
// Mock successful API response
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
(_) async => const VoteResponse(
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
···
// Vote state should be correct
final voteState = voteProvider.getVoteState(testPostUri);
expect(voteState?.direction, 'up');
+
expect(voteState?.uri, 'at://did:plc:test/social.coves.feed.vote/456');
expect(voteState?.deleted, false);
···
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
···
// Mock API response for toggling off
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
(_) async => const VoteResponse(deleted: true),
···
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
ApiException('Network error', statusCode: 500),
···
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
final initialState = voteProvider.getVoteState(testPostUri);
···
// Mock API failure when trying to toggle off
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
NetworkException('Connection failed'),
···
// Mock slow API response
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
await Future.delayed(const Duration(milliseconds: 100));
return const VoteResponse(
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
···
// Should have only called API once
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
···
test('should handle downvote direction', () async {
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
(_) async => const VoteResponse(
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
···
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
final voteState = voteProvider.getVoteState(testPostUri);
expect(voteState?.direction, 'up');
+
expect(voteState?.uri, 'at://did:plc:test/social.coves.feed.vote/456');
expect(voteState?.deleted, false);
···
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
···
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
// Should NOT notify listeners (silent initialization)
···
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/1',
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/2',
expect(voteProvider.isLiked(post1), true);
···
// Mock slow API response
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
await Future.delayed(const Duration(milliseconds: 50));
return const VoteResponse(
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
···
+
group('Score adjustments', () {
+
const testPostUri = 'at://did:plc:test/social.coves.post.record/123';
+
const testPostCid = 'bafy2bzacepostcid123';
+
test('should adjust score when creating upvote', () async {
+
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
+
(_) async => const VoteResponse(
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
+
// Initial score from server
+
const serverScore = 10;
+
// Before vote, adjustment should be 0
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 10);
+
await voteProvider.toggleVote(
+
// Should have +1 adjustment (upvote added)
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 11);
+
test('should adjust score when removing upvote', () async {
+
// Set initial state with upvote
+
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
+
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
+
(_) async => const VoteResponse(deleted: true),
+
const serverScore = 10;
+
// Before removing, adjustment should be 0 (server knows about upvote)
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 10);
+
await voteProvider.toggleVote(
+
// Should have -1 adjustment (upvote removed)
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 9);
+
test('should adjust score when creating downvote', () async {
+
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
+
(_) async => const VoteResponse(
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
+
const serverScore = 10;
+
await voteProvider.toggleVote(
+
// Should have -1 adjustment (downvote added)
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 9);
+
test('should adjust score when switching from upvote to downvote',
+
// Set initial state with upvote
+
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
+
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
+
(_) async => const VoteResponse(
+
uri: 'at://did:plc:test/social.coves.feed.vote/789',
+
const serverScore = 10;
+
await voteProvider.toggleVote(
+
// Should have -2 adjustment (remove +1, add -1)
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 8);
+
test('should adjust score when switching from downvote to upvote',
+
// Set initial state with downvote
+
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
+
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
+
(_) async => const VoteResponse(
+
uri: 'at://did:plc:test/social.coves.feed.vote/789',
+
const serverScore = 10;
+
await voteProvider.toggleVote(
+
// Should have +2 adjustment (remove -1, add +1)
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 12);
+
test('should rollback score adjustment on error', () async {
+
const serverScore = 10;
+
mockVoteService.createVote(
+
postUri: anyNamed('postUri'),
+
postCid: anyNamed('postCid'),
+
direction: anyNamed('direction'),
+
existingVoteRkey: anyNamed('existingVoteRkey'),
+
existingVoteDirection: anyNamed('existingVoteDirection'),
+
ApiException('Network error', statusCode: 500),
+
// Try to vote (will fail)
+
() => voteProvider.toggleVote(
+
throwsA(isA<ApiException>()),
+
await Future.delayed(Duration.zero);
+
// Adjustment should be rolled back to 0
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 10);
+
test('should clear score adjustments when clearing all state', () {
+
const testPostUri1 = 'at://did:plc:test/social.coves.post.record/1';
+
const testPostUri2 = 'at://did:plc:test/social.coves.post.record/2';
+
// Manually set some adjustments (simulating votes)
+
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/1',
+
// Adjustments should be cleared (back to 0)
+
expect(voteProvider.getAdjustedScore(testPostUri1, 10), 10);
+
expect(voteProvider.getAdjustedScore(testPostUri2, 5), 5);
group('Auth state listener', () {
test('should clear votes when user signs out', () {
const testPostUri = 'at://did:plc:test/social.coves.post.record/123';
···
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
···
voteProvider.setInitialVoteState(
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
expect(voteProvider.isLiked(testPostUri), true);