// Journey: business phone verification end-to-end (SMS OTP via Redis) // // Endpoints exercised: // POST /api/v1/auth/register // POST /api/v1/auth/register/confirm // POST /api/v1/members/me/verifications/phone/start // POST /api/v1/members/me/verifications/phone/confirm // GET /api/v1/members/me (verify business_phone_verified flag is true) // // SMS OTP source: the mock SMS sender (when WithMockRedis is wired by the // notification factory in k6 mode) writes the SMS body to Redis at // "dev:notification:last:sms:". fetchSMSOTP polls that key. // // k6/experimental/redis requires k6 v0.46+. import { get, post, checkEnvelope } from '../lib/http.js'; import { registerAndConfirm } from '../lib/auth.js'; import { fetchSMSOTP } from '../lib/otp.js'; import { unique } from '../lib/config.js'; export const options = { vus: 1, iterations: 1, thresholds: { checks: ['rate==1.0'] }, }; // Generate a deterministic-ish unique E.164 number per iteration to avoid // collisions across concurrent runs. Use +886912 + 7 digits derived from the // VU+iter+timestamp. function uniquePhone() { const ts = Date.now() % 1_000_000_0; const vu = (typeof __VU !== 'undefined' && __VU) || 0; const iter = (typeof __ITER !== 'undefined' && __ITER) || 0; const suffix = String(ts + vu * 100 + iter).padStart(7, '0').slice(-7); return `+886912${suffix}`; } export default async function () { const { tokens } = registerAndConfirm(); const bearer = { Authorization: `Bearer ${tokens.access_token}` }; const phone = uniquePhone(); const startRes = post( '/api/v1/members/me/verifications/phone/start', { target: phone }, bearer, ); const start = checkEnvelope(startRes, 'POST /me/verifications/phone/start').data; if (!start.challenge_id) throw new Error('phone/start: missing challenge_id'); const { code } = await fetchSMSOTP(phone); if (!code) throw new Error(`could not extract SMS OTP for ${phone}`); const confirmRes = post( '/api/v1/members/me/verifications/phone/confirm', { challenge_id: start.challenge_id, code }, bearer, ); checkEnvelope(confirmRes, 'POST /me/verifications/phone/confirm'); const me = checkEnvelope(get('/api/v1/members/me', bearer), 'GET /members/me (post-phone-verify)').data; if (me.business_phone !== phone) { throw new Error(`business_phone not set: got=${me.business_phone}`); } if (me.business_phone_verified !== true) { throw new Error(`business_phone_verified should be true: got=${me.business_phone_verified}`); } }