import assert from 'node:assert/strict'; import { mkdir, readFile, writeFile } from 'node:fs/promises'; import { chromium } from 'playwright'; const credentials = JSON.parse(await readFile(new URL('../../.work/frontend-accounts.json', import.meta.url), 'utf8')); const base = process.env.FRONTEND_URL || 'http://127.0.0.1:18763'; const browser = await chromium.launch({ headless: true, executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE || 'C:/Users/Administrator/AppData/Local/ms-playwright/chromium-1228/chrome-win64/chrome.exe' }); const page = await browser.newPage(); const errors = []; page.on('pageerror', error => errors.push(error.message)); async function route(name) { await page.evaluate(value => { location.hash = `#/merchant/${value}`; }, name); await page.waitForURL(new RegExp(`#/merchant/${name}$`)); await page.getByText('正在读取数据…', { exact: true }).waitFor({ state: 'hidden' }); } async function confirm() { const dialog = page.getByRole('dialog'); await dialog.getByRole('button', { name: '确认操作', exact: true }).click(); await dialog.waitFor({ state: 'hidden' }); } async function notice(text) { await page.locator('.app-notice').filter({ hasText: text }).waitFor(); } try { await page.goto(`${base}/#/merchant/login`); await page.getByLabel('商家标识').fill(credentials.tenant_id); await page.getByLabel('员工账户').fill('admin01'); await page.getByLabel('密码', { exact: true }).fill(credentials.password); await page.getByRole('button', { name: '登录', exact: true }).click(); await page.locator('.admin-shell').waitFor(); // 开发店铺保留已发布的服务资料,供配置清单引用;发布调用使用真实本地向量服务。 await route('knowledge'); const existing = page.getByRole('button', { name: '配件店售后服务说明', exact: true }); while (!await existing.count() && await page.getByRole('button', { name: '加载更多', exact: true }).count()) { const loaded = page.waitForResponse(response => response.request().method() === 'GET' && response.url().includes('/knowledge?')); await page.getByRole('button', { name: '加载更多', exact: true }).click(); assert.equal((await loaded).status(), 200); } if (await existing.count()) { await existing.first().click(); } else { await page.getByRole('button', { name: '新建资料', exact: true }).click(); await page.getByLabel('资料标题').fill('配件店售后服务说明'); await page.getByLabel('文本内容').fill('本店提供键盘、鼠标和桌面配件。查询订单与售后进度需要客户登录。键盘功能故障能否申请换货,以当前已发布售后规则和订单签收时间为准。换货方案需要客户确认,再由主管审批。批准后的处理结果以订单系统返回为准。客户可在咨询页面申请人工协助,由已授权客服接待。'); await page.getByRole('button', { name: '保存草稿', exact: true }).click(); await notice('知识草稿已保存'); await page.getByRole('button', { name: '发布当前版本', exact: true }).click(); await confirm(); await notice('知识资料已发布'); } await route('release'); await page.locator('.el-checkbox').filter({ hasText: '已核对当前版本的回归检查记录' }).click(); assert.equal(await page.getByRole('checkbox', { name: '已核对当前版本的回归检查记录', exact: true }).isChecked(), true); await page.getByLabel('发布说明', { exact: true }).fill('已验证真实接口、权限、审批、知识发布、规则发布和页面功能。'); const button = page.getByRole('button', { name: '检查并发布到当前授权店铺', exact: true }); assert.equal(await button.isEnabled(), true, '完整配置允许提交发布'); await button.click(); const published = page.waitForResponse(response => response.request().method() === 'POST' && response.url().endsWith('/agent-releases')); await confirm(); const response = await published; assert.equal(response.status(), 201, await response.text()); const release = await response.json(); assert.ok(release.version > 0); await notice('Agent 配置已发布'); await route('overview'); await route('release'); await page.getByText(`发布版本 R${release.version}`, { exact: true }).waitFor(); assert.deepEqual(errors, []); await mkdir(new URL('../../.work/frontend-verification/', import.meta.url), { recursive: true }); await writeFile(new URL('../../.work/frontend-verification/merchant-release.json', import.meta.url), JSON.stringify({ date: new Date().toISOString(), releaseVersion: release.version, checks: ['知识真实发布', 'Agent配置发布成功', '重新进入页面读取持久发布版本'], browserErrors: errors, generatedModelCalls: 0 }, null, 2)); console.log(`Agent R${release.version} 发布及持久读取通过,生成模型调用为0。`); } catch (error) { console.error(await page.locator('body').innerText()); throw error; } finally { await browser.close(); }