/** * 发布流程集成测试 * 测试发布→可见性完整流程 */ import { describe, it, expect, beforeAll } from 'vitest'; import { apiGet, apiPost, apiPut, apiDelete, setAuthToken, initHttpClient, createTestUser } from '../../integration/http-client'; describe('发布流程集成测试', () => { let authToken: string; let userId: string; let testBookId: number; beforeAll(async () => { try { const user = await createTestUser(); authToken = user.token; userId = user.userId; setAuthToken(authToken); } catch (e) { console.log('创建测试用户失败,跳过部分测试'); } }); describe('Step 1: 创建可发布的内容', () => { it('创建书籍', async () => { if (!authToken) return; const res = await apiPost('/api/book-generator/langgraph/create', { title: `发布测试书籍_${Date.now()}`, topic: '测试主题', wordCount: 10000, strategy: 'deep-plan-parallel', }); expect(res.code).toBe(0); expect(res.data?.bookId).toBeDefined(); testBookId = res.data?.bookId; }); it('新创建书籍初始状态为草稿', async () => { if (!authToken || !testBookId) return; const res = await apiGet(`/api/book-generator/langgraph/books/${testBookId}`); expect(res.code).toBe(0); // 初始状态应该是 draft 或类似 expect(res.data?.status).toBeDefined(); }); }); describe('Step 2: 发布状态管理', () => { it('获取当前发布状态', async () => { if (!authToken || !testBookId) return; const res = await apiGet(`/api/book-generator/langgraph/books/${testBookId}`); expect(res.code).toBe(0); expect(res.data).toHaveProperty('status'); }); it('发布书籍', async () => { if (!authToken || !testBookId) return; const res = await apiPut(`/api/book-generator/langgraph/books/${testBookId}/publish`); // 发布可能因状态限制返回不同结果,但不应是认证/权限错误 expect(res.code).toBeDefined(); expect([401, 403]).not.toContain(res.code); }); it('已发布书籍状态更新', async () => { if (!authToken || !testBookId) return; const res = await apiGet(`/api/book-generator/langgraph/books/${testBookId}`); expect(res.code).toBe(0); // 发布后状态应该变化 expect(res.data?.status).toBeDefined(); }); it('取消发布', async () => { if (!authToken || !testBookId) return; // 再次调用发布接口应该可以切换状态 const res = await apiPut(`/api/book-generator/langgraph/books/${testBookId}/publish`); // 发布/取消发布返回结果取决于当前状态,但不应是认证/权限错误 expect(res.code).toBeDefined(); expect([401, 403]).not.toContain(res.code); }); }); describe('Step 3: 发布可见性验证', () => { it('发布的书籍在列表中可见', async () => { if (!authToken) return; const res = await apiGet('/api/book-generator/langgraph/books'); expect(res.code).toBe(0); expect(Array.isArray(res.data?.books)).toBe(true); // 如果之前发布了书籍,列表中应该能看到 if (testBookId) { const found = res.data?.books?.some((b: any) => b.id === testBookId); expect(found).toBe(true); } }); it('搜索接口能查到已发布内容', async () => { if (!authToken) return; // 搜索接口 const res = await apiGet('/api/search', { keyword: '测试' }); // 搜索可能返回任何结果 expect(res.code).toBeDefined(); }); }); describe('Step 4: 发布权限验证', () { it('未登录用户无法发布', async () => { // 设置无效 token setAuthToken('invalid_token'); const res = await apiPut(`/api/book-generator/langgraph/books/${testBookId}/publish`); expect(res.code).not.toBe(0); }); it('无书籍所有权的用户无法发布', async () => { if (!authToken) return; // 尝试发布不属于自己的书籍(ID 不存在或属于其他用户) const res = await apiPut('/api/book-generator/langgraph/books/99999/publish'); // 应该返回权限错误(403)或不存在(404),不应成功(0) expect([401, 403, 404]).toContain(res.code); expect(res.code).not.toBe(0); }); }); describe('Step 5: 发布后清理', () => { it('删除已发布的书籍', async () => { if (!authToken || !testBookId) return; const res = await apiDelete(`/api/book-generator/langgraph/books/${testBookId}`); // 删除成功或返回权限错误(403)/不存在(404),不应是认证错误(401) expect(res.code).toBeDefined(); expect(res.code).not.toBe(401); }); it('删除后列表中不再可见', async () => { if (!authToken || !testBookId) return; const res = await apiGet('/api/book-generator/langgraph/books'); expect(res.code).toBe(0); // 被删除的书籍不应该在列表中 const found = res.data?.books?.some((b: any) => b.id === testBookId); // 删除后可能返回 404 或列表中不存在 expect(found).toBe(false); }); }); });