102 lines
10 KiB
JavaScript
102 lines
10 KiB
JavaScript
// 真实 Chrome 核对三个画像入口、统计切换及嵌套抽屉;所有业务数据使用受控响应。
|
|
const fs = require('node:fs/promises')
|
|
const path = require('node:path')
|
|
const assert = require('node:assert/strict')
|
|
const { chromium } = require(process.env.SW_PLAYWRIGHT_MODULE || 'playwright')
|
|
|
|
;(async () => {
|
|
const token = (await fs.readFile(path.join(process.env.TEMP, 'sw-kra-http-test-token'), 'utf8')).trim()
|
|
const browser = await chromium.launch({ channel: 'chrome', headless: true })
|
|
const results = []
|
|
try {
|
|
for (const level of [1, 3]) {
|
|
const context = await browser.newContext({ viewport: { width: 1600, height: 1080 } })
|
|
await context.addInitScript(value => localStorage.setItem('token', value), token)
|
|
const page = await context.newPage()
|
|
const errors = [], portraits = [], alertQueries = [], channelQueries = []
|
|
let unavailable = false
|
|
const normal = { userId: 70009, sourceDb: 'lx', platformName: '龙翔', platformBusierId: 14, platformBusierAccount: 'SDK测试账号', bindUserName: '测试商务', status: '0', createTime: '2026-11-01 10:00:00', promoteCount: 1 }
|
|
page.on('pageerror', error => errors.push(error.message))
|
|
await page.route('http://127.0.0.1:8080/api/**', async route => {
|
|
const request = route.request(), url = new URL(request.url()), api = url.pathname.slice(4)
|
|
const ok = data => route.fulfill({ json: { code: 0, msg: '成功', data } })
|
|
if (api === '/sw/business/list') return ok({ rows: level === 3 ? [] : [{ userId: 70009, userName: '测试商务账号', realName: '测试商务', level: 3, status: '0', bindCount: 1, promoteCount: 1, createTime: '2026-11-01 10:00:00' }], total: level === 3 ? 0 : 1 })
|
|
if (api === '/sw/business/70009/bindPlatform') return ok([normal])
|
|
if (api === '/sw/business/bindPlatform') return ok({ rows: [normal, { ...normal, platformBusierId: 15, platformBusierAccount: '驳回账号', status: '2' }, { ...normal, platformBusierId: 16, platformBusierAccount: '待审账号', status: '3' }], total: 3 })
|
|
if (api === '/sw/business/70009/portrait' || api === '/sw/business/bindPlatform/portrait') {
|
|
const sdk = api.includes('bindPlatform')
|
|
const period = url.searchParams.get('period') || 'today'
|
|
portraits.push({ api, period, source: url.searchParams.get(sdk ? 'sourceDb' : 'sourceDbList'), platformBusierId: url.searchParams.get('platformBusierId') })
|
|
const length = ['today', 'yesterday'].includes(period) ? 24 : 7
|
|
const trends = Array.from({ length }, (_, i) => ({ label: length === 24 ? String(i).padStart(2, '0') + ':00' : new Date(Date.UTC(2026, 9, 28 + i)).toISOString().slice(5, 10), value: i === 1 ? '2' : '0' }))
|
|
const compareLabel = period === 'today' ? '较昨日' : period === 'yesterday' ? '较前日' : period === 'thismonth' ? '较上月同期' : '较上一周期'
|
|
const metric = value => ({ value, compareValue: '1', changeRate: '100.0', changeDiff: null, compareLabel })
|
|
return ok({ basic: { userId: sdk ? 14 : 70009, userName: sdk ? 'SDK测试账号' : '测试商务账号', realName: '画像姓名', level: 3, levelLabel: '三级商务', parentUserName: '上级账号', status: '0', statusLabel: sdk ? '待审核' : '正常', promoteCount: unavailable ? null : 1, monthNewPromote: unavailable ? null : 1, createTime: '2026-11-01 10:00:00' }, period,
|
|
available: !unavailable, unavailableReason: unavailable ? '渠道数据尚未接入,画像指标暂不可用' : '', metrics: unavailable ? null : { register: metric('2'), payAmount: metric('12.00'), payRate: { ...metric('50.0'), changeRate: null, changeDiff: '25.0', compareValue: '25.0' }, arpu: metric('6.00') },
|
|
registerTrend: unavailable ? [] : trends, payTrend: unavailable ? [] : trends.map(point => ({ ...point, value: point.value === '2' ? '12.00' : '0.00' })), registerTop5: unavailable ? [] : [{ rank: 1, sourceDbLabel: '龙翔', promoteId: 100, promoteName: '测试主渠道', value: '2.00' }], payTop5: unavailable ? [] : [{ rank: 1, sourceDbLabel: '龙翔', promoteId: 100, promoteName: '测试主渠道', value: '12.00' }] })
|
|
}
|
|
if (api === '/sw/alertRecord/list') { alertQueries.push(Object.fromEntries(url.searchParams)); return ok({ available: true, pageData: { rows: [{ id: '1', createdAt: '2026-11-03 10:00:00', targetPromoteName: '测试预警渠道', ruleType: 'register_anomaly', alertContent: '测试关联预警', status: 1, statusLabel: '未处理' }], total: 1 }, statusCount: { 1: 1 } }) }
|
|
if (api === '/sw/business/70009/promotes') { channelQueries.push({ api, ...Object.fromEntries(url.searchParams) }); return ok({ rows: [{ promoteId: 100, promoteName: '测试直属渠道', sourceDb: 'lx', platformName: '龙翔' }], total: 1, available: true }) }
|
|
const response = await route.fetch({ url: 'http://127.0.0.1:18000' + api + url.search, headers: { ...request.headers(), 'x-token': token } })
|
|
if (api === '/user/getUserInfo') { const body = await response.json(); Object.assign(body.data.userInfo, { ID: level === 3 ? 70009 : 70001, level, authorityId: 900 + level, nickName: '画像核对账号', phone: '', email: '' }); return route.fulfill({ response, json: body }) }
|
|
return route.fulfill({ response })
|
|
})
|
|
await page.goto('http://127.0.0.1:8080/#/layout/sw-BusMgmt/BusinessList')
|
|
const close = async dialog => { await dialog.getByRole('button', { name: '关闭', exact: true }).click(); await dialog.waitFor({ state: 'hidden' }) }
|
|
if (level === 1) {
|
|
await page.getByRole('button', { name: '画像', exact: true }).click()
|
|
const portrait = page.getByRole('dialog', { name: '商务画像 — 测试商务', exact: true })
|
|
await portrait.getByText('画像姓名', { exact: true }).waitFor()
|
|
await portrait.locator('.el-loading-mask').first().waitFor({ state: 'hidden' })
|
|
await portrait.getByText('测试关联预警', { exact: true }).waitFor()
|
|
assert.equal(portraits.at(-1).source, 'lx,hw,yq')
|
|
await portrait.getByRole('img', { name: '注册量趋势', exact: true }).focus()
|
|
await portrait.getByRole('img', { name: '注册量趋势', exact: true }).press('ArrowRight')
|
|
await portrait.locator('.trend-tooltip').getByText('01:00', { exact: true }).waitFor()
|
|
await portrait.getByText('近7天', { exact: true }).click()
|
|
await page.waitForFunction(() => [...document.querySelectorAll('.profile-two-columns .el-card__header')].some(node => node.textContent.includes('近7天注册量')))
|
|
assert.equal(portraits.at(-1).period, 'last7')
|
|
await portrait.locator('.el-loading-mask').first().waitFor({ state: 'hidden' })
|
|
await page.screenshot({ path: path.join(process.env.TEMP, 'sw-business-portrait.png'), animations: 'disabled' })
|
|
await close(portrait)
|
|
await page.getByRole('button', { name: '查看SDK商务绑定详情', exact: true }).click()
|
|
const bindings = page.getByRole('dialog', { name: 'SDK商务绑定详情', exact: true })
|
|
await bindings.getByRole('button', { name: '龙翔', exact: true }).click()
|
|
const sdk = page.getByRole('dialog', { name: '游戏商务画像 — SDK测试账号', exact: true })
|
|
await sdk.getByText('画像姓名', { exact: true }).waitFor()
|
|
assert.equal(portraits.at(-1).platformBusierId, '14')
|
|
assert.equal(alertQueries.at(-1).businessId, '70009')
|
|
assert.equal(alertQueries.at(-1).platformCodes, 'lx')
|
|
await sdk.locator('.profile-info').getByText('待审核', { exact: true }).waitFor()
|
|
assert.equal(await sdk.locator('.profile-info .el-tag--success').count(), 0)
|
|
await sdk.locator('.profile-info').getByRole('button', { name: '1', exact: true }).click()
|
|
const channels = page.getByRole('dialog', { name: '旗下渠道', exact: true })
|
|
await channels.waitFor(); await channels.locator('.el-loading-mask').waitFor({ state: 'hidden' })
|
|
assert.equal(channelQueries.at(-1).api, '/sw/business/70009/promotes')
|
|
assert.equal(channelQueries.at(-1).platformBusierId, '14')
|
|
await channels.locator('.el-drawer__close-btn').click(); await channels.waitFor({ state: 'hidden' })
|
|
await close(sdk)
|
|
await bindings.locator('.el-drawer__close-btn').click(); await bindings.waitFor({ state: 'hidden' })
|
|
unavailable = true
|
|
await page.getByRole('button', { name: '画像', exact: true }).click()
|
|
await portrait.getByText('渠道数据尚未接入,画像指标暂不可用', { exact: true }).waitFor()
|
|
assert.equal(await portrait.getByRole('img', { name: '注册量趋势', exact: true }).count(), 0)
|
|
await close(portrait)
|
|
} else {
|
|
await page.getByRole('tab', { name: '绑定列表', exact: true }).click()
|
|
const normalRow = page.locator('.el-table__body-wrapper tr').filter({ hasText: 'SDK测试账号' })
|
|
await normalRow.getByRole('button', { name: '画像', exact: true }).click()
|
|
const sdk = page.getByRole('dialog', { name: '游戏商务画像 — SDK测试账号', exact: true })
|
|
await sdk.getByText('画像姓名', { exact: true }).waitFor()
|
|
await close(sdk)
|
|
assert.equal(await page.locator('.el-table__body-wrapper tr').filter({ hasText: '驳回账号' }).getByRole('button', { name: '画像', exact: true }).count(), 0)
|
|
assert.equal(await page.locator('.el-table__body-wrapper tr').filter({ hasText: '待审账号' }).getByRole('button', { name: '画像', exact: true }).count(), 0)
|
|
}
|
|
assert.deepEqual(errors, [])
|
|
const result = { level, passed: true, entry: level === 1 ? '商务列表与只读 SDK 详情' : '三级绑定列表正常行', pageErrors: errors }
|
|
results.push(result); console.log(JSON.stringify(result)); await context.close()
|
|
}
|
|
await fs.writeFile('docs/sw6-to-kra/portrait-page-2026-11-03.json', JSON.stringify({ method: '真实 Chrome 渲染;业务接口使用受控数据。验证三个入口、时间切换、交互图表、SDK 状态、SW 用户 ID 与平台 ID 分离、缺数据提示。', results }, null, 2) + '\n')
|
|
} finally { await browser.close() }
|
|
})().catch(error => { console.error(error); process.exitCode = 1 })
|