feat: 实现站内通知系统
- 后端: 新增 notifications/user_notifications 表迁移及 ORM 模型
- 后端: 实现 schema/repository/service/router 全套通知 API
- GET /api/v1/notifications (列表+游标分页)
- GET /api/v1/notifications/unread-count
- PATCH /api/v1/notifications/{id}/read (幂等)
- PATCH /api/v1/notifications/mark-all-read (幂等)
- 后端: payload 使用 Pydantic discriminated union (none/open_route/open_url)
- 后端: 19 个单元测试全部通过
- Flutter: 通知 feature 完整实现 (models/apis/repositories/bloc/UI)
- Flutter: Home 页通知按钮接入真实页面,显示未读 badge
- Flutter: 14 个测试全部通过
- 协议文档: notification-inbox-protocol.md 及错误码注册
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:meeyao_qianwen/features/notifications/data/models/notification_payload.dart';
|
||||
|
||||
void main() {
|
||||
group('parseNotificationPayload', () {
|
||||
test('parses none action', () {
|
||||
final payload = parseNotificationPayload({'action': 'none'});
|
||||
expect(payload, isA<NotificationPayloadNone>());
|
||||
});
|
||||
|
||||
test('parses open_route action with all fields', () {
|
||||
final payload = parseNotificationPayload({
|
||||
'action': 'open_route',
|
||||
'route': '/history',
|
||||
'entityId': 'abc-123',
|
||||
'tab': 'details',
|
||||
});
|
||||
expect(payload, isA<NotificationPayloadRoute>());
|
||||
final routePayload = payload as NotificationPayloadRoute;
|
||||
expect(routePayload.route, '/history');
|
||||
expect(routePayload.entityId, 'abc-123');
|
||||
expect(routePayload.tab, 'details');
|
||||
});
|
||||
|
||||
test('parses open_route action with minimal fields', () {
|
||||
final payload = parseNotificationPayload({
|
||||
'action': 'open_route',
|
||||
'route': '/settings',
|
||||
});
|
||||
expect(payload, isA<NotificationPayloadRoute>());
|
||||
final routePayload = payload as NotificationPayloadRoute;
|
||||
expect(routePayload.route, '/settings');
|
||||
expect(routePayload.entityId, isNull);
|
||||
expect(routePayload.tab, isNull);
|
||||
});
|
||||
|
||||
test('parses open_url action', () {
|
||||
final payload = parseNotificationPayload({
|
||||
'action': 'open_url',
|
||||
'url': 'https://example.com',
|
||||
});
|
||||
expect(payload, isA<NotificationPayloadUrl>());
|
||||
final urlPayload = payload as NotificationPayloadUrl;
|
||||
expect(urlPayload.url, 'https://example.com');
|
||||
});
|
||||
|
||||
test('unknown action defaults to none', () {
|
||||
final payload = parseNotificationPayload({'action': 'unknown'});
|
||||
expect(payload, isA<NotificationPayloadNone>());
|
||||
});
|
||||
|
||||
test('missing action defaults to none', () {
|
||||
final payload = parseNotificationPayload({});
|
||||
expect(payload, isA<NotificationPayloadNone>());
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user