Files
jiapuapp/tests/a01-password-login-runtime-smoke.js
T
2026-07-23 17:21:33 +08:00

208 lines
6.1 KiB
JavaScript

"use strict";
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const source = fs.readFileSync(
path.join(__dirname, "../pages/auth/a01-entry.vue"),
"utf8",
);
const match = source.match(/<script setup>([\s\S]*?)<\/script>/);
assert(match, "A01 script setup is missing");
const pageScript = match[1].replace(
/import[\s\S]*?from\s+["'][^"']+["'];\s*/g,
"",
);
const createHarnessFactory = (goRootResult = true, goRootError = null) => new Function(
"goRootResult",
"goRootError",
`
"use strict";
const calls = [];
const ref = (value) => ({ value });
const onBackPress = () => {};
const onShow = (callback) => callback();
const onUnload = () => {};
const AuthPageShell = {};
const AppToast = {};
const TacVerification = {};
const createRequestController = () => ({
abort() {},
bind() {},
release() {},
});
const isRequestCancelled = () => false;
const isSmsDeliveryOutcomeUnknown = () => false;
const createAuthSmsCooldown = ({ onChange }) => ({
start() {
onChange(60);
},
sync() {
onChange(0);
return 0;
},
dispose() {},
});
const appApi = {
async getCaptchaRequirement(payload) {
calls.push({ type: "require", payload: { ...payload } });
return {
required: true,
providerCode: "TIANAI",
captchaType: "SLIDER",
sceneCode: payload.sceneCode,
ttlSeconds: 300,
};
},
async loginWithPassword(payload) {
calls.push({ type: "password-login", payload: { ...payload } });
return { access_token: "token-password" };
},
async sendSmsCode(payload) {
calls.push({ type: "sms-code", payload: { ...payload } });
return null;
},
async loginWithSms(payload) {
calls.push({ type: "sms-login", payload: { ...payload } });
return { access_token: "token-sms" };
},
};
const AUTH_TAC_SCENE = Object.freeze({ SMS_LOGIN: "APP_SMS_LOGIN" });
const createTacRenderContext = (value) => ({ ...value });
const isAuthPhone = (value) => /^1[3-9]\\d{9}$/.test(value);
const normalizeCaptchaRequirement = (value, expectedScene) => {
if (value?.sceneCode !== expectedScene || value?.required !== true) {
throw new Error("requirement invalid");
}
return value;
};
const normalizeTacSuccess = (value, expectedRequestId) => {
if (
!value ||
value.requestId !== expectedRequestId ||
typeof value.validToken !== "string" ||
!value.validToken
) {
throw new Error("TAC result invalid");
}
return value;
};
const runtimeConfig = {
baseUrl: "https://backend-api.ddxcjp.cn",
clientId: "client-1",
tenantId: "000000",
};
const calcMD5 = (value) => "md5:" + value;
const goRoot = async (pageId) => {
calls.push({ type: "go-root", pageId });
if (goRootError) throw goRootError;
return goRootResult;
};
const handleBackPress = () => false;
const openPage = () => {};
const runBackGuard = () => false;
const setTimeout = () => 1;
const clearTimeout = () => {};
const setInterval = () => 1;
const clearInterval = () => {};
${pageScript}
return {
calls,
phone,
password,
agreed,
tacVisible,
tacContext,
submitting,
authenticationCommitted,
feedbackMessage,
submitLogin,
completeTac,
closeTac,
setPendingTacAction(value) {
pendingTacAction = value;
},
};
`,
)(goRootResult, goRootError);
const createHarness = (options = {}) =>
createHarnessFactory(
options.goRootResult ?? true,
options.goRootError ?? null,
);
const countCalls = (harness, type) =>
harness.calls.filter((call) => call.type === type).length;
const preparePassword = async (harness, passwordValue = "secret-1") => {
harness.phone.value = "13800138000";
harness.password.value = passwordValue;
harness.agreed.value = true;
await harness.submitLogin();
assert.deepStrictEqual(harness.calls.map((call) => call.type), ["require"]);
assert.strictEqual(harness.submitting.value, false);
assert.strictEqual(harness.tacVisible.value, true);
assert(harness.tacContext.value?.requestId?.startsWith("a01-password-"));
};
const completePasswordTac = (harness) =>
harness.completeTac({
requestId: harness.tacContext.value.requestId,
validToken: "ticket-1",
expireSeconds: 300,
});
const run = async () => {
const success = createHarness();
await preparePassword(success);
assert.strictEqual(countCalls(success, "password-login"), 0);
await completePasswordTac(success);
assert.deepStrictEqual(
success.calls.map((call) => call.type),
["require", "password-login", "go-root"],
);
assert.deepStrictEqual(success.calls[1].payload, {
phone: "13800138000",
passwordHash: "md5:secret-1",
});
assert.strictEqual(success.calls[2].pageId, "G01");
assert.strictEqual(countCalls(success, "require"), 1);
assert.strictEqual(countCalls(success, "sms-code"), 0);
assert.strictEqual(success.tacVisible.value, false);
assert.strictEqual(success.tacContext.value, null);
const navigationRejected = createHarness({ goRootResult: false });
await preparePassword(navigationRejected);
await completePasswordTac(navigationRejected);
assert.strictEqual(navigationRejected.authenticationCommitted.value, true);
assert.match(navigationRejected.feedbackMessage.value, /登录已完成/);
assert.strictEqual(countCalls(navigationRejected, "password-login"), 1);
await navigationRejected.submitLogin();
assert.strictEqual(countCalls(navigationRejected, "password-login"), 1);
assert.strictEqual(countCalls(navigationRejected, "go-root"), 2);
const cancelled = createHarness();
await preparePassword(cancelled);
cancelled.closeTac();
await cancelled.completeTac({
requestId: "stale-request",
validToken: "ticket-stale",
expireSeconds: 300,
});
assert.strictEqual(countCalls(cancelled, "password-login"), 0);
assert.strictEqual(countCalls(cancelled, "sms-code"), 0);
process.stdout.write("A01-PASSWORD-LOGIN-RUNTIME-SMOKE PASS\n");
};
run().catch((error) => {
process.stderr.write(`${error.stack || error.message}\n`);
process.exit(1);
});