20260917212907

This commit is contained in:
oneao committed 2026-09-17 21:29:08 +08:00
1 parent 6fa3d8535e
commit 5cbf745bbf
115 files changed
+4104 -85

No files matched your search

@@ -0,0 +1,109 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createTestPinia } from '../helpers/app'
import { useI18nStore } from '@/stores/i18n'
import { BUILTIN_MESSAGES } from '@/i18n/builtin-messages'
const loadDataApi = vi.fn()
vi.mock('@/services/api', () => ({
loadDataApi: (...args) => loadDataApi(...args),
}))
/** 按 s_i18n 行结构构造返回值 */
function rows(locale, entries) {
return {
data: entries.map(([b_key, b_value]) => ({ b_key, b_locale: locale, b_value, b_canuse: 1 })),
}
}
beforeEach(() => {
loadDataApi.mockReset()
createTestPinia()
const i18n = useI18nStore()
i18n.setLocale('zh-CN')
i18n.clearMessages()
})
describe('i18n store · 译文加载(s_i18n)', () => {
it('加载当前语言译文并写入运行时(t 生效)', async () => {
loadDataApi.mockResolvedValue(rows('zh-CN', [['field.x.b_name', '客户名称']]))
const i18n = useI18nStore()
await i18n.loadMessages()
expect(loadDataApi).toHaveBeenCalledTimes(1)
const [viewName, condition] = loadDataApi.mock.calls[0]
expect(viewName).toBe('s_i18n')
expect(condition).toContain("b_locale = N'zh-CN'")
expect(condition).toContain('b_canuse = 1')
expect(i18n.t('field.x.b_name', '名称')).toBe('客户名称')
})
it('英文模式:内置 UI 文案兜底,库表译文覆盖同名 key', async () => {
loadDataApi.mockResolvedValue(rows('en-US', [['common.cancel', 'Cancel!!']]))
const i18n = useI18nStore()
i18n.setLocale('en-US')
await i18n.loadMessages()
// 库里有的以库为准
expect(i18n.t('common.cancel', '取消')).toBe('Cancel!!')
// 库里没有的走前端内置英文
expect(i18n.t('common.applyQuery', '应用')).toBe(BUILTIN_MESSAGES['en-US']['common.applyQuery'])
expect(i18n.t('common.applyQuery', '应用')).toBe('Apply')
})
it('切换语言后重新加载,且缓存命中不再发请求', async () => {
loadDataApi.mockResolvedValue(rows('zh-CN', [['k', '中文']]))
const i18n = useI18nStore()
await i18n.loadMessages()
expect(loadDataApi).toHaveBeenCalledTimes(1)
// 切到英文:新语言未缓存 → 发请求
loadDataApi.mockResolvedValue(rows('en-US', [['k', 'EN']]))
i18n.setLocale('en-US')
await i18n.loadMessages('en-US')
expect(loadDataApi).toHaveBeenCalledTimes(2)
expect(i18n.t('k', 'x')).toBe('EN')
// 切回中文:命中缓存 → 不再请求,但译文要切回来
i18n.setLocale('zh-CN')
await i18n.loadMessages()
expect(loadDataApi).toHaveBeenCalledTimes(2)
expect(i18n.t('k', 'x')).toBe('中文')
})
it('并发同语言只发一个请求', async () => {
loadDataApi.mockResolvedValue(rows('zh-CN', [['k', 'v']]))
const i18n = useI18nStore()
await Promise.all([i18n.loadMessages(), i18n.loadMessages(), i18n.loadMessages()])
expect(loadDataApi).toHaveBeenCalledTimes(1)
})
it('接口失败不抛出,界面回落兜底文案', async () => {
loadDataApi.mockRejectedValue(new Error('boom'))
const i18n = useI18nStore()
await expect(i18n.loadMessages()).resolves.toEqual({})
expect(i18n.t('common.cancel', '取消')).toBe('取消')
expect(i18n.error).toBe('boom')
})
it('b_locale 走转义,单引号不会拼坏 SQL', async () => {
loadDataApi.mockResolvedValue({ data: [] })
const i18n = useI18nStore()
await i18n.loadMessages("zh'; drop table s_i18n --")
expect(loadDataApi.mock.calls[0][1]).toContain("N'zh''; drop table s_i18n --'")
})
it('请求回来时语言已被切走则不覆盖当前译文', async () => {
let resolveQuery
loadDataApi.mockReturnValue(new Promise((r) => (resolveQuery = r)))
const i18n = useI18nStore()
const pending = i18n.loadMessages()
i18n.setLocale('en-US')
resolveQuery({ data: [{ b_key: 'k', b_value: '中文值' }] })
await pending
// 当前是英文,中文译文不应写进运行时(英文下 k 无译文 → 回落 fallback)
expect(i18n.t('k', 'fallback')).toBe('fallback')
})
})