import 'package:flutter_test/flutter_test.dart'; import 'package:social_app/core/api/mock_api_client.dart'; import 'package:social_app/features/calendar/data/calendar_api.dart'; import 'package:social_app/features/calendar/data/models/schedule_item_model.dart'; void main() { group('CalendarApi', () { test('listByRange parses metadata and attachments', () async { final client = MockApiClient(); client.registerPatternHandler( RegExp(r'^/api/v1/schedule-items\?.*$'), 'GET', (_) => [ { 'id': 'evt_1', 'title': '晨会', 'description': '同步', 'start_at': '2026-03-11T01:00:00Z', 'end_at': '2026-03-11T02:00:00Z', 'timezone': 'Asia/Shanghai', 'metadata': { 'color': '#4F46E5', 'location': '会议室A', 'notes': '带电脑', 'reminder_minutes': 15, 'attachments': [ { 'name': '议程文档', 'visible_to': ['u1'], 'url': 'https://example.com/a', 'note': '会前阅读', 'content': null, 'type': 'document', }, ], 'version': 1, 'new_field': 'future', }, 'status': 'active', 'source_type': 'manual', 'created_at': '2026-03-10T01:00:00Z', 'updated_at': '2026-03-10T01:30:00Z', }, ], ); final api = CalendarApi(client); final result = await api.listByRange( startAt: DateTime.utc(2026, 3, 1), endAt: DateTime.utc(2026, 3, 31, 23, 59, 59), ); expect(result, hasLength(1)); expect(result.first.metadata?.attachments, hasLength(1)); expect(result.first.metadata?.raw['new_field'], 'future'); expect(result.first.metadata?.reminderMinutes, 15); expect(result.first.startAt.isUtc, isFalse); }); test('create serializes full metadata', () async { final client = MockApiClient(); client.registerHandler('/api/v1/schedule-items', 'POST', (request) { final body = request.data as Map; expect(body['metadata']['version'], 1); expect(body['metadata']['reminder_minutes'], 15); expect(body['metadata']['attachments'], isA>()); return { 'id': 'evt_2', ...body, 'status': 'active', 'source_type': 'manual', 'created_at': '2026-03-10T01:00:00Z', 'updated_at': '2026-03-10T01:00:00Z', }; }); final api = CalendarApi(client); final created = await api.create( ScheduleItemModel( id: 'evt_local', ownerId: 'user-1', title: '评审', startAt: DateTime.utc(2026, 3, 11, 3), endAt: DateTime.utc(2026, 3, 11, 4), metadata: ScheduleMetadata( color: '#F59E0B', location: '线上', notes: '准备 demo', attachments: [Attachment(name: 'PRD', type: 'document')], reminderMinutes: 15, version: 1, ), ), ); expect(created.id, 'evt_2'); expect(created.metadata?.location, '线上'); }); test('update does not send unknown metadata fields', () async { final client = MockApiClient(); client.registerHandler('/api/v1/schedule-items/evt_3', 'PATCH', ( request, ) { final body = request.data as Map; final metadata = body['metadata'] as Map; expect(metadata.containsKey('new_field'), isFalse); expect(metadata['reminder_minutes'], 30); return { 'id': 'evt_3', ...body, 'status': 'active', 'source_type': 'manual', 'created_at': '2026-03-10T01:00:00Z', 'updated_at': '2026-03-11T01:00:00Z', }; }); final api = CalendarApi(client); final event = ScheduleItemModel( id: 'evt_3', ownerId: 'user-1', title: '同步会', startAt: DateTime.utc(2026, 3, 11, 1), metadata: ScheduleMetadata.fromJson({ 'color': '#3B82F6', 'location': '会议室B', 'notes': '更新周报', 'attachments': const [], 'version': 1, 'reminder_minutes': 30, 'new_field': 'future', }), ); final updated = await api.update(event); expect(updated.id, 'evt_3'); }); }); }