const assert = require('assert'); const http = require('http'); const { startLoginFlowServer, stopLoginFlowServer } = require('../mcp/src/core/login-flow-server'); async function body(req) { const chunks = []; for await (const chunk of req) chunks.push(chunk); if (!chunks.length) return {}; return JSON.parse(Buffer.concat(chunks).toString('utf8')); } async function startGateway() { const requests = []; const server = http.createServer(async (req, res) => { const url = new URL(req.url, 'http://localhost'); const input = await body(req); requests.push({ path: url.pathname, method: req.method, input, authorization: req.headers.authorization }); let data; if (url.pathname === '/subscribe/status') { const quotedSeats = Number(url.searchParams.get('seats')); data = quotedSeats ? { subscribed: true, seats: 1, usedSeats: 1, quote: { seats: quotedSeats, amount: 125 } } : { subscribed: true, seats: 1, usedSeats: 1, price: 500 }; } else if (url.pathname === '/login/accounts') { data = { seats: 1, usedSeats: 1, accounts: [{ id: `account_${'a'.repeat(40)}`, nickname: '原账号', corpName: '测试企业', online: false }] }; } else if (url.pathname === '/login/status') { data = { configured: true, online: false, statusCode: -1 }; } else if (url.pathname === '/login/select') { data = { selected: true, uid: input.uid, accountId: input.accountId, online: false }; } else if (url.pathname === '/login/start') { data = { uid: input.newAccount ? 'qiwei-temporary-login' : input.uid, loginQrcodeBase64Data: Buffer.from('mock-png').toString('base64') }; } else if (url.pathname === '/login/check') { data = { uid: input.uid, status: 2, detail: { corpId: 'corp-new', userId: 'user-new', nickname: '新账号' }, decisionRequired: true, seats: 1, usedSeats: 1, account: { id: `account_${'b'.repeat(40)}`, nickname: '新账号' }, accounts: [{ id: `account_${'a'.repeat(40)}`, nickname: '原账号' }], actions: ['purchase', 'replace', 'cancel'] }; } else if (url.pathname === '/login/resolve') { data = { resolved: true, action: input.action, cancelled: input.action === 'cancel' }; } else if (url.pathname === '/subscribe') { data = { seats: input.seats, amount: input.expectedAmount, state: 'active' }; } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ code: 404, mess: 'not found' })); return; } res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ code: 200, data })); }); await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); return { apiBase: `http://127.0.0.1:${server.address().port}`, requests, close: () => new Promise(resolve => server.close(resolve)) }; } async function main() { const gateway = await startGateway(); const port = 4397; try { const { url } = await startLoginFlowServer({ token: 'sk-login-seat-smoke', apiBase: gateway.apiBase, uid: 'qiwei-client-one', port }); const page = await fetch(url).then(res => res.text()); const checkoutToken = JSON.parse(page.match(/const CHECKOUT_TOKEN = ("[^"]+")/)[1]); const origin = `http://127.0.0.1:${port}`; const state = await fetch(`${origin}/flow/state`).then(res => res.json()); assert.strictEqual(state.subscribed, true); assert.strictEqual(state.accounts.length, 1); const select = await fetch(`${origin}/flow/select-account`, { method: 'POST', headers: { 'Content-Type': 'application/json', Origin: origin }, body: JSON.stringify({ accountId: state.accounts[0].id }) }).then(res => res.json()); assert.strictEqual(select.selected, true); await fetch(`${origin}/flow/start-login`, { method: 'POST', headers: { 'Content-Type': 'application/json', Origin: origin }, body: JSON.stringify({ newAccount: true }) }); const decision = await fetch(`${origin}/flow/check`).then(res => res.json()); assert.strictEqual(decision.decisionRequired, true); assert.deepStrictEqual(decision.actions, ['purchase', 'replace', 'cancel']); const quote = await fetch(`${origin}/flow/upgrade-quote`).then(res => res.json()); assert.strictEqual(quote.targetSeats, 2); assert.strictEqual(quote.quote.amount, 125); const cancel = await fetch(`${origin}/flow/resolve`, { method: 'POST', headers: { 'Content-Type': 'application/json', Origin: origin }, body: JSON.stringify({ checkoutToken, action: 'cancel' }) }).then(res => res.json()); assert.strictEqual(cancel.cancelled, true); const refreshedPage = await fetch(origin).then(res => res.text()); const upgradeToken = JSON.parse(refreshedPage.match(/const CHECKOUT_TOKEN = ("[^"]+")/)[1]); await fetch(`${origin}/flow/start-login`, { method: 'POST', headers: { 'Content-Type': 'application/json', Origin: origin }, body: JSON.stringify({ newAccount: true }) }); await fetch(`${origin}/flow/check`); const upgraded = await fetch(`${origin}/flow/upgrade`, { method: 'POST', headers: { 'Content-Type': 'application/json', Origin: origin }, body: JSON.stringify({ checkoutToken: upgradeToken, idempotencyKey: 'seat-upgrade-smoke-001' }) }).then(res => res.json()); assert.strictEqual(upgraded.resolved, true); assert(gateway.requests.some(request => request.path === '/subscribe' && request.input.expectedAmount === 125)); assert(gateway.requests.some(request => request.path === '/login/resolve' && request.input.action === 'purchase')); const replacePage = await fetch(origin).then(res => res.text()); const replaceToken = JSON.parse(replacePage.match(/const CHECKOUT_TOKEN = ("[^"]+")/)[1]); await fetch(`${origin}/flow/start-login`, { method: 'POST', headers: { 'Content-Type': 'application/json', Origin: origin }, body: JSON.stringify({ newAccount: true }) }); await fetch(`${origin}/flow/check`); const replaced = await fetch(`${origin}/flow/resolve`, { method: 'POST', headers: { 'Content-Type': 'application/json', Origin: origin }, body: JSON.stringify({ checkoutToken: replaceToken, action: 'replace', replaceAccountId: state.accounts[0].id }) }).then(res => res.json()); assert.strictEqual(replaced.resolved, true); assert(gateway.requests.some(request => request.path === '/login/resolve' && request.input.action === 'replace')); assert(gateway.requests.every(request => request.authorization === 'Bearer sk-login-seat-smoke')); console.log('[ok] account selection and purchase, replace, cancel seat decisions'); } finally { stopLoginFlowServer(); await gateway.close(); } } main().catch(error => { console.error(error); process.exitCode = 1; });