Use account and content readiness throughout canvas integration navigation
creative workspace review checks / verify (pull_request) Has been cancelled

This commit is contained in:
2026-10-30 19:07:58 +08:00
parent fb6f29db76
commit f4f0d67306
3 changed files with 38 additions and 26 deletions
@@ -12,9 +12,10 @@ export async function verifyCanvasAgentUI(base:string){
const context=await browser.newContext({viewport:{width:1440,height:1000}}),errors:string[]=[];
try{
const page=await context.newPage();page.setDefaultTimeout(20000);page.on('pageerror',e=>errors.push(e.message));
await page.goto(base+'/',{waitUntil:'networkidle'});
await page.goto(base+'/',{waitUntil:'domcontentloaded'});
await page.getByRole('heading',{name:/想法不该停在对话里/,level:1}).waitFor();
await page.getByRole('link',{name:'开始创作',exact:true}).click();
await page.getByText('登录你的账户',{exact:true}).first().waitFor({state:'attached'});
await page.getByLabel('邮箱地址',{exact:true}).fill(email);
await page.getByLabel('密码',{exact:true}).fill(password);
await page.locator('form').getByRole('button',{name:'登录',exact:true}).click();
@@ -79,7 +80,8 @@ export async function verifyCanvasAgentUI(base:string){
assert.equal((await fetch(base+root,{headers:{authorization:second.authorization}})).status,404);
await page.setViewportSize({width:390,height:844});
const bounds=await panel.boundingBox();assert.ok(bounds&&bounds.x>=0&&bounds.x+bounds.width<=390,'Agent panel stays within the mobile viewport');
await page.reload({waitUntil:'networkidle'});
await page.reload({waitUntil:'domcontentloaded'});
await page.getByRole('link',{name:email,exact:true}).waitFor({state:'attached'});
await page.getByRole('button',{name:'Agent',exact:true}).click();
const reopened=page.getByRole('region',{name:'Agent 连接',exact:true});
await reopened.getByRole('combobox',{name:'打开在线画布',exact:true}).selectOption(list.canvases[0].id);
@@ -100,7 +100,23 @@ test(
const page = await context.newPage();
page.setDefaultTimeout(10000);
page.on("pageerror", (error) => errors.push(error.message));
await page.goto(base + "/documents", { waitUntil: "networkidle" });
const pending = new Set<string>(), network: string[] = [];
page.on("request", request => pending.add(request.url()));
page.on("requestfinished", request => pending.delete(request.url()));
page.on("requestfailed", request => {pending.delete(request.url());network.push(new URL(request.url()).pathname+": "+request.failure()?.errorText);});
async function navigate(url: string, reload = false) {
const session = page.waitForResponse(response => new URL(response.url()).pathname === "/api/account/session" && response.status() === 200);
try {
const [navigation] = await Promise.all([reload ? page.reload({waitUntil:"domcontentloaded"}) : page.goto(url,{waitUntil:"domcontentloaded"}),session]);
assert.ok(navigation?.ok(), "Navigation returns a successful document");
await page.getByText(signedIn ? "editor@example.com" : "登录你的账户",{exact:true}).first().waitFor({state:"attached"});
} catch (error) {
console.error("Workspace UI navigation diagnostics",JSON.stringify({url:page.url(),pending:[...pending].map(value=>new URL(value).pathname),network:network.slice(-20),errors,body:(await page.locator("body").innerText().catch(()=>"unavailable")).slice(0,1600)}));
throw error;
}
}
await navigate(base + "/documents");
await page
.getByRole("heading", { name: authored.title, exact: true })
.waitFor();
@@ -111,7 +127,8 @@ test(
await page
.getByRole("heading", { name: "没有匹配文档", exact: true })
.waitFor();
await page.reload({ waitUntil: "networkidle" });
await navigate(page.url(), true);
await page.getByRole("heading",{name:"没有匹配文档",exact:true}).waitFor();
assert.equal(await search.inputValue(), "不存在的文档");
await page
.getByRole("button", { name: "清除所有筛选", exact: true })
@@ -129,9 +146,7 @@ test(
fullPage: true,
});
}
await page.goto(base + "/guide/review-changes?revision=1", {
waitUntil: "networkidle",
});
await navigate(base + "/guide/review-changes?revision=1");
await page.getByRole("tab", { name: "XML 源文档" }).click();
assert.match(await page.locator("pre").innerText(), /linked-guidance/);
await page.getByRole("tab", { name: /版本记录/ }).click();
@@ -142,7 +157,7 @@ test(
path: process.env.WORKSPACE_SCREENSHOT_DIR + "/reader.png",
fullPage: true,
});
await page.goto(base + "/account", { waitUntil: "networkidle" });
await navigate(base + "/account");
await page.getByRole("button", { name: "创建账户", exact: true }).click();
await page.getByRole("heading", { name: "创建你的账户" }).waitFor();
await page
@@ -160,10 +175,10 @@ test(
path: process.env.WORKSPACE_SCREENSHOT_DIR + "/account.png",
fullPage: true,
});
await page.goto(base + "/write", { waitUntil: "networkidle" });
await navigate(base + "/write");
await page.getByRole("heading", { name: "登录后开始编写" }).waitFor();
signedIn = true;
await page.reload({ waitUntil: "networkidle" });
await navigate(page.url(), true);
await page.getByLabel("文档短名", { exact: true }).fill("workspace-test");
await page.getByLabel("标题", { exact: false }).fill("界面回归验证文档");
await page
@@ -213,16 +228,13 @@ test(
(published as Guidance).id,
"user-" + owner + "-workspace-test",
);
await page.goto(base + "/documents?scope=mine", {
waitUntil: "networkidle",
});
assert.equal(requestedAuthor, owner);
await navigate(base + "/documents?scope=mine");
await page
.getByRole("heading", { name: authored.title, exact: true })
.waitFor();
await page.goto(base + "/write?id=" + authored.id, {
waitUntil: "networkidle",
});
assert.equal(requestedAuthor, owner);
await navigate(base + "/write?id=" + authored.id);
await page.waitForFunction(title=>Array.from(document.querySelectorAll<HTMLInputElement>("input")).some(input=>input.value===title),authored.title);
assert.equal(
await page.getByLabel("文档短名", { exact: true }).isDisabled(),
true,
@@ -248,7 +260,7 @@ test(
"通过 XML 更新的文档",
);
await page.setViewportSize({ width: 390, height: 844 });
await page.goto(base + "/documents", { waitUntil: "networkidle" });
await navigate(base + "/documents");
assert.equal(
await page.evaluate(
() => document.documentElement.scrollWidth <= window.innerWidth,
@@ -269,9 +281,7 @@ test(
path: process.env.WORKSPACE_SCREENSHOT_DIR + "/mobile-directory.png",
fullPage: true,
});
await page.goto(base + "/guide/review-changes?revision=1", {
waitUntil: "networkidle",
});
await navigate(base + "/guide/review-changes?revision=1");
assert.equal(
await page.evaluate(
() => document.documentElement.scrollWidth <= window.innerWidth,
@@ -283,14 +293,14 @@ test(
path: process.env.WORKSPACE_SCREENSHOT_DIR + "/mobile-reader.png",
fullPage: true,
});
await page.goto(base + "/account", { waitUntil: "networkidle" });
await navigate(base + "/account");
assert.equal(
await page.evaluate(
() => document.documentElement.scrollWidth <= window.innerWidth,
),
true,
);
await page.goto(base + "/write", { waitUntil: "networkidle" });
await navigate(base + "/write");
await page.getByLabel("文档短名", { exact: true }).waitFor();
await page.getByRole("button", { name: "协议 XML", exact: true }).click();
await page.getByLabel("XML 输入").waitFor();
@@ -305,7 +315,7 @@ test(
path: process.env.WORKSPACE_SCREENSHOT_DIR + "/mobile-editor.png",
fullPage: true,
});
await page.goto(base + "/protocol", { waitUntil: "networkidle" });
await navigate(base + "/protocol");
assert.equal(
await page.evaluate(
() => document.documentElement.scrollWidth <= window.innerWidth,
@@ -22,7 +22,7 @@ import {verifyFlatNoteMigration} from './flat-note-migration';
import {staticEntries} from '../src/lib/explore';
import {publishLearningSeries} from '../src/lib/publish-learning-series';
test('real PostgreSQL + S3 notes, flat tags, resource sharing and video processing', {timeout:300000}, async()=>{
test('real PostgreSQL + S3 notes, flat tags, resource sharing and video processing', {timeout:600000}, async()=>{
assert.equal(process.env.PROMPT_INTEGRATION_TEST,'1','Run only against an explicitly isolated test database');
const socket=createServer();socket.listen(0,'127.0.0.1');await once(socket,'listening');const address=socket.address();assert.ok(address&&typeof address!=='string');const port=address.port;await new Promise<void>(r=>socket.close(()=>r()));
const external=process.env.PROMPT_TEST_BASE_URL;
@@ -39,7 +39,7 @@ test('real PostgreSQL + S3 notes, flat tags, resource sharing and video processi
await verifyGuidancePublishing(base);
const workspaceEnv:NodeJS.ProcessEnv={...process.env,WORKSPACE_TEST_URL:base};
delete workspaceEnv.NODE_TEST_CONTEXT;
const workspaceUI=spawn(process.execPath,['--import','tsx','--test','tests/guidance-workspace.test.ts'],{env:workspaceEnv,timeout:90000,stdio:'inherit'});
const workspaceUI=spawn(process.execPath,['--import','tsx','--test','tests/guidance-workspace.test.ts'],{env:workspaceEnv,timeout:180000,stdio:'inherit'});
const [workspaceExit]=await once(workspaceUI,'exit');assert.equal(workspaceExit,0,'SaaS workspace UI regression checks');
await verifyFlatNoteMigration();
const root=await request('/api/tags',{name:'线条',slug:'lines'});const child=await request('/api/tags',{name:'白色',slug:'white'});