feat: 重构项目心跳数据结构并实现项目列表API
- 新增统一项目列表Redis键和迁移工具 - 实现GET /api/projects端点获取项目列表 - 实现POST /api/projects/migrate端点支持数据迁移 - 更新前端ProjectSelector组件使用真实项目数据 - 扩展projectStore状态管理 - 更新相关文档和OpenSpec规范 - 添加测试用例验证新功能
This commit is contained in:
62
src/backend/routes/projects.integration.test.js
Normal file
62
src/backend/routes/projects.integration.test.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import request from 'supertest';
|
||||
|
||||
import { createApp } from '../app.js';
|
||||
import { createFakeRedis } from '../test/fakeRedis.js';
|
||||
|
||||
describe('projects API', () => {
|
||||
it('GET /api/projects returns projects from unified list', async () => {
|
||||
const now = Date.now();
|
||||
const redis = createFakeRedis({
|
||||
项目心跳: JSON.stringify([
|
||||
{ projectName: 'Demo', apiBaseUrl: 'http://localhost:8080', lastActiveAt: now },
|
||||
]),
|
||||
});
|
||||
|
||||
const app = createApp({ redis });
|
||||
const resp = await request(app).get('/api/projects');
|
||||
|
||||
expect(resp.status).toBe(200);
|
||||
expect(resp.body.success).toBe(true);
|
||||
expect(resp.body.count).toBe(1);
|
||||
expect(resp.body.projects[0]).toMatchObject({
|
||||
id: 'Demo',
|
||||
name: 'Demo',
|
||||
apiBaseUrl: 'http://localhost:8080',
|
||||
});
|
||||
expect([ 'online', 'offline', 'unknown' ]).toContain(
|
||||
resp.body.projects[0].status,
|
||||
);
|
||||
});
|
||||
|
||||
it('POST /api/projects/migrate migrates old *_项目心跳 keys into 项目心跳 list', async () => {
|
||||
const now = Date.now();
|
||||
const redis = createFakeRedis({
|
||||
'A_项目心跳': JSON.stringify({
|
||||
apiBaseUrl: 'http://a',
|
||||
lastActiveAt: now,
|
||||
}),
|
||||
});
|
||||
|
||||
const app = createApp({ redis });
|
||||
const resp = await request(app)
|
||||
.post('/api/projects/migrate')
|
||||
.send({ dryRun: false, deleteOldKeys: true });
|
||||
|
||||
expect(resp.status).toBe(200);
|
||||
expect(resp.body.success).toBe(true);
|
||||
expect(resp.body.migrated).toBe(1);
|
||||
|
||||
const listRaw = await redis.get('项目心跳');
|
||||
expect(typeof listRaw).toBe('string');
|
||||
const list = JSON.parse(listRaw);
|
||||
expect(Array.isArray(list)).toBe(true);
|
||||
expect(list[0]).toMatchObject({
|
||||
projectName: 'A',
|
||||
apiBaseUrl: 'http://a',
|
||||
});
|
||||
|
||||
const old = await redis.get('A_项目心跳');
|
||||
expect(old).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user