const assert = require('node:assert/strict') const path = require('node:path') const { chromium } = require('/Users/macclaw/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright') module.exports = async function digitalHumanBrowser(auth, directory) { const browser = await chromium.launch({ headless: true, channel: 'chrome' }) const errors = [] try { const context = await browser.newContext({ viewport: { width: 1440, height: 1000 } }) await context.addInitScript(a => { for (const [key, value] of Object.entries({ weknora_user: JSON.stringify({ ...a.user, tenant_id: String(a.user.tenant_id) }), weknora_tenant: JSON.stringify({ ...a.active_tenant, id: String(a.active_tenant.id) }), weknora_token: a.token, weknora_refresh_token: a.refresh_token, weknora_memberships: JSON.stringify(a.memberships), })) localStorage.setItem(key, value) }, auth) const page = await context.newPage() page.on('pageerror', error => errors.push(error.message)) await page.goto('http://127.0.0.1:15173/platform/digital-humans') await page.locator('.guide__close').click() await page.getByRole('button', { name: '新建数字人', exact: true }).click() const dialog = page.locator('.t-dialog:visible') const name = `浏览器验收数字人-${Date.now()}` await dialog.locator('input').first().fill(name) await dialog.locator('.t-select').click() await page.getByText('acceptance-model', { exact: true }).last().click() await dialog.getByRole('button', { name: '创建', exact: true }).click() const drawer = page.locator('.t-drawer:visible') await drawer.getByText('补充蒸馏材料', { exact: true }).waitFor() await drawer.locator('input[type=file]').setInputFiles({ name: '课程原稿.md', mimeType: 'text/markdown', buffer: Buffer.from('先确认学习目标,再用案例说明,最后进行总结。') }) const start = drawer.getByRole('button', { name: /开始蒸馏/ }) await start.click() await drawer.locator('.job-progress .t-progress').waitFor() await page.screenshot({ path: path.join(directory, 'digital-human-progress-desktop.png') }) await drawer.getByRole('button', { name: '审核通过并生效', exact: true }).waitFor({ timeout: 30000 }) await drawer.getByRole('button', { name: '审核通过并生效', exact: true }).click() await drawer.getByText('已审核通过', { exact: true }).first().waitFor() await drawer.getByText('绑定 Agent', { exact: true }).click() await drawer.getByText('同名默认 Agent', { exact: true }).waitFor() await page.screenshot({ path: path.join(directory, 'digital-human-bindings-desktop.png') }) await page.setViewportSize({ width: 390, height: 844 }) await page.screenshot({ path: path.join(directory, 'digital-human-mobile.png') }) assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 2), 'Digital human page overflows mobile viewport') await drawer.locator('.t-drawer__close-btn').click() const row = page.locator('.human-row').filter({ hasText: name }) await row.getByRole('button', { name: '删除数字人', exact: true }).click() await page.getByRole('button', { name: '解除绑定并删除', exact: true }).click() await row.waitFor({ state: 'detached' }) assert.deepEqual(errors, [], 'Browser JavaScript errors') return '数字人真实浏览器创建、MD上传、进度、审核、绑定及删除;桌面/手机截图' } catch (error) { const pages = browser.contexts().flatMap(context => context.pages()) if (pages[0]) await pages[0].screenshot({ path: path.join(directory, 'digital-human-browser-failure.png') }) throw error } finally { await browser.close() } }