// 独立 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 }) try { const context = await browser.newContext({ viewport: { width: 1600, height: 1000 } }) await context.addInitScript(value => localStorage.setItem('token', value), token) const page = await context.newPage() const errors = [], queries = [], gameQueries = [], writes = [] let available = true const rows = [ { id: 100, sourceDb: 'lx', platformName: '龙翔', account: 'lx-channel', nickname: '测试渠道', promoteLevel: 1, busierDisplayName: 'SDK-LX(测试商务)', parentName: '', realName: '负责人', registerType: 0, gameCount: 2, playerCount: 3, totalPayAmount: '30.30', lockStatus: 0 }, { id: 100, sourceDb: 'hw', platformName: '汇玩', account: 'hw-channel', promoteLevel: 1, registerType: 1, gameCount: 0, playerCount: null, totalPayAmount: null, lockStatus: -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/promote/list') { queries.push(url.search); return ok({ rows: available ? rows : [], total: available ? 2 : 0, available }) } if (api === '/sw/promote/bindOptions') { const source = url.searchParams.get('sourceDb') const option = { sourceDb: source, platformBusierId: source === 'lx' ? 14 : 18, platformBusierAccount: source === 'lx' ? 'SDK-LX' : 'SDK-HW', userId: 70009 } return ok([option, option]) } if (api === '/sw/promote/game-distribution') { gameQueries.push({ sourceDb: url.searchParams.get('sourceDb'), promoteId: url.searchParams.get('promoteId') }) return ok(url.searchParams.get('sourceDb') === 'lx' ? [{ gameId: 1, gameName: '测试游戏', registerCount: 2, payAmount: '70.00' }] : []) } if (api === '/sw/promote' && request.method() === 'POST') { writes.push(request.postDataJSON()); return ok({ id: 200, sourceDb: 'lx' }) } 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: 70001, level: 1, authorityId: 901, 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/ChannelList') await page.getByText('lx-channel', { exact: true }).waitFor() const lx = page.locator('.el-table__body-wrapper tr').filter({ hasText: 'lx-channel' }) const hw = page.locator('.el-table__body-wrapper tr').filter({ hasText: 'hw-channel' }) assert.equal(await page.getByRole('button', { name: '编辑', exact: true }).count(), 0) assert.equal(await hw.getByText('未接入', { exact: true }).count(), 2) await lx.getByRole('button', { name: '2 款', exact: true }).click() const games = page.getByRole('dialog', { name: '推广游戏数据 — 测试渠道', exact: true }) await games.getByText('测试游戏', { exact: true }).waitFor() await games.locator('.el-loading-mask').waitFor({ state: 'hidden' }) await games.getByText('¥70.00', { exact: true }).waitFor() assert.deepEqual(gameQueries.at(-1), { sourceDb: 'lx', promoteId: '100' }) await page.screenshot({ path: path.join(process.env.TEMP, 'sw-channel-games.png'), animations: 'disabled' }) await games.locator('.el-drawer__close-btn').click(); await games.waitFor({ state: 'hidden' }) await hw.getByRole('button', { name: '0 款', exact: true }).click() const emptyGames = page.getByRole('dialog', { name: '推广游戏数据 — hw-channel', exact: true }) await emptyGames.waitFor() await emptyGames.locator('.el-loading-mask').waitFor({ state: 'hidden' }) assert.deepEqual(gameQueries.at(-1), { sourceDb: 'hw', promoteId: '100' }) await emptyGames.locator('.el-drawer__close-btn').click(); await emptyGames.waitFor({ state: 'hidden' }) await page.getByRole('button', { name: '添加渠道', exact: true }).click() const drawer = page.getByRole('dialog', { name: '添加渠道', exact: true }) const select = async (label, option) => { await drawer.locator('.el-form-item').filter({ hasText: label }).locator('.el-select__wrapper').click() await page.getByRole('option', { name: option, exact: true }).click() } await select('所属平台', '龙翔') await select('游戏商务', 'SDK-LX') await select('所属平台', '汇玩') assert.equal(await drawer.getByText('SDK-LX', { exact: true }).count(), 0) await select('游戏商务', 'SDK-HW') await select('所属平台', '龙翔') await select('游戏商务', 'SDK-LX') await select('推广类型', '企业') await drawer.getByPlaceholder('中文/英文/数字,4-30位', { exact: true }).fill('中文渠道') await drawer.getByPlaceholder('6-15位', { exact: true }).fill('demo123') await drawer.getByRole('button', { name: '确认添加', exact: true }).click() await drawer.waitFor({ state: 'hidden' }) assert.equal(writes.length, 1) assert.equal(writes[0].platformBusierId, 14) assert.equal(writes[0].sourceDb, 'lx') assert.equal(writes[0].registerType, 1) available = false await page.locator('.kra-search-box').getByRole('button', { name: '搜索', exact: true }).click() await page.getByText('渠道数据尚未接入。', { exact: true }).waitFor() assert.deepEqual(errors, []) const result = { passed: true, level: 1, noEditEntry: true, createAllowedForUpperBusiness: true, platformSwitchClearsBinding: true, crossPlatformSameID: true, zeroGameCountClickable: true, missingMetricsVisible: true, sourceDatabaseCreatePayload: true, portraitPending: false, pageErrors: errors } await fs.writeFile('docs/sw6-to-kra/channel-page-2026-11-03.json', JSON.stringify({ method: '真实 Chrome 渲染;受控页面数据、身份及平台创建响应,不创建真实平台渠道', ...result }, null, 2) + '\n') console.log(JSON.stringify(result)) await context.close() } finally { await browser.close() } })().catch(error => { console.error(error); process.exitCode = 1 })