vending-machine/mobile/__tests__/user-auth.property.test.js
2026-04-08 20:45:41 +08:00

105 lines
3.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, it, expect, beforeEach, vi } from 'vitest'
import * as fc from 'fast-check'
import { TOKEN_KEY } from '../utils/storage.js'
// 模拟uni全局对象和请求
let mockStorage = {}
let requestSuccessCallback = null
beforeEach(() => {
mockStorage = {}
requestSuccessCallback = null
globalThis.uni = {
setStorageSync: (key, value) => { mockStorage[key] = value },
getStorageSync: (key) => mockStorage[key] || '',
removeStorageSync: (key) => { delete mockStorage[key] },
showToast: vi.fn(),
reLaunch: vi.fn(),
request: (options) => {
requestSuccessCallback = options.success
}
}
})
/**
* 动态导入模块
*/
async function loadModules() {
vi.resetModules()
const { createPinia, setActivePinia } = await import('pinia')
setActivePinia(createPinia())
const { useUserStore } = await import('../stores/user.js')
return { useUserStore }
}
describe('Property 4: 未勾选协议阻止登录', () => {
/**
* **Feature: mobile-app, Property 4: 未勾选协议阻止登录**
* **Validates: Requirements 2.3**
*
* 对于任意手机号和验证码输入当协议勾选状态为false时
* 调用登录操作应被阻止且不发出API请求。
*/
it('协议未勾选时登录应被阻止不发出API请求', async () => {
const phoneArb = fc.stringMatching(/^1[3-9]\d{9}$/)
const codeArb = fc.stringMatching(/^\d{4,6}$/)
const areaCodeArb = fc.constantFrom('+86', '+852', '+886', '+1')
await fc.assert(
fc.asyncProperty(phoneArb, codeArb, areaCodeArb, async (phone, code, areaCode) => {
const { useUserStore } = await loadModules()
const store = useUserStore()
// agreedToTerms = false
await expect(store.login(phone, code, areaCode, false)).rejects.toThrow('未同意协议')
// 不应发出API请求
expect(requestSuccessCallback).toBeNull()
// 应弹出提示
expect(uni.showToast).toHaveBeenCalledWith({ title: '请阅读并同意协议', icon: 'none' })
}),
{ numRuns: 100 }
)
})
})
describe('Property 5: 登录Token存储', () => {
/**
* **Feature: mobile-app, Property 5: 登录Token存储**
* **Validates: Requirements 2.5**
*
* 对于任意成功的登录API响应包含token字段
* 登录操作完成后本地存储中应包含该token值且用户状态应为已登录。
*/
it('登录成功后Token应存储到本地且状态为已登录', async () => {
const tokenArb = fc.string({ minLength: 10, maxLength: 200 }).filter(s => s.trim().length > 0)
await fc.assert(
fc.asyncProperty(tokenArb, async (token) => {
const { useUserStore } = await loadModules()
const store = useUserStore()
// 发起登录请求agreedToTerms = true
const loginPromise = store.login('13800138000', '123456', '+86', true)
// 模拟成功响应
requestSuccessCallback({
statusCode: 200,
data: { success: true, data: { token }, message: 'ok' }
})
await loginPromise
// 验证Token已存储到本地
expect(mockStorage[TOKEN_KEY]).toBe(token)
// 验证用户状态为已登录
expect(store.isLoggedIn).toBe(true)
expect(store.token).toBe(token)
}),
{ numRuns: 100 }
)
})
})