Add Share Inbox flow for unresolved WhatsApp imports
This commit is contained in:
@@ -107,7 +107,9 @@ void main() {
|
||||
expect(first.createdProfile, isTrue);
|
||||
expect(afterFirst.people.length, before.people.length + 1);
|
||||
expect(
|
||||
afterFirst.sourceLinks.any((link) => link.profileId == first.profileId),
|
||||
afterFirst.sourceLinks.any(
|
||||
(SourceProfileLink link) => link.profileId == first.profileId,
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
expect(
|
||||
@@ -142,6 +144,116 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'queues ambiguous shared message into inbox for manual resolution',
|
||||
() async {
|
||||
final ProviderContainer container = _createContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
final LocalDataState before = await container.read(
|
||||
localRepositoryProvider.future,
|
||||
);
|
||||
|
||||
await container
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.addPerson(
|
||||
name: 'Alex Morgan',
|
||||
relationship: 'Friend',
|
||||
notes: '',
|
||||
tags: const <String>[],
|
||||
);
|
||||
await container
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.addPerson(
|
||||
name: 'Alex Morgan',
|
||||
relationship: 'Cousin',
|
||||
notes: '',
|
||||
tags: const <String>[],
|
||||
);
|
||||
|
||||
final SharedMessageIngestResult result = await container
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.ingestSharedMessage(
|
||||
const SharedMessageIngestInput(
|
||||
sourceApp: 'whatsapp',
|
||||
sourceDisplayName: 'Alex Morgan',
|
||||
messageText: 'Can we sync up tomorrow?',
|
||||
),
|
||||
);
|
||||
|
||||
final LocalDataState after = await container.read(
|
||||
localRepositoryProvider.future,
|
||||
);
|
||||
expect(result.isQueuedForResolution, isTrue);
|
||||
expect(result.inboxEntryId, isNotNull);
|
||||
expect(after.sharedInbox.length, 1);
|
||||
expect(
|
||||
after.sharedInbox.first.reason,
|
||||
SharedInboxReason.ambiguousProfileMatch,
|
||||
);
|
||||
expect(after.moments.length, before.moments.length);
|
||||
},
|
||||
);
|
||||
|
||||
test('resolves inbox item to existing profile', () async {
|
||||
final ProviderContainer container = _createContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
await container.read(localRepositoryProvider.future);
|
||||
|
||||
await container
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.addPerson(
|
||||
name: 'Alex Morgan',
|
||||
relationship: 'Friend',
|
||||
notes: '',
|
||||
tags: const <String>[],
|
||||
);
|
||||
await container
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.addPerson(
|
||||
name: 'Alex Morgan',
|
||||
relationship: 'Cousin',
|
||||
notes: '',
|
||||
tags: const <String>[],
|
||||
);
|
||||
|
||||
final SharedMessageIngestResult queued = await container
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.ingestSharedMessage(
|
||||
const SharedMessageIngestInput(
|
||||
sourceApp: 'whatsapp',
|
||||
sourceDisplayName: 'Alex Morgan',
|
||||
messageText: 'Did you see the offer?',
|
||||
),
|
||||
);
|
||||
final LocalDataState pending = await container.read(
|
||||
localRepositoryProvider.future,
|
||||
);
|
||||
final String profileId = pending.people.first.id;
|
||||
|
||||
final SharedMessageIngestResult resolved = await container
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.resolveSharedInboxToExistingProfile(
|
||||
inboxEntryId: queued.inboxEntryId!,
|
||||
profileId: profileId,
|
||||
);
|
||||
|
||||
final LocalDataState after = await container.read(
|
||||
localRepositoryProvider.future,
|
||||
);
|
||||
expect(resolved.isQueuedForResolution, isFalse);
|
||||
expect(resolved.profileId, profileId);
|
||||
expect(after.sharedInbox, isEmpty);
|
||||
expect(
|
||||
after.moments.any(
|
||||
(RelationshipMoment moment) => moment.personId == profileId,
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
expect(after.sharedMessages.first.resolvedAutomatically, isFalse);
|
||||
});
|
||||
|
||||
test('adds, archives, edits, and deletes ideas', () async {
|
||||
final ProviderContainer container = _createContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:relationship_saver/features/local/local_models.dart';
|
||||
import 'package:relationship_saver/features/local/local_repository.dart';
|
||||
import 'package:relationship_saver/features/local/storage/local_data_store_in_memory.dart';
|
||||
import 'package:relationship_saver/features/local/storage/local_data_store_provider.dart';
|
||||
import 'package:relationship_saver/features/reminders/scheduling/reminder_scheduler.dart';
|
||||
import 'package:relationship_saver/features/reminders/scheduling/reminder_scheduler_provider.dart';
|
||||
import 'package:relationship_saver/features/share_intake/share_inbox_view.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_in_memory.dart';
|
||||
import 'package:relationship_saver/features/sync/storage/sync_state_store_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
void main() {
|
||||
setUp(() {
|
||||
SharedPreferences.setMockInitialValues(<String, Object>{});
|
||||
});
|
||||
|
||||
testWidgets('shows queued inbox entry and allows dismiss', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final ProviderContainer container = ProviderContainer(
|
||||
overrides: [
|
||||
localDataStoreProvider.overrideWithValue(InMemoryLocalDataStore()),
|
||||
syncStateStoreProvider.overrideWithValue(InMemorySyncStateStore()),
|
||||
reminderSchedulerProvider.overrideWithValue(_NoopReminderScheduler()),
|
||||
],
|
||||
);
|
||||
addTearDown(container.dispose);
|
||||
|
||||
await container.read(localRepositoryProvider.future);
|
||||
await container
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.addPerson(
|
||||
name: 'Alex Morgan',
|
||||
relationship: 'Friend',
|
||||
notes: '',
|
||||
tags: const <String>[],
|
||||
);
|
||||
await container
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.addPerson(
|
||||
name: 'Alex Morgan',
|
||||
relationship: 'Cousin',
|
||||
notes: '',
|
||||
tags: const <String>[],
|
||||
);
|
||||
await container
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.ingestSharedMessage(
|
||||
const SharedMessageIngestInput(
|
||||
sourceApp: 'whatsapp',
|
||||
sourceDisplayName: 'Alex Morgan',
|
||||
messageText: 'Need help choosing this gift?',
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
UncontrolledProviderScope(
|
||||
container: container,
|
||||
child: const MaterialApp(home: Scaffold(body: ShareInboxView())),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Share Inbox'), findsOneWidget);
|
||||
expect(find.text('Ambiguous match'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.widgetWithText(TextButton, 'Dismiss Item').first);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('No unresolved shares.'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
||||
class _NoopReminderScheduler implements ReminderScheduler {
|
||||
@override
|
||||
Future<void> clearAll() async {}
|
||||
|
||||
@override
|
||||
Future<bool> requestPermissions() async => true;
|
||||
|
||||
@override
|
||||
Future<void> reconcile(List<ReminderRule> reminders) async {}
|
||||
}
|
||||
Reference in New Issue
Block a user