Files
photo-live/apps/viewer/src/__tests__/i18n.spec.ts
T
2026-09-21 23:10:58 +08:00

79 lines
3.5 KiB
TypeScript
Raw 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 { mount, type VueWrapper } from '@vue/test-utils';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { nextTick } from 'vue';
import App from '../App.vue';
import { LOCALE_STORAGE_KEY, createViewerI18n } from '../i18n';
import { router } from '../router';
// i18n 切换机制(顶栏 chrome 层):活动页级的「切换语言 → 重取内容」由
// activity.spec.ts 覆盖,此处聚焦首页 chrome(无需 api mock)。
// 逐挂载独立 i18n + 逐用例卸载(背景见 activity.spec.ts 头注)。
let i18n: ReturnType<typeof createViewerI18n>;
let wrapper: VueWrapper;
describe('viewer i18n', () => {
beforeEach(async () => {
localStorage.clear();
i18n = createViewerI18n('zh-CN');
await router.push('/');
await router.isReady();
wrapper = mount(App, { global: { plugins: [router, i18n] } });
});
afterEach(() => {
wrapper.unmount();
});
it('switching locale re-renders messages and persists the choice', async () => {
expect(wrapper.text()).toContain('打开相册链接即可观看');
expect(document.title).toBe('现场相册');
// UI-02 V01 紧凑语言控件:展开菜单 → 选择 English。
await wrapper.find('.locale-trigger').trigger('click');
await nextTick();
const english = wrapper.findAll('.locale-option').find((btn) => btn.text() === 'English');
expect(english).toBeDefined();
await english!.trigger('click');
await nextTick();
expect(wrapper.text()).toContain('Open an album link to start viewing');
expect(document.title).toBe('Live Gallery');
expect(document.documentElement.getAttribute('lang')).toBe('en');
expect(localStorage.getItem(LOCALE_STORAGE_KEY)).toBe('en');
// 切回 zh-CN 同样生效(菜单内当前语言 English 为勾选态)。
await wrapper.find('.locale-trigger').trigger('click');
await nextTick();
const options = wrapper.findAll('.locale-option');
const englishNow = options.find((btn) => btn.text() === 'English');
expect(englishNow!.attributes('aria-checked')).toBe('true');
const chinese = options.find((btn) => btn.text() === '中文');
expect(chinese!.attributes('aria-checked')).toBe('false');
await chinese!.trigger('click');
await nextTick();
expect(wrapper.text()).toContain('打开相册链接即可观看');
expect(localStorage.getItem(LOCALE_STORAGE_KEY)).toBe('zh-CN');
});
// UI-02 Task 6(V05 §5.4 分享链路闭环):分享 URL 携带 ?lang=,接收端
// 首载据此定语言——优先于本地持久化偏好;不合法值(fr/auto)自然回退。
it('initial locale honors the ?lang= share parameter over the stored preference', () => {
localStorage.setItem(LOCALE_STORAGE_KEY, 'zh-CN');
window.history.pushState({}, '', '/a/token?lang=en');
expect(createViewerI18n().global.locale.value).toBe('en');
// 非法/不支持值:回落到持久化偏好。
window.history.pushState({}, '', '/a/token?lang=auto');
expect(createViewerI18n().global.locale.value).toBe('zh-CN');
window.history.pushState({}, '', '/a/token?lang=fr');
expect(createViewerI18n().global.locale.value).toBe('zh-CN');
// 无参数:持久化偏好照旧生效。
window.history.pushState({}, '', '/a/token');
expect(createViewerI18n().global.locale.value).toBe('zh-CN');
// 参数不写 localStorage——接收者未做选择,显式切换才持久化。
expect(localStorage.getItem(LOCALE_STORAGE_KEY)).toBe('zh-CN');
});
});