Files
rely/test/features/ai_digest/ai_digest_repository_test.dart
T
Rijad Zuzo f655adfbea feat: add local-first private AI digest workflow
Migrate app code into canonical feature slices, add phone-only AI digest scheduling and review, wire local notification/background task support, and cover the flow with tests.
2026-05-17 00:17:20 +02:00

115 lines
4.0 KiB
Dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:relationship_saver/app/data/relationship_repository.dart';
import 'package:relationship_saver/app/data/storage/local_data_store_in_memory.dart';
import 'package:relationship_saver/app/data/storage/local_data_store_provider.dart';
import 'package:relationship_saver/app/state/local_data_state.dart';
import 'package:relationship_saver/features/ai_digest/domain/ai_digest_models.dart';
import 'package:relationship_saver/features/ideas/domain/idea_models.dart';
import 'package:relationship_saver/features/reminders/application/reminder_scheduler.dart';
import 'package:relationship_saver/features/reminders/application/reminder_scheduler_provider.dart';
import 'package:relationship_saver/features/sync/data/storage/sync_state_store_in_memory.dart';
import 'package:relationship_saver/features/sync/data/storage/sync_state_store_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
setUp(() {
SharedPreferences.setMockInitialValues(<String, Object>{});
});
test('accepting gift draft creates idea and marks draft accepted', () async {
final ProviderContainer container = _createContainer();
addTearDown(container.dispose);
final LocalDataState initial = await container.read(
localRepositoryProvider.future,
);
final String personId = initial.people.first.id;
await container
.read(localRepositoryProvider.notifier)
.saveAiSuggestionDrafts(<AiSuggestionDraft>[
AiSuggestionDraft(
id: 'ai-1',
personId: personId,
kind: AiSuggestionKind.giftIdea,
title: 'Coffee sampler',
details: 'Small local roaster pack.',
suggestedAt: DateTime(2026, 5, 16),
confidence: 0.8,
status: AiSuggestionStatus.pending,
sourceRunId: 'run-1',
),
]);
await container
.read(localRepositoryProvider.notifier)
.acceptAiSuggestionDraft('ai-1');
final LocalDataState after = await container.read(
localRepositoryProvider.future,
);
expect(after.aiSuggestionDrafts.single.status, AiSuggestionStatus.accepted);
expect(
after.ideas.any(
(RelationshipIdea idea) =>
idea.personId == personId &&
idea.type == IdeaType.gift &&
idea.title == 'Coffee sampler',
),
isTrue,
);
});
test('dismissing draft does not create local artifacts', () async {
final ProviderContainer container = _createContainer();
addTearDown(container.dispose);
final LocalDataState initial = await container.read(
localRepositoryProvider.future,
);
final String personId = initial.people.first.id;
final int ideaCount = initial.ideas.length;
await container
.read(localRepositoryProvider.notifier)
.saveAiSuggestionDrafts(<AiSuggestionDraft>[
AiSuggestionDraft(
id: 'ai-2',
personId: personId,
kind: AiSuggestionKind.eventIdea,
title: 'Museum afternoon',
details: 'Pick a quiet exhibit.',
suggestedAt: DateTime(2026, 5, 16),
confidence: 0.7,
status: AiSuggestionStatus.pending,
sourceRunId: 'run-1',
),
]);
await container
.read(localRepositoryProvider.notifier)
.dismissAiSuggestionDraft('ai-2');
final LocalDataState after = await container.read(
localRepositoryProvider.future,
);
expect(
after.aiSuggestionDrafts.single.status,
AiSuggestionStatus.dismissed,
);
expect(after.ideas.length, ideaCount);
});
}
ProviderContainer _createContainer() {
return ProviderContainer(
overrides: [
localDataStoreProvider.overrideWithValue(InMemoryLocalDataStore()),
syncStateStoreProvider.overrideWithValue(InMemorySyncStateStore()),
reminderSchedulerProvider.overrideWithValue(
const NoopReminderScheduler(),
),
],
);
}