238 行
10 KiB
JavaScript
238 行
10 KiB
JavaScript
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
let passed = 0;
|
||
let failed = 0;
|
||
|
||
function assert(condition, testName, detail = '') {
|
||
if (condition) {
|
||
console.log(` [PASS] ${testName}`);
|
||
passed++;
|
||
} else {
|
||
console.error(` [FAIL] ${testName} - ${detail}`);
|
||
failed++;
|
||
}
|
||
}
|
||
|
||
console.log("========================================================");
|
||
console.log(" 微信小程序默认登录采用手机号一键快捷登录规格测试");
|
||
console.log("========================================================\n");
|
||
|
||
// 1. 后端服务层: MiniProgram.php
|
||
const miniProgramPhpPath = path.resolve(__dirname, '../addons/shopro/service/third/wechat/MiniProgram.php');
|
||
assert(fs.existsSync(miniProgramPhpPath), 'MiniProgram.php 文件存在');
|
||
const miniProgramPhpContent = fs.readFileSync(miniProgramPhpPath, 'utf-8');
|
||
|
||
assert(
|
||
miniProgramPhpContent.includes('wxa/business/getuserphonenumber') && miniProgramPhpContent.includes("['code']"),
|
||
'MiniProgram.php 支持微信新版 code 获取手机号接口',
|
||
'未包含 wxa/business/getuserphonenumber 逻辑'
|
||
);
|
||
|
||
assert(
|
||
miniProgramPhpContent.includes('encryptor->decryptData') && miniProgramPhpContent.includes('purePhoneNumber'),
|
||
'MiniProgram.php 保留传统 iv + encryptedData 解密降级兼容',
|
||
'未包含 decryptData 解密兼容'
|
||
);
|
||
|
||
assert(
|
||
miniProgramPhpContent.includes('$mobile = $this->getUserPhoneNumber()') && miniProgramPhpContent.includes("'mobile' => $mobile"),
|
||
'MiniProgram.php 在 login() 方法中当传入手机号凭证时自动提取 mobile',
|
||
'login() 中未提取手机号'
|
||
);
|
||
|
||
// 2. 后端服务层: Wechat.php
|
||
const wechatServicePath = path.resolve(__dirname, '../addons/shopro/service/third/wechat/Wechat.php');
|
||
assert(fs.existsSync(wechatServicePath), 'Wechat.php (Service) 文件存在');
|
||
const wechatServiceContent = fs.readFileSync(wechatServicePath, 'utf-8');
|
||
|
||
assert(
|
||
wechatServiceContent.includes("UserModel::where('mobile', $extend['mobile'])->find()"),
|
||
'Wechat.php 在 registerOrBindUser 中检查已有手机号并直接绑定关联',
|
||
'未检测到已有手机号用户直接关联逻辑'
|
||
);
|
||
|
||
assert(
|
||
wechatServiceContent.includes('$user->mobile = $extend['),
|
||
'Wechat.php 为已绑定微信但尚无手机号的用户自动补充手机号',
|
||
'未检测到已绑定账号补充手机号逻辑'
|
||
);
|
||
|
||
// 3. 后端控制器层: Wechat.php
|
||
const wechatControllerPath = path.resolve(__dirname, '../addons/shopro/controller/third/Wechat.php');
|
||
assert(fs.existsSync(wechatControllerPath), 'Wechat.php (Controller) 文件存在');
|
||
const wechatControllerContent = fs.readFileSync(wechatControllerPath, 'utf-8');
|
||
|
||
assert(
|
||
wechatControllerContent.includes("'token' => $auth->isLogin() ? $auth->getToken() : ''"),
|
||
'Wechat.php (Controller) 在 login 成功响应数据中返回 token',
|
||
'响应未返回 token'
|
||
);
|
||
|
||
// 4. 前端平台驱动层: miniProgram.js
|
||
const miniProgramJsPath = path.resolve(__dirname, '../uniapp/sheep/platform/provider/wechat/miniProgram.js');
|
||
assert(fs.existsSync(miniProgramJsPath), 'miniProgram.js 文件存在');
|
||
const miniProgramJsContent = fs.readFileSync(miniProgramJsPath, 'utf-8');
|
||
|
||
assert(
|
||
miniProgramJsContent.includes('const mobileLogin = async (e) => {') && miniProgramJsContent.includes('third.wechat.login'),
|
||
'miniProgram.js 包含封装完善的 mobileLogin 方法',
|
||
'未包含 mobileLogin 方法'
|
||
);
|
||
|
||
assert(
|
||
miniProgramJsContent.includes('mobileLogin,') && miniProgramJsContent.includes('export default {'),
|
||
'miniProgram.js 在 export default 中导出了 mobileLogin',
|
||
'未导出 mobileLogin'
|
||
);
|
||
|
||
// 5. 前端弹窗状态控制: useModal.js
|
||
const useModalPath = path.resolve(__dirname, '../uniapp/sheep/hooks/useModal.js');
|
||
assert(fs.existsSync(useModalPath), 'useModal.js 文件存在');
|
||
const useModalContent = fs.readFileSync(useModalPath, 'utf-8');
|
||
|
||
assert(
|
||
useModalContent.includes('MP-WEIXIN') && useModalContent.includes("targetType = 'mpMobileLogin'"),
|
||
'useModal.js 微信小程序环境下默认弹窗类型为 mpMobileLogin',
|
||
'未设置微信小程序默认弹窗类型为 mpMobileLogin'
|
||
);
|
||
|
||
// 6. 新增组件: mp-mobile-login.vue
|
||
const mpMobileLoginPath = path.resolve(__dirname, '../uniapp/sheep/components/s-auth-modal/components/mp-mobile-login.vue');
|
||
assert(fs.existsSync(mpMobileLoginPath), 'mp-mobile-login.vue 文件存在');
|
||
const mpMobileLoginContent = fs.readFileSync(mpMobileLoginPath, 'utf-8');
|
||
|
||
assert(
|
||
mpMobileLoginContent.includes('open-type="getPhoneNumber"') && mpMobileLoginContent.includes('@getphonenumber="onGetPhoneNumber"'),
|
||
'mp-mobile-login.vue 包含 open-type="getPhoneNumber" 授权按钮',
|
||
'缺少 getPhoneNumber 授权按钮'
|
||
);
|
||
|
||
assert(
|
||
mpMobileLoginContent.includes("showAuthModal('smsLogin')") && mpMobileLoginContent.includes("showAuthModal('accountLogin')"),
|
||
'mp-mobile-login.vue 提供切换短信登录和账号登录的快速入口',
|
||
'缺少其他登录方式入口'
|
||
);
|
||
|
||
assert(
|
||
mpMobileLoginContent.includes('agreeStatus') && mpMobileLoginContent.includes('mobileLogin'),
|
||
'mp-mobile-login.vue 校验用户协议并调用 mobileLogin 登录',
|
||
'缺少协议校验或登录调用'
|
||
);
|
||
|
||
// 7. 弹窗容器: s-auth-modal.vue
|
||
const sAuthModalPath = path.resolve(__dirname, '../uniapp/sheep/components/s-auth-modal/s-auth-modal.vue');
|
||
assert(fs.existsSync(sAuthModalPath), 's-auth-modal.vue 文件存在');
|
||
const sAuthModalContent = fs.readFileSync(sAuthModalPath, 'utf-8');
|
||
|
||
assert(
|
||
sAuthModalContent.includes("import mpMobileLogin from './components/mp-mobile-login.vue'") && sAuthModalContent.includes("authType === 'mpMobileLogin'"),
|
||
's-auth-modal.vue 成功挂载 mp-mobile-login 组件',
|
||
'未挂载 mp-mobile-login'
|
||
);
|
||
|
||
assert(
|
||
sAuthModalContent.includes("'mpMobileLogin'") && sAuthModalContent.includes('agreement-box'),
|
||
's-auth-modal.vue 协议栏支持 mpMobileLogin 显示与勾选状态关联',
|
||
'协议栏未支持 mpMobileLogin'
|
||
);
|
||
|
||
// 8. 个人中心卡片组件: s-user-card.vue
|
||
const sUserCardPath = path.resolve(__dirname, '../uniapp/sheep/components/s-user-card/s-user-card.vue');
|
||
assert(fs.existsSync(sUserCardPath), 's-user-card.vue 文件存在');
|
||
const sUserCardContent = fs.readFileSync(sUserCardPath, 'utf-8');
|
||
|
||
assert(
|
||
sUserCardContent.includes('#ifdef MP-WEIXIN') && sUserCardContent.includes('open-type="getPhoneNumber"') && sUserCardContent.includes('@getphonenumber="onQuickLogin"'),
|
||
's-user-card.vue 在微信小程序端未登录时渲染 open-type="getPhoneNumber" 快捷登录按钮',
|
||
'未检测到微信小程序快捷登录按钮'
|
||
);
|
||
|
||
assert(
|
||
sUserCardContent.includes('async function onQuickLogin(e)') && sUserCardContent.includes("mobileLogin(e.detail)"),
|
||
's-user-card.vue 包含 onQuickLogin 处理函数调用 mobileLogin 完成快捷登录',
|
||
'未检测到 onQuickLogin 处理逻辑'
|
||
);
|
||
|
||
assert(
|
||
sUserCardContent.includes('hasBoundMobile') && sUserCardContent.includes('userInfo.value?.mobile || userInfo.value?.verification?.mobile'),
|
||
's-user-card.vue 使用 hasBoundMobile 判定:只要存在手机号则不展示绑定提示条',
|
||
'缺少 hasBoundMobile 判定逻辑'
|
||
);
|
||
|
||
assert(
|
||
sUserCardContent.includes('onBindPhoneNumber') && sUserCardContent.includes('bindUserPhoneNumber(e.detail)'),
|
||
's-user-card.vue 在微信小程序端去绑定支持 open-type="getPhoneNumber" 一键绑定',
|
||
'缺少一键去绑定逻辑'
|
||
);
|
||
|
||
assert(
|
||
sUserCardContent.includes('#ifndef MP-WEIXIN') && sUserCardContent.includes('showAuthModal()'),
|
||
's-user-card.vue 保留非微信小程序端正常点击弹窗唤醒逻辑',
|
||
'未保留非微信小程序端唤醒逻辑'
|
||
);
|
||
|
||
// 9. 用户模型与用户仓库:User.php & user.js
|
||
const userModelPath = path.resolve(__dirname, '../application/admin/model/shopro/user/User.php');
|
||
assert(fs.existsSync(userModelPath), 'User.php 模型存在');
|
||
const userModelContent = fs.readFileSync(userModelPath, 'utf-8');
|
||
|
||
assert(
|
||
userModelContent.includes("if (!empty($data['mobile']))") && userModelContent.includes("$value['mobile'] = 1"),
|
||
'User.php 模型 getVerificationAttr 当会员已有手机号时自动认定 mobile = 1',
|
||
'缺少 mobile 存在时自动认定 mobile = 1 逻辑'
|
||
);
|
||
|
||
assert(
|
||
userModelContent.includes('function setVerificationAttr'),
|
||
'User.php 模型定义了 setVerificationAttr 支持对象/数组自动 json 序列化',
|
||
'缺少 setVerificationAttr 方法'
|
||
);
|
||
|
||
const userStorePath = path.resolve(__dirname, '../uniapp/sheep/store/user.js');
|
||
assert(fs.existsSync(userStorePath), 'user.js Store 存在');
|
||
const userStoreContent = fs.readFileSync(userStorePath, 'utf-8');
|
||
|
||
assert(
|
||
userStoreContent.includes('if (merged.mobile)') && userStoreContent.includes('mobile: 1'),
|
||
'user.js getInfo() 当存在 mobile 时自动认定 verification.mobile = 1',
|
||
'缺少 getInfo() 补充 verification.mobile 逻辑'
|
||
);
|
||
|
||
// 10. 售后申请页编译修复: apply.vue
|
||
const applyVuePath = path.resolve(__dirname, '../uniapp/pages/order/aftersale/apply.vue');
|
||
assert(fs.existsSync(applyVuePath), 'apply.vue 存在');
|
||
const applyVueContent = fs.readFileSync(applyVuePath, 'utf-8');
|
||
|
||
assert(
|
||
applyVueContent.includes(':modelValue="formData"') && !applyVueContent.includes('v-model="formData"'),
|
||
'apply.vue 使用 :modelValue="formData" 消除 const 重赋值编译错误',
|
||
'仍包含 v-model="formData"'
|
||
);
|
||
|
||
assert(
|
||
applyVueContent.includes('let formData = reactive({'),
|
||
'apply.vue 中 formData 使用 let 声明提供双重防护',
|
||
'formData 不是 let 声明'
|
||
);
|
||
|
||
// 11. bindUserPhoneNumber 弹性支持与自动更新
|
||
assert(
|
||
miniProgramJsContent.includes('bindUserPhoneNumber') && miniProgramJsContent.includes("sheep.$store('user').getInfo()"),
|
||
'miniProgram.js bindUserPhoneNumber 成功后自动调用 getInfo() 刷新用户信息',
|
||
'bindUserPhoneNumber 未自动刷新用户信息'
|
||
);
|
||
|
||
// 12. 个人中心绑定横条受 showBindMobile 精确控制(微信小程序环境不冗余展示)
|
||
assert(
|
||
sUserCardContent.includes('v-if="showBindMobile"') && sUserCardContent.includes('#ifdef MP-WEIXIN'),
|
||
's-user-card.vue 使用 showBindMobile 精确控制,微信小程序端不显示冗余绑定提示条',
|
||
'未配置 showBindMobile 精确控制'
|
||
);
|
||
|
||
console.log("\n--------------------------------------------------------");
|
||
console.log(`测试执行结果: 通过 ${passed} 项, 失败 ${failed} 项`);
|
||
console.log("========================================================");
|
||
|
||
process.exit(failed === 0 ? 0 : 1);
|