diff --git a/apps/waterfall-wiki/tests/canvas-ui-integration.ts b/apps/waterfall-wiki/tests/canvas-ui-integration.ts index a2d633d..cc17580 100644 --- a/apps/waterfall-wiki/tests/canvas-ui-integration.ts +++ b/apps/waterfall-wiki/tests/canvas-ui-integration.ts @@ -2,20 +2,27 @@ import assert from 'node:assert/strict'; import {randomUUID} from 'node:crypto'; import {chromium} from 'playwright-core'; import {db} from '../src/lib/db'; -import {newToken,tokenDigest,ACCOUNT_COOKIE} from '../src/lib/account-crypto'; +import {hashPassword,ACCOUNT_COOKIE} from '../src/lib/account-crypto'; export async function verifyCanvasAgentUI(base:string){ assert.equal(process.env.PROMPT_INTEGRATION_TEST,'1'); - const owner=randomUUID(),session=newToken(); - await db().query("INSERT INTO account_users(id,email,password_hash,verified_at) VALUES($1,$2,'test',now())",[owner,owner+'@example.com']); - await db().query("INSERT INTO account_tokens(digest,user_id,kind,expires_at) VALUES($1,$2,'session',now()+interval '1 hour')",[tokenDigest(session),owner]); + const owner=randomUUID(),email=owner+'@example.com',password='Canvas integration example1!'; + await db().query("INSERT INTO account_users(id,email,password_hash,verified_at) VALUES($1,$2,$3,now())",[owner,email,await hashPassword(password)]); const browser=await chromium.launch({executablePath:process.env.CHROMIUM_PATH||'/usr/bin/chromium',headless:true,args:['--no-sandbox','--disable-dev-shm-usage']}); const context=await browser.newContext({viewport:{width:1440,height:1000}}),errors:string[]=[]; - const ownerHeaders={cookie:ACCOUNT_COOKIE+'='+session}; try{ - await context.addCookies([{name:ACCOUNT_COOKIE,value:session,url:base,httpOnly:true,sameSite:'Lax'}]); const page=await context.newPage();page.setDefaultTimeout(20000);page.on('pageerror',e=>errors.push(e.message)); - await page.goto(base+'/infinite_canvas',{waitUntil:'networkidle'}); + await page.goto(base+'/',{waitUntil:'networkidle'}); + await page.getByRole('heading',{name:/想法不该停在对话里/,level:1}).waitFor(); + await page.getByRole('link',{name:'开始创作',exact:true}).click(); + await page.getByLabel('邮箱地址',{exact:true}).fill(email); + await page.getByLabel('密码',{exact:true}).fill(password); + await page.locator('form').getByRole('button',{name:'登录',exact:true}).click(); + await page.waitForURL(url=>url.pathname==='/workspace'); + await page.getByRole('heading',{name:'今天,让哪个想法成形?',exact:true}).waitFor(); + const session=(await context.cookies()).find(c=>c.name===ACCOUNT_COOKIE);assert.ok(session?.httpOnly,'The actual login response establishes an HTTP-only account session'); + const ownerHeaders={cookie:ACCOUNT_COOKIE+'='+session.value}; + await page.getByRole('link',{name:'无限画布',exact:true}).click(); await page.getByRole('button',{name:'从示例开始 ↗',exact:true}).click(); const shot=page.locator('[data-node-id="shot"] [data-node-content]'); await shot.click();await shot.click(); diff --git a/scripts/integration.sh b/scripts/integration.sh index 55e101b..d08dad7 100644 --- a/scripts/integration.sh +++ b/scripts/integration.sh @@ -19,7 +19,7 @@ trap cleanup EXIT docker run --rm --entrypoint node "$WATERFALL_WIKI_IMAGE" -e "const c=require('crypto');const hex=()=>c.randomBytes(24).toString('hex');console.log('POSTGRES_PASSWORD='+hex()+'\nS3_ACCESS_KEY='+hex()+'\nS3_SECRET_KEY='+hex())" > "$TEST_ENV" # Explicitly isolate legacy unauthenticated integration coverage; production fails closed. printf '\nAUTH_DISABLED_FOR_TESTS=true\n' >> "$TEST_ENV" -if [[ -n "${STUDIO_REVIEW_IMAGE:-}" ]]; then printf '\nACCOUNT_PUBLIC_ORIGIN=http://waterfall-wiki:3000\n' >> "$TEST_ENV"; fi +if [[ -n "${STUDIO_REVIEW_IMAGE:-}" ]]; then printf '\nACCOUNT_PUBLIC_ORIGIN=http://waterfall-wiki:3000\nAUTH_COOKIE_SECURE=false\n' >> "$TEST_ENV"; fi compose up -d --no-build --wait --wait-timeout 120 postgres objects compose run --rm --no-deps migrate compose up -d --no-build --wait --wait-timeout 150 waterfall-wiki waterfall-wiki-worker "${STUDIO_SERVICES[@]}"