feat: 进行功能分区方便后期维护
- 添加导航条目和分类数据模型 - 实现导航卡片网格展示 - 支持点击卡片打开链接 - 添加主题样式(渐变色、卡片阴影) - 区分系统默认和自定义条目 - 添加分类统计信息"
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:frontend/features/home/data/mock_home_repository.dart';
|
||||
import 'package:frontend/features/home/domain/models/home_data.dart';
|
||||
import 'package:frontend/features/home/domain/models/link_item.dart';
|
||||
import 'package:frontend/features/home/domain/models/link_section.dart';
|
||||
import 'package:frontend/features/home/domain/models/nav_node.dart';
|
||||
|
||||
void main() {
|
||||
const MockHomeRepository repository = MockHomeRepository();
|
||||
final HomeData data = repository.fetchHomeData();
|
||||
|
||||
group('导航树(对照 index3.html 的 nav-group)', () {
|
||||
test('三个一级条目:一个直接跳转,两个可展开分组', () {
|
||||
expect(
|
||||
data.navNodes.map((NavNode node) => node.title),
|
||||
<String>['常用推荐', '素材资源', '开发工具'],
|
||||
);
|
||||
expect(data.navNodes[0].isGroup, isFalse);
|
||||
expect(data.navNodes[1].children.length, 3);
|
||||
expect(data.navNodes[2].children.length, 2);
|
||||
});
|
||||
|
||||
test('叶子 id 与原型里的锚点一致', () {
|
||||
expect(
|
||||
data.navLeaves.map((NavNode node) => node.id),
|
||||
<String>['common', 'design', 'icon', 'stock', 'dev', 'api'],
|
||||
);
|
||||
});
|
||||
|
||||
test('active 固定取第一个条目', () {
|
||||
expect(data.activeSectionId, 'common');
|
||||
});
|
||||
});
|
||||
|
||||
group('内容区(对照 index3.html 的两段内容)', () {
|
||||
test('只有两个分区', () {
|
||||
expect(
|
||||
data.sections.map((LinkSection s) => s.title),
|
||||
<String>['常用推荐', '素材资源 - UI 设计'],
|
||||
);
|
||||
});
|
||||
|
||||
test('两个分区共五张卡片,与原型的卡片数一致', () {
|
||||
expect(data.sectionById('common')!.items, hasLength(3));
|
||||
expect(data.sectionById('design')!.items, hasLength(2));
|
||||
expect(data.itemCount, 5);
|
||||
expect(data.allItems, hasLength(5));
|
||||
});
|
||||
|
||||
test('原型里没有对应元素的锚点取不到分区', () {
|
||||
for (final String id in <String>['icon', 'stock', 'dev', 'api']) {
|
||||
expect(data.sectionById(id), isNull, reason: '$id 不应该有内容');
|
||||
}
|
||||
});
|
||||
|
||||
test('分区 id 不重复', () {
|
||||
final Set<String> ids = data.sections
|
||||
.map((LinkSection s) => s.id)
|
||||
.toSet();
|
||||
expect(ids, hasLength(data.sections.length));
|
||||
});
|
||||
|
||||
test('条目字段完整且地址合法', () {
|
||||
for (final LinkItem item in data.allItems) {
|
||||
expect(item.id, isNotEmpty);
|
||||
expect(item.title, isNotEmpty);
|
||||
expect(item.description, isNotEmpty);
|
||||
expect(item.url, startsWith('https://'));
|
||||
expect(item.host, isNotEmpty);
|
||||
}
|
||||
});
|
||||
|
||||
test('条目 id 全局唯一', () {
|
||||
final List<String> ids = data.allItems
|
||||
.map((LinkItem item) => item.id)
|
||||
.toList();
|
||||
expect(ids.toSet(), hasLength(ids.length));
|
||||
});
|
||||
});
|
||||
|
||||
group('LinkItem.initial', () {
|
||||
test('英文取首字母并大写', () {
|
||||
expect(
|
||||
const LinkItem(id: 'a', title: 'github', url: 'https://a.com').initial,
|
||||
'G',
|
||||
);
|
||||
});
|
||||
|
||||
test('中文取第一个字,不会被截成半个字符', () {
|
||||
expect(
|
||||
const LinkItem(id: 'a', title: '知乎', url: 'https://a.com').initial,
|
||||
'知',
|
||||
);
|
||||
});
|
||||
|
||||
test('空标题有兜底字符', () {
|
||||
expect(
|
||||
const LinkItem(id: 'a', title: '', url: 'https://a.com').initial,
|
||||
'·',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('NavNode.shortLabel', () {
|
||||
test('取首字', () {
|
||||
expect(const NavNode(id: 'x', title: '素材资源').shortLabel, '素');
|
||||
expect(const NavNode(id: 'x', title: 'GitHub').shortLabel, 'G');
|
||||
expect(const NavNode(id: 'x', title: '').shortLabel, '·');
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user