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

115 lines
3.5 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 } from 'vitest'
import * as fc from 'fast-check'
import { createI18n } from 'vue-i18n'
import zhCN from '../i18n/zh-CN.js'
import zhTW from '../i18n/zh-TW.js'
import en from '../i18n/en.js'
import { SUPPORTED_LOCALES } from '../i18n/index.js'
import { setStorage, getStorage, LOCALE_KEY } from '../utils/storage.js'
// 所有语言包
const messages = { 'zh-CN': zhCN, 'zh-TW': zhTW, 'en': en }
/**
* 递归收集所有翻译键(扁平化为 "a.b.c" 格式)
*/
function collectKeys(obj, prefix = '') {
let keys = []
for (const key of Object.keys(obj)) {
const fullKey = prefix ? `${prefix}.${key}` : key
if (typeof obj[key] === 'object' && obj[key] !== null) {
keys = keys.concat(collectKeys(obj[key], fullKey))
} else {
keys.push(fullKey)
}
}
return keys
}
/**
* 根据扁平键从对象中取值
*/
function getNestedValue(obj, path) {
return path.split('.').reduce((acc, part) => acc && acc[part], obj)
}
// 收集所有翻译键以zh-CN为基准
const allKeys = collectKeys(zhCN)
describe('Property 1: 语言切换翻译正确性', () => {
/**
* **Feature: mobile-app, Property 1: 语言切换翻译正确性**
* **Validates: Requirements 1.2**
*
* 对于任意支持的语言locale和任意翻译键key切换到该locale后
* 翻译函数t(key)应返回该语言对应的非空文本。
*/
it('切换到任意支持语言后,翻译函数返回对应的非空文本', () => {
const localeArb = fc.constantFrom(...SUPPORTED_LOCALES)
const keyArb = fc.constantFrom(...allKeys)
fc.assert(
fc.property(localeArb, keyArb, (locale, key) => {
const i18n = createI18n({
legacy: false,
locale,
messages
})
const result = i18n.global.t(key)
// 翻译结果应为非空字符串
expect(typeof result).toBe('string')
expect(result.length).toBeGreaterThan(0)
// 翻译结果应等于该语言包中的原始值(不含插值参数的情况下)
const expected = getNestedValue(messages[locale], key)
if (expected !== undefined && !String(expected).includes('{')) {
expect(result).toBe(String(expected))
}
}),
{ numRuns: 200 }
)
})
})
describe('Property 2: 语言设置持久化Round-Trip', () => {
/**
* **Feature: mobile-app, Property 2: 语言设置持久化Round-Trip**
* **Validates: Requirements 1.4, 1.5**
*
* 对于任意支持的语言locale设置语言后持久化到本地存储
* 再从本地存储读取并初始化最终的locale应等于最初设置的值。
*/
let mockStorage = {}
beforeEach(() => {
mockStorage = {}
globalThis.uni = {
setStorageSync: (key, value) => { mockStorage[key] = value },
getStorageSync: (key) => mockStorage[key] || '',
removeStorageSync: (key) => { delete mockStorage[key] },
getSystemInfoSync: () => ({ language: 'zh-CN' })
}
})
it('设置语言后持久化再读取locale保持一致', () => {
const localeArb = fc.constantFrom(...SUPPORTED_LOCALES)
fc.assert(
fc.property(localeArb, (targetLocale) => {
// 步骤1持久化语言设置
setStorage(LOCALE_KEY, targetLocale)
// 步骤2从存储中读取
const restored = getStorage(LOCALE_KEY)
// 验证:读取的值应等于设置的值
expect(restored).toBe(targetLocale)
}),
{ numRuns: 100 }
)
})
})