···
// Mock successful API response
mockVoteService.createVote(
46
-
postUri: testPostUri,
47
-
postCid: testPostCid,
46
+
postUri: anyNamed('postUri'),
47
+
postCid: anyNamed('postCid'),
48
+
direction: anyNamed('direction'),
49
+
existingVoteRkey: anyNamed('existingVoteRkey'),
50
+
existingVoteDirection: anyNamed('existingVoteDirection'),
(_) async => const VoteResponse(
51
-
uri: 'at://did:plc:test/social.coves.interaction.vote/456',
54
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
···
// Vote state should be correct
final voteState = voteProvider.getVoteState(testPostUri);
expect(voteState?.direction, 'up');
84
-
expect(voteState?.uri, 'at://did:plc:test/social.coves.interaction.vote/456');
87
+
expect(voteState?.uri, 'at://did:plc:test/social.coves.feed.vote/456');
expect(voteState?.deleted, false);
···
voteProvider.setInitialVoteState(
93
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
96
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
···
// Mock API response for toggling off
mockVoteService.createVote(
101
-
postUri: testPostUri,
102
-
postCid: testPostCid,
104
+
postUri: anyNamed('postUri'),
105
+
postCid: anyNamed('postCid'),
106
+
direction: anyNamed('direction'),
107
+
existingVoteRkey: anyNamed('existingVoteRkey'),
108
+
existingVoteDirection: anyNamed('existingVoteDirection'),
(_) async => const VoteResponse(deleted: true),
···
mockVoteService.createVote(
132
-
postUri: testPostUri,
133
-
postCid: testPostCid,
138
+
postUri: anyNamed('postUri'),
139
+
postCid: anyNamed('postCid'),
140
+
direction: anyNamed('direction'),
141
+
existingVoteRkey: anyNamed('existingVoteRkey'),
142
+
existingVoteDirection: anyNamed('existingVoteDirection'),
ApiException('Network error', statusCode: 500),
···
voteProvider.setInitialVoteState(
167
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
176
+
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(
176
-
postUri: testPostUri,
177
-
postCid: testPostCid,
185
+
postUri: anyNamed('postUri'),
186
+
postCid: anyNamed('postCid'),
187
+
direction: anyNamed('direction'),
188
+
existingVoteRkey: anyNamed('existingVoteRkey'),
189
+
existingVoteDirection: anyNamed('existingVoteDirection'),
NetworkException('Connection failed'),
···
// Mock slow API response
mockVoteService.createVote(
202
-
postUri: testPostUri,
203
-
postCid: testPostCid,
214
+
postUri: anyNamed('postUri'),
215
+
postCid: anyNamed('postCid'),
216
+
direction: anyNamed('direction'),
217
+
existingVoteRkey: anyNamed('existingVoteRkey'),
218
+
existingVoteDirection: anyNamed('existingVoteDirection'),
await Future.delayed(const Duration(milliseconds: 100));
return const VoteResponse(
209
-
uri: 'at://did:plc:test/social.coves.interaction.vote/456',
224
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
···
// Should have only called API once
mockVoteService.createVote(
239
-
postUri: testPostUri,
240
-
postCid: testPostCid,
254
+
postUri: anyNamed('postUri'),
255
+
postCid: anyNamed('postCid'),
256
+
direction: anyNamed('direction'),
257
+
existingVoteRkey: anyNamed('existingVoteRkey'),
258
+
existingVoteDirection: anyNamed('existingVoteDirection'),
···
test('should handle downvote direction', () async {
mockVoteService.createVote(
248
-
postUri: testPostUri,
249
-
postCid: testPostCid,
266
+
postUri: anyNamed('postUri'),
267
+
postCid: anyNamed('postCid'),
268
+
direction: anyNamed('direction'),
269
+
existingVoteRkey: anyNamed('existingVoteRkey'),
270
+
existingVoteDirection: anyNamed('existingVoteDirection'),
(_) async => const VoteResponse(
254
-
uri: 'at://did:plc:test/social.coves.interaction.vote/456',
274
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
···
voteProvider.setInitialVoteState(
283
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
303
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
final voteState = voteProvider.getVoteState(testPostUri);
expect(voteState?.direction, 'up');
290
-
expect(voteState?.uri, 'at://did:plc:test/social.coves.interaction.vote/456');
310
+
expect(voteState?.uri, 'at://did:plc:test/social.coves.feed.vote/456');
expect(voteState?.deleted, false);
···
voteProvider.setInitialVoteState(
299
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
319
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
···
voteProvider.setInitialVoteState(
322
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
342
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
// Should NOT notify listeners (silent initialization)
···
voteProvider.setInitialVoteState(
339
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/1',
359
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/1',
voteProvider.setInitialVoteState(
344
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/2',
364
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/2',
expect(voteProvider.isLiked(post1), true);
···
// Mock slow API response
mockVoteService.createVote(
380
-
postUri: testPostUri,
381
-
postCid: testPostCid,
400
+
postUri: anyNamed('postUri'),
401
+
postCid: anyNamed('postCid'),
402
+
direction: anyNamed('direction'),
403
+
existingVoteRkey: anyNamed('existingVoteRkey'),
404
+
existingVoteDirection: anyNamed('existingVoteDirection'),
await Future.delayed(const Duration(milliseconds: 50));
return const VoteResponse(
387
-
uri: 'at://did:plc:test/social.coves.interaction.vote/456',
410
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
···
445
+
group('Score adjustments', () {
446
+
const testPostUri = 'at://did:plc:test/social.coves.post.record/123';
447
+
const testPostCid = 'bafy2bzacepostcid123';
449
+
test('should adjust score when creating upvote', () async {
451
+
mockVoteService.createVote(
452
+
postUri: anyNamed('postUri'),
453
+
postCid: anyNamed('postCid'),
454
+
direction: anyNamed('direction'),
455
+
existingVoteRkey: anyNamed('existingVoteRkey'),
456
+
existingVoteDirection: anyNamed('existingVoteDirection'),
459
+
(_) async => const VoteResponse(
460
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
467
+
// Initial score from server
468
+
const serverScore = 10;
470
+
// Before vote, adjustment should be 0
471
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 10);
474
+
await voteProvider.toggleVote(
475
+
postUri: testPostUri,
476
+
postCid: testPostCid,
479
+
// Should have +1 adjustment (upvote added)
480
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 11);
483
+
test('should adjust score when removing upvote', () async {
484
+
// Set initial state with upvote
485
+
voteProvider.setInitialVoteState(
486
+
postUri: testPostUri,
487
+
voteDirection: 'up',
488
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
492
+
mockVoteService.createVote(
493
+
postUri: anyNamed('postUri'),
494
+
postCid: anyNamed('postCid'),
495
+
direction: anyNamed('direction'),
496
+
existingVoteRkey: anyNamed('existingVoteRkey'),
497
+
existingVoteDirection: anyNamed('existingVoteDirection'),
500
+
(_) async => const VoteResponse(deleted: true),
503
+
const serverScore = 10;
505
+
// Before removing, adjustment should be 0 (server knows about upvote)
506
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 10);
509
+
await voteProvider.toggleVote(
510
+
postUri: testPostUri,
511
+
postCid: testPostCid,
514
+
// Should have -1 adjustment (upvote removed)
515
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 9);
518
+
test('should adjust score when creating downvote', () async {
520
+
mockVoteService.createVote(
521
+
postUri: anyNamed('postUri'),
522
+
postCid: anyNamed('postCid'),
523
+
direction: anyNamed('direction'),
524
+
existingVoteRkey: anyNamed('existingVoteRkey'),
525
+
existingVoteDirection: anyNamed('existingVoteDirection'),
528
+
(_) async => const VoteResponse(
529
+
uri: 'at://did:plc:test/social.coves.feed.vote/456',
536
+
const serverScore = 10;
539
+
await voteProvider.toggleVote(
540
+
postUri: testPostUri,
541
+
postCid: testPostCid,
545
+
// Should have -1 adjustment (downvote added)
546
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 9);
549
+
test('should adjust score when switching from upvote to downvote',
551
+
// Set initial state with upvote
552
+
voteProvider.setInitialVoteState(
553
+
postUri: testPostUri,
554
+
voteDirection: 'up',
555
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
559
+
mockVoteService.createVote(
560
+
postUri: anyNamed('postUri'),
561
+
postCid: anyNamed('postCid'),
562
+
direction: anyNamed('direction'),
563
+
existingVoteRkey: anyNamed('existingVoteRkey'),
564
+
existingVoteDirection: anyNamed('existingVoteDirection'),
567
+
(_) async => const VoteResponse(
568
+
uri: 'at://did:plc:test/social.coves.feed.vote/789',
575
+
const serverScore = 10;
577
+
// Switch to downvote
578
+
await voteProvider.toggleVote(
579
+
postUri: testPostUri,
580
+
postCid: testPostCid,
584
+
// Should have -2 adjustment (remove +1, add -1)
585
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 8);
588
+
test('should adjust score when switching from downvote to upvote',
590
+
// Set initial state with downvote
591
+
voteProvider.setInitialVoteState(
592
+
postUri: testPostUri,
593
+
voteDirection: 'down',
594
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
598
+
mockVoteService.createVote(
599
+
postUri: anyNamed('postUri'),
600
+
postCid: anyNamed('postCid'),
601
+
direction: anyNamed('direction'),
602
+
existingVoteRkey: anyNamed('existingVoteRkey'),
603
+
existingVoteDirection: anyNamed('existingVoteDirection'),
606
+
(_) async => const VoteResponse(
607
+
uri: 'at://did:plc:test/social.coves.feed.vote/789',
614
+
const serverScore = 10;
616
+
// Switch to upvote
617
+
await voteProvider.toggleVote(
618
+
postUri: testPostUri,
619
+
postCid: testPostCid,
623
+
// Should have +2 adjustment (remove -1, add +1)
624
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 12);
627
+
test('should rollback score adjustment on error', () async {
628
+
const serverScore = 10;
631
+
mockVoteService.createVote(
632
+
postUri: anyNamed('postUri'),
633
+
postCid: anyNamed('postCid'),
634
+
direction: anyNamed('direction'),
635
+
existingVoteRkey: anyNamed('existingVoteRkey'),
636
+
existingVoteDirection: anyNamed('existingVoteDirection'),
639
+
ApiException('Network error', statusCode: 500),
642
+
// Try to vote (will fail)
644
+
() => voteProvider.toggleVote(
645
+
postUri: testPostUri,
646
+
postCid: testPostCid,
648
+
throwsA(isA<ApiException>()),
651
+
await Future.delayed(Duration.zero);
653
+
// Adjustment should be rolled back to 0
654
+
expect(voteProvider.getAdjustedScore(testPostUri, serverScore), 10);
657
+
test('should clear score adjustments when clearing all state', () {
658
+
const testPostUri1 = 'at://did:plc:test/social.coves.post.record/1';
659
+
const testPostUri2 = 'at://did:plc:test/social.coves.post.record/2';
661
+
// Manually set some adjustments (simulating votes)
662
+
voteProvider.setInitialVoteState(
663
+
postUri: testPostUri1,
664
+
voteDirection: 'up',
665
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/1',
669
+
voteProvider.clear();
671
+
// Adjustments should be cleared (back to 0)
672
+
expect(voteProvider.getAdjustedScore(testPostUri1, 10), 10);
673
+
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(
430
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
685
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
expect(voteProvider.isLiked(testPostUri), true);
···
voteProvider.setInitialVoteState(
454
-
voteUri: 'at://did:plc:test/social.coves.interaction.vote/456',
709
+
voteUri: 'at://did:plc:test/social.coves.feed.vote/456',
expect(voteProvider.isLiked(testPostUri), true);