From b615a70a44ec57b340b504f015110ee5ba83b659 Mon Sep 17 00:00:00 2001 From: lili Date: Sun, 21 Jun 2026 01:09:51 -0700 Subject: [PATCH] =?UTF-8?q?fix(studio):=20work=20=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E8=A1=A5=20commandId=20+=20D1=20work-schema=20e2e=20=E7=9C=9F?= =?UTF-8?q?=E8=B7=91[P1]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit D1-4 e2e 真跑暴露既有缺陷:useWorkCreate 漏传 commandId(后端 @NotBlank),真实后端 400(vitest mock 不校验故长期潜伏,work 创建此前无真实 e2e)。补 crypto.randomUUID() 幂等键。 新增 work-schema-binding.spec.ts 端到端验证 D1 链路:真实 GET /works/schema-options 200 渲染 Schema 下拉 → 真实 POST /works 200 + workSchemaId 字段贯通前后端。 验证:e2e 1 passed(真实后端,新 jar 含 D1-1/2/3);vitest useWorks 6/6 不破。 Co-Authored-By: Claude Opus 4.8 (1M context) --- muse-studio/e2e/work-schema-binding.spec.ts | 53 +++++++++++++++++++ .../src/features/editor/hooks/useWorks.ts | 3 +- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 muse-studio/e2e/work-schema-binding.spec.ts diff --git a/muse-studio/e2e/work-schema-binding.spec.ts b/muse-studio/e2e/work-schema-binding.spec.ts new file mode 100644 index 00000000..6477d701 --- /dev/null +++ b/muse-studio/e2e/work-schema-binding.spec.ts @@ -0,0 +1,53 @@ +import { expect, test, type Page } from '@playwright/test'; + +/** + * 作品创建时绑定 Meta Schema 的 e2e(真实后端,MSW off)。 + * + * 覆盖 D1 链路端到端:打开新建作品弹窗 → 真实 GET /works/schema-options 渲染 Schema 下拉 → + * 真实 POST /works 创建。不依赖 DB 是否已 seed active schema(无 schema 时走"不绑定"基线,链路仍通)。 + */ +const TOKEN = 'test1'; + +async function seedToken(page: Page): Promise { + await page.addInitScript((t) => { + window.localStorage.setItem('accessToken', t); + window.localStorage.setItem('tenantId', '1'); + }, TOKEN); +} + +test('用户新建作品时可见 Schema 选择并经真实后端创建', async ({ page }) => { + await seedToken(page); + const uniqueTitle = `Schema作品-e2e-${Date.now()}`; + + await page.goto('/'); + await expect(page.getByRole('heading', { name: '我的创作台' })).toBeVisible({ timeout: 15_000 }); + + // 打开新建作品弹窗(有作品→"新建作品",空状态→"立即创建",均触发同一弹窗),并捕获真实 schema-options 请求。 + const schemaOptionsPromise = page.waitForResponse((r) => + r.url().includes('/works/schema-options') && r.request().method() === 'GET' + ); + await page.getByRole('button', { name: /新建作品|立即创建/ }).first().click(); + + // D1-4:schema-options 经真实后端 200(端到端打通,非 mock);Schema 下拉渲染。 + const schemaOptionsResp = await schemaOptionsPromise; + expect(schemaOptionsResp.status()).toBe(200); + const schemaSelect = page.getByLabel('作品结构 Schema'); + await expect(schemaSelect).toBeVisible({ timeout: 15_000 }); + + // 填标题并创建(不绑定 schema 走基线,验证 work 创建链路在带 schema 字段后仍通)。 + await page.getByPlaceholder('请输入小说或书籍的标题,例如:星海迷途').fill(uniqueTitle); + const createResponsePromise = page.waitForResponse((response) => + response.url().includes('/app-api/muse/works') && + response.request().method() === 'POST' + ); + await page.getByRole('button', { name: '确认创建' }).click(); + + const createResponse = await createResponsePromise; + // work 创建成功为 HTTP 200(CommonResult success;区别于 agent 创建的 201)。 + expect(createResponse.status()).toBe(200); + const createBody = await createResponse.json(); + expect(createBody.code).toBe(0); + expect(createBody.data?.id).toBeTruthy(); + // 作品创建成功后 workSchemaId 字段存在(本用例不绑定故为 null,验证 D1 字段贯通前后端)。 + expect(createBody.data).toHaveProperty('workSchemaId'); +}); diff --git a/muse-studio/src/features/editor/hooks/useWorks.ts b/muse-studio/src/features/editor/hooks/useWorks.ts index d0ec1d3b..47b0e4cc 100644 --- a/muse-studio/src/features/editor/hooks/useWorks.ts +++ b/muse-studio/src/features/editor/hooks/useWorks.ts @@ -46,7 +46,8 @@ export function useWorkCreate() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (dto: { title: string; genre?: string; description?: string; schemaId?: number }) => - api.post('/works', dto), + // commandId 幂等键:后端 @NotBlank 必填(此前前端漏传致真实后端 400,D1-4 e2e 真跑暴露),前端生成 UUID 补齐。 + api.post('/works', { ...dto, commandId: crypto.randomUUID() }), onSuccess: () => { // 标记作品列表缓存失效,触发重新获取最新列表 queryClient.invalidateQueries({ queryKey: ['works'] });