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 } ) }) })