import assert from "node:assert/strict"; import { describe, it } from "node:test"; import { buildCaptchaImageUrl, buildSendMobileCodeRequest, isImageCaptchaLocked, resolveImageCaptchaInteractionState, resolveLoginErrorMessage, } from "./loginSms.ts"; describe("login sms api helpers", () => { it("builds send-code request with image captcha params and clientConfigId header", () => { const result = buildSendMobileCodeRequest({ mobile: "+8613800000000", clientConfigId: "6", imageRandomStr: "captcha-random", imageCode: "42", }); assert.deepEqual(result.config, { url: "/admin/platformUser/sendMobileCode/%2B8613800000000", method: "get", params: { imageRandomStr: "captcha-random", imageCode: "42", }, }); assert.deepEqual(result.options, { skipAuth: true, headers: { clientConfigId: "6", }, }); }); it("builds captcha image url from api base url", () => { assert.equal( buildCaptchaImageUrl("captcha random", { baseURL: "/ingress/", cacheBust: 123, }), "/ingress/auth/code/image?randomStr=captcha+random&_t=123", ); }); it("uses backend business error message before generic fallback", () => { assert.equal( resolveLoginErrorMessage( { kind: "business", message: "图形验证码不合法", }, "网络错误", ), "图形验证码不合法", ); assert.equal( resolveLoginErrorMessage( { kind: "network", message: "Network Error", }, "网络错误", ), "网络错误", ); }); it("locks image captcha while sms countdown is active", () => { assert.equal(isImageCaptchaLocked(60), true); assert.equal(isImageCaptchaLocked(1), true); assert.equal(isImageCaptchaLocked(0), false); }); it("resolves captcha field and refresh button interaction state", () => { assert.deepEqual( resolveImageCaptchaInteractionState({ smsSending: false, smsCountdown: 60, }), { disabled: true, clearable: false, refreshDisabled: true, }, ); assert.deepEqual( resolveImageCaptchaInteractionState({ smsSending: false, smsCountdown: 0, }), { disabled: false, clearable: true, refreshDisabled: false, }, ); assert.deepEqual( resolveImageCaptchaInteractionState({ smsSending: true, smsCountdown: 0, }), { disabled: true, clearable: false, refreshDisabled: true, }, ); }); });