111 lines
3.6 KiB
Dart
111 lines
3.6 KiB
Dart
|
|
/// 照片域模型往返测试(P3 计划 Task 2)。
|
|||
|
|
///
|
|||
|
|
/// fixture 来源(字段逐一转写):
|
|||
|
|
/// - openapi.yaml components.schemas.PhotoRecord / AdminPhoto /
|
|||
|
|
/// AdminPhotoUploader / PhotoVisibility / PhotoProcessingState;
|
|||
|
|
/// - services/api/test/photos-admin.e2e-spec.ts 的 ADMIN_PHOTO_KEYS
|
|||
|
|
/// (PhotoRecord 必返字段 + uploader 内嵌)与种子形态
|
|||
|
|
/// (visibility=published / processingState=ready、categoryId 可空、
|
|||
|
|
/// displayName 取资料字段而非账号)。
|
|||
|
|
library;
|
|||
|
|
|
|||
|
|
import 'package:flutter_test/flutter_test.dart';
|
|||
|
|
import 'package:photo_live/features/photos/models.dart';
|
|||
|
|
|
|||
|
|
final Map<String, dynamic> photoRecordFixture = <String, dynamic>{
|
|||
|
|
'photoId': 'pa-photo-p1',
|
|||
|
|
'albumId': 'cktragt000001',
|
|||
|
|
'categoryId': 'ckucat0000001',
|
|||
|
|
'uploaderId': 'usr-col-02',
|
|||
|
|
'visibility': 'published',
|
|||
|
|
'processingState': 'ready',
|
|||
|
|
'bytes': 4096000,
|
|||
|
|
'width': 4032,
|
|||
|
|
'height': 3024,
|
|||
|
|
'shotAt': '2026-09-12T07:55:00.000Z',
|
|||
|
|
'uploadedAt': '2026-09-12T08:05:00.000Z',
|
|||
|
|
'publishedAt': '2026-09-12T08:06:00.000Z',
|
|||
|
|
'likeCount': 3,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
void main() {
|
|||
|
|
test('PhotoRecord fromJson/toJson 往返(管理端全字段)', () {
|
|||
|
|
final model = PhotoRecord.fromJson(photoRecordFixture);
|
|||
|
|
expect(model.visibility, PhotoVisibility.published);
|
|||
|
|
expect(model.processingState, PhotoProcessingState.ready);
|
|||
|
|
expect(model.likeCount, 3);
|
|||
|
|
expect(model.toJson(), equals(photoRecordFixture));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('PhotoRecord 可空字段:处理前宽高为 null、未发布为 null', () {
|
|||
|
|
final fixture = {
|
|||
|
|
...photoRecordFixture,
|
|||
|
|
'categoryId': null,
|
|||
|
|
'width': null,
|
|||
|
|
'height': null,
|
|||
|
|
'shotAt': null,
|
|||
|
|
'publishedAt': null,
|
|||
|
|
'visibility': 'unpublished',
|
|||
|
|
'processingState': 'uploaded',
|
|||
|
|
};
|
|||
|
|
final model = PhotoRecord.fromJson(fixture);
|
|||
|
|
expect(model.categoryId, isNull);
|
|||
|
|
expect(model.width, isNull);
|
|||
|
|
expect(model.height, isNull);
|
|||
|
|
expect(model.shotAt, isNull);
|
|||
|
|
expect(model.publishedAt, isNull);
|
|||
|
|
expect(model.visibility, PhotoVisibility.unpublished);
|
|||
|
|
expect(model.processingState, PhotoProcessingState.uploaded);
|
|||
|
|
expect(model.toJson(), equals(fixture));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('PhotoRecord 解析毫秒精度时间(服务端 Date.toISOString 形态)', () {
|
|||
|
|
final model = PhotoRecord.fromJson({
|
|||
|
|
...photoRecordFixture,
|
|||
|
|
'uploadedAt': '2026-09-12T08:05:00.000Z',
|
|||
|
|
});
|
|||
|
|
expect(model.uploadedAt, DateTime.utc(2026, 9, 12, 8, 5));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('AdminPhoto fromJson/toJson 往返(PhotoRecord + uploader 内嵌)', () {
|
|||
|
|
final fixture = {
|
|||
|
|
...photoRecordFixture,
|
|||
|
|
'uploader': {
|
|||
|
|
'userId': 'usr-col-02',
|
|||
|
|
'account': 'collab01',
|
|||
|
|
'displayName': '李四',
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
final model = AdminPhoto.fromJson(fixture);
|
|||
|
|
// e2e:uploader 映射取的是资料 displayName,而非账号。
|
|||
|
|
expect(model.uploader.displayName, '李四');
|
|||
|
|
expect(model.uploader.userId, model.uploaderId);
|
|||
|
|
expect(model.toJson(), equals(fixture));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('PhotoVisibility / PhotoProcessingState 全枚举解析', () {
|
|||
|
|
for (final value in const [
|
|||
|
|
'unpublished',
|
|||
|
|
'published',
|
|||
|
|
'hidden',
|
|||
|
|
'deleted',
|
|||
|
|
]) {
|
|||
|
|
expect(PhotoVisibility.fromJson(value).wire, value);
|
|||
|
|
}
|
|||
|
|
for (final value in const [
|
|||
|
|
'pending_upload',
|
|||
|
|
'uploaded',
|
|||
|
|
'processing',
|
|||
|
|
'ready',
|
|||
|
|
'processing_failed',
|
|||
|
|
]) {
|
|||
|
|
expect(PhotoProcessingState.fromJson(value).wire, value);
|
|||
|
|
}
|
|||
|
|
expect(() => PhotoVisibility.fromJson('archived'), throwsFormatException);
|
|||
|
|
expect(
|
|||
|
|
() => PhotoProcessingState.fromJson('failed'),
|
|||
|
|
throwsFormatException,
|
|||
|
|
);
|
|||
|
|
});
|
|||
|
|
}
|