Some checks failed
Deploy API Server / build-and-deploy (push) Failing after 33s
- ChatSession/ChatMessage/ChatCitation Prisma models - CAPI: create/list sessions, send message, get history, delete - Admin AAPI: view user sessions and messages - Content safety integration on user input - Placeholder RAG pipeline (real pipeline in M3) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
309 lines
12 KiB
TypeScript
309 lines
12 KiB
TypeScript
import { Test, TestingModule } from '@nestjs/testing';
|
|
import { INestApplication } from '@nestjs/common';
|
|
import request from 'supertest';
|
|
import { AppModule } from '../src/app.module';
|
|
|
|
describe('M2 E2E Tests', () => {
|
|
let app: INestApplication;
|
|
|
|
beforeAll(async () => {
|
|
const moduleFixture: TestingModule = await Test.createTestingModule({
|
|
imports: [AppModule],
|
|
}).compile();
|
|
app = moduleFixture.createNestApplication();
|
|
app.setGlobalPrefix('api', { exclude: ['admin-api/(.*)', 'internal/(.*)'] });
|
|
await app.init();
|
|
});
|
|
|
|
afterAll(async () => { await app.close(); });
|
|
|
|
async function loginAdmin(): Promise<string> {
|
|
const res = await request(app.getHttpServer())
|
|
.post('/admin-api/auth/login')
|
|
.send({ email: 'admin@zhixi.app', password: 'admin123' });
|
|
return res.body?.data?.accessToken || '';
|
|
}
|
|
|
|
// ══════════════════════════════════════════════
|
|
// M2-01: User & Account 深化
|
|
// ══════════════════════════════════════════════
|
|
describe('M2-01 User & Account Deepening', () => {
|
|
let token: string;
|
|
beforeAll(async () => { token = await loginAdmin(); });
|
|
|
|
// ── Admin membership management ──
|
|
|
|
it('GET /admin-api/users/memberships → 200 member list', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.get('/admin-api/users/memberships')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect(200);
|
|
expect(Array.isArray(res.body.data)).toBe(true);
|
|
});
|
|
|
|
it('POST /admin-api/users/memberships → 200 assign membership', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.post('/admin-api/users/memberships')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.send({ userId: 'user1', planId: 'plan-free' })
|
|
.expect([200, 201]);
|
|
expect(res.body.data).toHaveProperty('id');
|
|
});
|
|
|
|
// ── Admin deletion requests ──
|
|
|
|
it('GET /admin-api/users/deletion-requests → 200 list', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.get('/admin-api/users/deletion-requests')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect(200);
|
|
expect(Array.isArray(res.body.data)).toBe(true);
|
|
});
|
|
|
|
it('POST /admin-api/users/deletion-requests/:id/approve → approve', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.post('/admin-api/users/deletion-requests/test-id/approve')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect([200, 201]);
|
|
expect(res.body.data).toHaveProperty('status', 'completed');
|
|
});
|
|
|
|
it('POST /admin-api/users/deletion-requests/:id/reject → reject', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.post('/admin-api/users/deletion-requests/test-id2/reject')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect([200, 201]);
|
|
expect(res.body.data).toHaveProperty('status', 'cancelled');
|
|
});
|
|
|
|
// ── Admin device view ──
|
|
|
|
it('GET /admin-api/users/:userId/devices → 200 device list', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.get('/admin-api/users/user1/devices')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect(200);
|
|
expect(Array.isArray(res.body.data)).toBe(true);
|
|
});
|
|
});
|
|
|
|
// ══════════════════════════════════════════════
|
|
// M2-02: Workspace & KnowledgeBase
|
|
// ══════════════════════════════════════════════
|
|
describe('M2-02 Workspace & KnowledgeBase', () => {
|
|
let token: string;
|
|
beforeAll(async () => { token = await loginAdmin(); });
|
|
|
|
it('POST /api/knowledge-bases → 201 create KB', async () => {
|
|
const res = await request(app.getHttpServer())
|
|
.post('/api/knowledge-bases')
|
|
.send({ title: 'E2E Test KB', description: 'test' })
|
|
.expect([200, 201]);
|
|
expect(res.body.data).toHaveProperty('id');
|
|
});
|
|
|
|
it('GET /api/knowledge-bases/:id/folders → 200 folder list', async () => {
|
|
const kb = await request(app.getHttpServer())
|
|
.post('/api/knowledge-bases')
|
|
.send({ title: 'Folder Test', description: 'test' });
|
|
const kbId = kb.body?.data?.id;
|
|
if (!kbId) return;
|
|
|
|
const res = await request(app.getHttpServer())
|
|
.get(`/api/knowledge-bases/${kbId}/folders`)
|
|
.expect(200);
|
|
expect(Array.isArray(res.body.data)).toBe(true);
|
|
});
|
|
|
|
it('POST /api/knowledge-bases/:id/folders → 201 create folder', async () => {
|
|
const kb = await request(app.getHttpServer())
|
|
.post('/api/knowledge-bases')
|
|
.send({ title: 'Folder Create Test', description: 'test' });
|
|
const kbId = kb.body?.data?.id;
|
|
if (!kbId) return;
|
|
|
|
const res = await request(app.getHttpServer())
|
|
.post(`/api/knowledge-bases/${kbId}/folders`)
|
|
.send({ name: 'Chapter 1' })
|
|
.expect([200, 201]);
|
|
expect(res.body.data).toHaveProperty('id');
|
|
});
|
|
|
|
it('GET /admin-api/knowledge-bases → 200 admin KB list', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.get('/admin-api/knowledge-bases')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect(200);
|
|
expect(res.body.data).toHaveProperty('items');
|
|
expect(res.body.data).toHaveProperty('total');
|
|
});
|
|
});
|
|
|
|
// ══════════════════════════════════════════════
|
|
// M2-03: Material & Source
|
|
// ══════════════════════════════════════════════
|
|
describe('M2-03 Material & Source', () => {
|
|
let token: string;
|
|
beforeAll(async () => { token = await loginAdmin(); });
|
|
|
|
it('POST /api/knowledge-bases/:kbId/sources → 201 add source', async () => {
|
|
const kb = await request(app.getHttpServer())
|
|
.post('/api/knowledge-bases')
|
|
.send({ title: 'Source Test KB', description: 'test' });
|
|
const kbId = kb.body?.data?.id;
|
|
if (!kbId) return;
|
|
|
|
const res = await request(app.getHttpServer())
|
|
.post(`/api/knowledge-bases/${kbId}/sources`)
|
|
.send({ type: 'file', title: 'Test PDF', originalFilename: 'test.pdf', mimeType: 'application/pdf' })
|
|
.expect([200, 201]);
|
|
expect(res.body.data).toHaveProperty('id');
|
|
});
|
|
|
|
it('GET /admin-api/knowledge-bases/:id/sources → 200 source list', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.get('/admin-api/knowledge-bases/kb-test/sources')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect(200);
|
|
expect(Array.isArray(res.body.data)).toBe(true);
|
|
});
|
|
|
|
it('GET /admin-api/knowledge-bases/sources/:sourceId/references → 200', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.get('/admin-api/knowledge-bases/sources/src-test/references')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect(200);
|
|
expect(Array.isArray(res.body.data)).toBe(true);
|
|
});
|
|
});
|
|
|
|
// ══════════════════════════════════════════════
|
|
// M2-04: Ingestion & Indexing
|
|
// ══════════════════════════════════════════════
|
|
describe('M2-04 Ingestion & Indexing', () => {
|
|
let token: string;
|
|
beforeAll(async () => { token = await loginAdmin(); });
|
|
|
|
it('POST /api/imports → 201 create import', async () => {
|
|
const res = await request(app.getHttpServer())
|
|
.post('/api/imports')
|
|
.send({ sourceType: 'file', sourceName: 'test.pdf', knowledgeBaseId: 'kb1', userId: 'user1' })
|
|
.expect([200, 201]);
|
|
expect(res.body.data).toHaveProperty('id');
|
|
});
|
|
|
|
it('GET /admin-api/imports → 200 import list', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.get('/admin-api/imports')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect(200);
|
|
expect(res.body.data).toHaveProperty('items');
|
|
expect(res.body.data).toHaveProperty('total');
|
|
});
|
|
|
|
it('GET /admin-api/imports → 401 without token', async () => {
|
|
await request(app.getHttpServer()).get('/admin-api/imports').expect(401);
|
|
});
|
|
|
|
it('GET /admin-api/imports/:id → 200 import detail', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.get('/admin-api/imports/test-id')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect(200);
|
|
expect(res.body.data).toHaveProperty('job');
|
|
});
|
|
|
|
it('POST /admin-api/imports/:id/retry → retry failed import', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.post('/admin-api/imports/test-id/retry')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect([200, 201]);
|
|
expect(res.body.success).toBe(true);
|
|
});
|
|
});
|
|
|
|
// ══════════════════════════════════════════════
|
|
// M2-05: Vector & Retrieval 对接
|
|
// ══════════════════════════════════════════════
|
|
describe('M2-05 Vector Integration', () => {
|
|
let token: string;
|
|
beforeAll(async () => { token = await loginAdmin(); });
|
|
|
|
it('VectorService collection accessible', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.get('/admin-api/vector/collection')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect(200);
|
|
expect(res.body.data).toHaveProperty('name');
|
|
});
|
|
|
|
it('VectorService count accessible', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.get('/admin-api/vector/count')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect(200);
|
|
expect(res.body.data).toHaveProperty('count');
|
|
});
|
|
});
|
|
|
|
// ══════════════════════════════════════════════
|
|
// M2-07: RAG Chat
|
|
// ══════════════════════════════════════════════
|
|
describe('M2-07 RAG Chat', () => {
|
|
let token: string;
|
|
beforeAll(async () => { token = await loginAdmin(); });
|
|
|
|
it('POST /api/rag-chat/sessions → 201 create session', async () => {
|
|
const res = await request(app.getHttpServer())
|
|
.post('/api/rag-chat/sessions')
|
|
.send({ knowledgeBaseId: 'kb1', title: 'Test Chat' })
|
|
.expect([200, 201]);
|
|
expect(res.body.data).toHaveProperty('id');
|
|
});
|
|
|
|
it('GET /api/rag-chat/sessions → 200 list sessions', async () => {
|
|
const res = await request(app.getHttpServer())
|
|
.get('/api/rag-chat/sessions')
|
|
.expect(200);
|
|
expect(Array.isArray(res.body.data)).toBe(true);
|
|
});
|
|
|
|
it('POST /api/rag-chat/sessions/:id/messages → send message', async () => {
|
|
const session = await request(app.getHttpServer())
|
|
.post('/api/rag-chat/sessions')
|
|
.send({ knowledgeBaseId: 'kb1' });
|
|
const sId = session.body?.data?.id;
|
|
if (!sId) return;
|
|
|
|
const res = await request(app.getHttpServer())
|
|
.post(`/api/rag-chat/sessions/${sId}/messages`)
|
|
.send({ content: '这个知识库的主要内容是什么?' })
|
|
.expect([200, 201]);
|
|
expect(res.body.data).toHaveProperty('message');
|
|
});
|
|
|
|
it('GET /admin-api/rag-chat/sessions → 200 admin sessions', async () => {
|
|
if (!token) return;
|
|
const res = await request(app.getHttpServer())
|
|
.get('/admin-api/rag-chat/sessions')
|
|
.set('Authorization', `Bearer ${token}`)
|
|
.expect(200);
|
|
expect(Array.isArray(res.body.data)).toBe(true);
|
|
});
|
|
});
|
|
});
|