import assert from 'node:assert/strict'; import http from 'node:http'; import { spawn } from 'node:child_process'; import { runRemoteSmsLoginSmoke } from './remote-sms-login-smoke.js'; const tenantId = '00000000-0000-0000-0000-000000000001'; const phone = '13800138000'; const bindPhone = '13900139000'; function json(res, status, payload) { res.writeHead(status, { 'content-type': 'application/json' }); res.end(JSON.stringify(payload)); } function bodyJson(req) { return new Promise(resolve => { const chunks = []; req.on('data', chunk => chunks.push(chunk)); req.on('end', () => { try { resolve(JSON.parse(Buffer.concat(chunks).toString('utf8') || '{}')); } catch { resolve({}); } }); }); } const seen = []; const server = http.createServer(async (req, res) => { const url = new URL(req.url || '/', 'http://127.0.0.1'); seen.push({ path: url.pathname, method: req.method, tenantId: req.headers['x-tenant-id'], origin: req.headers.origin }); if (url.pathname === '/api/auth/sms/send' && req.method === 'POST') { const body = await bodyJson(req); assert.ok([phone, bindPhone].includes(body.phone)); assert.equal(body.purpose, body.phone === bindPhone ? 'bind_phone' : 'login'); if (body.phone === bindPhone) assert.equal(req.headers.authorization, 'Bearer session-token'); json(res, 200, { item: { id: 'sms-id', phone: body.phone, purpose: body.purpose, provider: 'aliyun-pnvs', status: 'sent' }, expireIn: 300, cooldown: 60, }); return; } if (url.pathname === '/api/auth/sms/verify' && req.method === 'POST') { const body = await bodyJson(req); assert.equal(body.phone, phone); assert.equal(body.code, '123456'); json(res, 200, { user: { id: 'user-id', phone }, session: { token: 'session-token' }, }); return; } if (url.pathname === '/api/auth/me' && req.method === 'GET') { assert.equal(req.headers.authorization, 'Bearer session-token'); json(res, 200, { user: { id: 'user-id', phone } }); return; } if (url.pathname === '/api/auth/phone/bind' && req.method === 'POST') { assert.equal(req.headers.authorization, 'Bearer session-token'); const body = await bodyJson(req); assert.equal(body.phone, bindPhone); assert.equal(body.code, '654321'); assert.equal(body.purpose, 'bind_phone'); json(res, 200, { ok: true, user: { id: 'user-id', phone: bindPhone }, phoneChanged: true, revokedOtherSessions: 0 }); return; } json(res, 404, { code: 'NOT_FOUND', path: url.pathname }); }); await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); function runCliSmoke(address) { return new Promise(resolve => { const child = spawn(process.execPath, ['scripts/remote-sms-login-smoke.js', '--json'], { cwd: process.cwd(), env: { ...process.env, SMS_SMOKE_API_BASE_URL: `http://127.0.0.1:${address.port}`, SMS_SMOKE_TENANT_ID: tenantId, SMS_SMOKE_PHONE: phone, SMS_SMOKE_BIND_PHONE: bindPhone, SMS_SMOKE_ORIGIN: 'https://admin.tjszsb.com', SMS_SMOKE_CODE: '123456', SMS_SMOKE_BIND_CODE: '654321', }, }); let stdout = ''; let stderr = ''; child.stdout.on('data', chunk => { stdout += chunk.toString('utf8'); }); child.stderr.on('data', chunk => { stderr += chunk.toString('utf8'); }); child.on('close', status => resolve({ status, stdout, stderr })); }); } try { const address = server.address(); const result = await runRemoteSmsLoginSmoke( { apiBaseUrl: `http://127.0.0.1:${address.port}`, tenantId, phone, origin: 'https://admin.tjszsb.com', purpose: 'login', code: '123456', bindPhone, bindCode: '654321', timeoutMs: 5000, skipSend: false, skipMe: false, }, { quiet: true }, ); assert.equal(result.sessionToken, 'session-token'); assert.equal(result.boundPhone, bindPhone); assert.equal(result.summary.provider, 'aliyun-pnvs'); assert.equal(result.summary.loginVerified, true); assert.equal(result.summary.authMe, true); assert.equal(result.summary.bindProvider, 'aliyun-pnvs'); assert.equal(result.summary.bindVerified, true); assert.equal(seen.some(item => item.path === '/api/auth/sms/send' && item.tenantId === tenantId), true); assert.equal(seen.some(item => item.path === '/api/auth/sms/verify' && item.origin === 'https://admin.tjszsb.com'), true); assert.equal(seen.some(item => item.path === '/api/auth/me'), true); assert.equal(seen.some(item => item.path === '/api/auth/phone/bind'), true); const cliResult = await runCliSmoke(address); assert.equal(cliResult.status, 0, `CLI --json smoke should pass: ${cliResult.stdout} ${cliResult.stderr}`); const cliSummary = JSON.parse(cliResult.stdout); assert.equal(cliSummary.provider, 'aliyun-pnvs'); assert.equal(cliSummary.bindProvider, 'aliyun-pnvs'); assert.doesNotMatch(cliResult.stdout, /Enter received/, 'CLI --json stdout must stay machine-readable JSON'); console.log('[PASS] remote SMS login smoke script'); } finally { await new Promise(resolve => server.close(resolve)); }