Files
rely/test/features/signals/signals_feed_synthesizer_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

140 lines
4.0 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:relationship_saver/app/state/local_data_state.dart';
import 'package:relationship_saver/features/ideas/domain/idea_models.dart';
import 'package:relationship_saver/features/people/domain/person_models.dart';
import 'package:relationship_saver/features/reminders/domain/reminder_models.dart';
import 'package:relationship_saver/features/share_intake/domain/share_models.dart';
import 'package:relationship_saver/features/signals/domain/signals_feed_synthesizer.dart';
void main() {
test(
'creates a check-in signal when interaction is stale and no reminder exists',
() {
final LocalDataState state = LocalDataState(
people: <PersonProfile>[
PersonProfile(
id: 'p-1',
name: 'Alex',
relationship: 'Friend',
affinityScore: 80,
nextMoment: DateTime(2026, 4, 30),
tags: const <String>[],
notes: '',
lastInteractedAt: DateTime(2026, 4, 1),
),
],
moments: const [],
ideas: const [],
reminders: const [],
tasks: const [],
);
final signals = SignalsFeedSynthesizer.synthesize(
state: state,
now: DateTime(2026, 4, 17),
);
expect(signals, isNotEmpty);
expect(signals.first.title, 'Check in with Alex');
expect(
signals.first.metadata?[signalMetadataActionKey],
createReminderSignalAction,
);
},
);
test(
'suppresses stale check-in signal when a nearby reminder already exists',
() {
final LocalDataState state = LocalDataState(
people: <PersonProfile>[
PersonProfile(
id: 'p-1',
name: 'Alex',
relationship: 'Friend',
affinityScore: 80,
nextMoment: DateTime(2026, 4, 30),
tags: const <String>[],
notes: '',
lastInteractedAt: DateTime(2026, 4, 1),
),
],
moments: const [],
ideas: const [],
reminders: <ReminderRule>[
ReminderRule(
id: 'r-1',
personId: 'p-1',
title: 'Weekly check in',
cadence: ReminderCadence.weekly,
nextAt: DateTime(2026, 4, 18),
),
],
tasks: const [],
);
final signals = SignalsFeedSynthesizer.synthesize(
state: state,
now: DateTime(2026, 4, 17),
);
expect(
signals.where((signal) => signal.title.contains('Check in')),
isEmpty,
);
},
);
test('creates an upcoming date signal with idea count context', () {
final DateTime now = DateTime(2026, 4, 17);
final LocalDataState state = LocalDataState(
people: <PersonProfile>[
PersonProfile(
id: 'p-1',
name: 'Mila',
relationship: 'Sister',
affinityScore: 88,
nextMoment: DateTime(2026, 4, 25),
tags: const <String>[],
notes: '',
lastInteractedAt: DateTime(2026, 4, 16),
),
],
moments: const [],
ideas: <RelationshipIdea>[
RelationshipIdea(
id: 'i-1',
personId: 'p-1',
type: IdeaType.gift,
title: 'Plant stand',
details: 'Oak finish',
createdAt: DateTime(2026, 4, 10),
),
],
reminders: const [],
tasks: const [],
importantDates: <PersonImportantDate>[
PersonImportantDate(
id: 'd-1',
personId: 'p-1',
label: 'Birthday',
date: now.add(const Duration(days: 3)),
classification: 'birthday',
sourceKind: CaptureSourceKind.manual,
createdAt: now.subtract(const Duration(days: 1)),
updatedAt: now,
),
],
);
final signals = SignalsFeedSynthesizer.synthesize(state: state, now: now);
expect(
signals.any(
(signal) => signal.title.contains('Birthday for Mila is in 3 days'),
),
isTrue,
);
});
}