fix(studio): work 创建补 commandId + D1 work-schema e2e 真跑[P1]
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) <noreply@anthropic.com>
This commit is contained in:
parent
1dc1c3af2b
commit
b615a70a44
53
muse-studio/e2e/work-schema-binding.spec.ts
Normal file
53
muse-studio/e2e/work-schema-binding.spec.ts
Normal file
@ -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<void> {
|
||||
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');
|
||||
});
|
||||
@ -46,7 +46,8 @@ export function useWorkCreate() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (dto: { title: string; genre?: string; description?: string; schemaId?: number }) =>
|
||||
api.post<WorkVO>('/works', dto),
|
||||
// commandId 幂等键:后端 @NotBlank 必填(此前前端漏传致真实后端 400,D1-4 e2e 真跑暴露),前端生成 UUID 补齐。
|
||||
api.post<WorkVO>('/works', { ...dto, commandId: crypto.randomUUID() }),
|
||||
onSuccess: () => {
|
||||
// 标记作品列表缓存失效,触发重新获取最新列表
|
||||
queryClient.invalidateQueries({ queryKey: ['works'] });
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user