import { mockI18nSuccess, mockAllRequiredAPIs } from '../../support/mock/handlers/i18n';
import LoginPage from '../../support/pageObjects/LoginPage';
describe('多语言资源内容验证测试', () => {
const loginPage = new LoginPage();
beforeEach(() => {
cy.clearAllSessionStorage();
cy.clearAllLocalStorage();
// Mock所有必要的API,避免影响页面加载
mockAllRequiredAPIs();
});
it('验证中文翻译内容的正确性', () => {
mockI18nSuccess('zh');
cy.window().then((win) => {
Object.defineProperty(win.navigator, 'language', {
value: 'zh-CN',
writable: false
});
});
loginPage.visit();
cy.wait('@getI18nZHSuccess');
// 验证Redux状态中的中文翻译
cy.window().its('store').invoke('getState').then((state) => {
const messages = state.i18n.messages;
// 验证基础翻译
expect(messages).to.have.property('greeting', '你好,世界!');
expect(messages).to.have.property('name', '张三');
expect(messages).to.have.property('patient', '患者管理');
expect(messages).to.have.property('register', '注册');
expect(messages).to.have.property('worklist', '任务清单');
// 验证嵌套键名翻译
expect(messages).to.have.property('worklist.operationPanel', '操作面板');
expect(messages).to.have.property('register.basicInfoPanel', '基本信息表单区域');
expect(messages).to.have.property('worklistTable.patientId', '患者编号');
expect(messages).to.have.property('worklistTable.name', '患者姓名');
// 验证表单字段翻译
expect(messages).to.have.property('register.patientId', '患者编号');
expect(messages).to.have.property('register.patientName', '患者姓名');
expect(messages).to.have.property('register.gender', '性别');
expect(messages).to.have.property('register.gender.male', '男');
expect(messages).to.have.property('register.gender.female', '女');
});
// 验证页面显示的中文内容
cy.get('body').should('contain', '患者管理');
});
it('验证英文翻译内容的正确性', () => {
mockI18nSuccess('en');
cy.window().then((win) => {
Object.defineProperty(win.navigator, 'language', {
value: 'en-US',
writable: false
});
});
loginPage.visit();
cy.wait('@getI18nENSuccess');
// 验证Redux状态中的英文翻译
cy.window().its('store').invoke('getState').then((state) => {
const messages = state.i18n.messages;
// 验证基础翻译
expect(messages).to.have.property('greeting', 'Hello, world!');
expect(messages).to.have.property('name', 'John Doe');
expect(messages).to.have.property('patient', 'Patient Management');
expect(messages).to.have.property('register', 'Register');
expect(messages).to.have.property('worklist', 'Task List');
// 验证嵌套键名翻译
expect(messages).to.have.property('worklist.operationPanel', 'Operation Panel');
expect(messages).to.have.property('register.basicInfoPanel', 'Basic Information Form Area');
expect(messages).to.have.property('worklistTable.patientId', 'Patient ID');
expect(messages).to.have.property('worklistTable.name', 'Patient Name');
// 验证表单字段翻译
expect(messages).to.have.property('register.patientId', 'Patient ID');
expect(messages).to.have.property('register.patientName', 'Patient Name');
expect(messages).to.have.property('register.gender', 'Gender');
expect(messages).to.have.property('register.gender.male', 'Male');
expect(messages).to.have.property('register.gender.female', 'Female');
});
// 验证页面显示的英文内容
cy.get('body').should('contain', 'Patient Management');
});
it('验证中英文翻译的对应关系', () => {
// 定义需要验证的关键翻译对
const translationPairs = [
{ key: 'patient', zh: '患者管理', en: 'Patient Management' },
{ key: 'register', zh: '注册', en: 'Register' },
{ key: 'worklist', zh: '任务清单', en: 'Task List' },
{ key: 'register.patientId', zh: '患者编号', en: 'Patient ID' },
{ key: 'register.patientName', zh: '患者姓名', en: 'Patient Name' },
{ key: 'register.gender.male', zh: '男', en: 'Male' },
{ key: 'register.gender.female', zh: '女', en: 'Female' }
];
// 先验证中文
mockI18nSuccess('zh');
cy.window().then((win) => {
Object.defineProperty(win.navigator, 'language', {
value: 'zh-CN',
writable: false
});
});
loginPage.visit();
cy.wait('@getI18nZHSuccess');
cy.window().its('store').invoke('getState').then((zhState) => {
const zhMessages = zhState.i18n.messages;
// 验证中文翻译
translationPairs.forEach(({ key, zh }) => {
expect(zhMessages).to.have.property(key, zh);
});
});
// 再验证英文
mockI18nSuccess('en');
cy.window().then((win) => {
Object.defineProperty(win.navigator, 'language', {
value: 'en-US',
writable: false
});
});
loginPage.visit();
cy.wait('@getI18nENSuccess');
cy.window().its('store').invoke('getState').then((enState) => {
const enMessages = enState.i18n.messages;
// 验证英文翻译
translationPairs.forEach(({ key, en }) => {
expect(enMessages).to.have.property(key, en);
});
});
});
it('验证嵌套键名的正确解析', () => {
mockI18nSuccess('zh');
cy.window().then((win) => {
Object.defineProperty(win.navigator, 'language', {
value: 'zh-CN',
writable: false
});
});
loginPage.visit();
cy.wait('@getI18nZHSuccess');
cy.window().its('store').invoke('getState').then((state) => {
const messages = state.i18n.messages;
// 验证多层嵌套的键名
expect(messages).to.have.property('worklist.operationPanel', '操作面板');
expect(messages).to.have.property('register.basicInfoPanel', '基本信息表单区域');
expect(messages).to.have.property('register.protocolListPanel', '待选择协议列表区域');
expect(messages).to.have.property('register.selectedProtocolListPanel', '已选择协议列表区域');
// 验证表格相关的嵌套键名
expect(messages).to.have.property('worklistTable.patientId', '患者编号');
expect(messages).to.have.property('worklistTable.name', '患者姓名');
expect(messages).to.have.property('worklistTable.birthDate', '出生日期');
expect(messages).to.have.property('worklistTable.gender', '性别');
// 验证表单字段的嵌套键名
expect(messages).to.have.property('register.patientId', '患者编号');
expect(messages).to.have.property('register.patientName', '患者姓名');
expect(messages).to.have.property('register.gender.male', '男');
expect(messages).to.have.property('register.gender.female', '女');
});
});
it('验证特殊字符和格式的处理', () => {
// 创建包含特殊字符的mock数据
cy.intercept('GET', '/dr/api/v1/pub/trans/zh/zh.js', (req) => {
req.reply({
statusCode: 200,
body: {
'special.chars': '特殊字符:@#$%^&*()',
'unicode.emoji': '表情符号:😀 🎉 ✅ ❌',
'html.content': '粗体文本',
'quotes.single': "包含'单引号'的文本",
'quotes.double': '包含"双引号"的文本',
'newlines': '第一行\n第二行\n第三行',
'spaces': ' 前后有空格 ',
'numbers': '数字:123456789',
'mixed': '混合内容:123 ABC 中文 @#$ 😀'
}
});
}).as('getI18nZHSpecial');
cy.window().then((win) => {
Object.defineProperty(win.navigator, 'language', {
value: 'zh-CN',
writable: false
});
});
loginPage.visit();
cy.wait('@getI18nZHSpecial');
cy.window().its('store').invoke('getState').then((state) => {
const messages = state.i18n.messages;
// 验证特殊字符正确保存
expect(messages).to.have.property('special.chars', '特殊字符:@#$%^&*()');
expect(messages).to.have.property('unicode.emoji', '表情符号:😀 🎉 ✅ ❌');
expect(messages).to.have.property('html.content', '粗体文本');
expect(messages).to.have.property('quotes.single', "包含'单引号'的文本");
expect(messages).to.have.property('quotes.double', '包含"双引号"的文本');
expect(messages).to.have.property('newlines', '第一行\n第二行\n第三行');
expect(messages).to.have.property('spaces', ' 前后有空格 ');
expect(messages).to.have.property('numbers', '数字:123456789');
expect(messages).to.have.property('mixed', '混合内容:123 ABC 中文 @#$ 😀');
});
});
it('验证翻译内容的完整性', () => {
mockI18nSuccess('en');
cy.window().then((win) => {
Object.defineProperty(win.navigator, 'language', {
value: 'en-US',
writable: false
});
});
loginPage.visit();
cy.wait('@getI18nENSuccess');
cy.window().its('store').invoke('getState').then((state) => {
const messages = state.i18n.messages;
// 验证必要的翻译键都存在
const requiredKeys = [
'greeting',
'name',
'patient',
'register',
'worklist',
'register.patientId',
'register.patientName',
'register.gender',
'register.gender.male',
'register.gender.female',
'worklistTable.patientId',
'worklistTable.name'
];
requiredKeys.forEach(key => {
expect(messages).to.have.property(key);
expect(messages[key]).to.be.a('string');
expect(messages[key]).to.not.be.empty;
});
// 验证翻译内容不包含占位符或错误标记
Object.values(messages).forEach((value: any) => {
expect(value).to.not.include('TODO');
expect(value).to.not.include('FIXME');
expect(value).to.not.include('{{');
expect(value).to.not.include('}}');
expect(value).to.not.include('[MISSING]');
});
});
});
it('验证翻译内容的一致性', () => {
// 验证相同概念在不同上下文中的翻译一致性
mockI18nSuccess('zh');
cy.window().then((win) => {
Object.defineProperty(win.navigator, 'language', {
value: 'zh-CN',
writable: false
});
});
loginPage.visit();
cy.wait('@getI18nZHSuccess');
cy.window().its('store').invoke('getState').then((state) => {
const messages = state.i18n.messages;
// 验证"患者"相关翻译的一致性
expect(messages['register.patientId']).to.include('患者');
expect(messages['register.patientName']).to.include('患者');
expect(messages['worklistTable.patientId']).to.include('患者');
expect(messages['worklistTable.name']).to.include('患者');
// 验证性别翻译的一致性
expect(messages['register.gender.male']).to.equal('男');
expect(messages['register.gender.female']).to.equal('女');
});
});
it('验证翻译内容的长度和格式', () => {
mockI18nSuccess('en');
cy.window().then((win) => {
Object.defineProperty(win.navigator, 'language', {
value: 'en-US',
writable: false
});
});
loginPage.visit();
cy.wait('@getI18nENSuccess');
cy.window().its('store').invoke('getState').then((state) => {
const messages = state.i18n.messages;
// 验证翻译内容的合理长度
Object.entries(messages).forEach(([key, value]: [string, any]) => {
// 翻译内容不应该过长(假设最长不超过200字符)
expect(value.length).to.be.lessThan(200);
// 翻译内容不应该为空
expect(value.trim()).to.not.be.empty;
// 验证特定键的格式
if (key.includes('placeholder')) {
// placeholder应该以适当的提示开始
expect(value).to.match(/^(Enter|Please|Input)/i);
}
if (key.includes('button') || key === 'register' || key === 'print') {
// 按钮文本应该是动词或动作词
expect(value).to.not.include('.');
expect(value.length).to.be.lessThan(50);
}
});
});
});
it('验证动态内容的翻译支持', () => {
// 测试包含变量占位符的翻译(如果有的话)
cy.intercept('GET', '/dr/api/v1/pub/trans/zh/zh.js', (req) => {
req.reply({
statusCode: 200,
body: {
'dynamic.welcome': '欢迎,{name}!',
'dynamic.count': '共有 {count} 个项目',
'dynamic.date': '日期:{date}',
'validation.required': '{field} 是必填项',
'validation.minLength': '{field} 至少需要 {min} 个字符'
}
});
}).as('getI18nZHDynamic');
cy.window().then((win) => {
Object.defineProperty(win.navigator, 'language', {
value: 'zh-CN',
writable: false
});
});
loginPage.visit();
cy.wait('@getI18nZHDynamic');
cy.window().its('store').invoke('getState').then((state) => {
const messages = state.i18n.messages;
// 验证动态内容的占位符格式正确
expect(messages).to.have.property('dynamic.welcome', '欢迎,{name}!');
expect(messages).to.have.property('dynamic.count', '共有 {count} 个项目');
expect(messages).to.have.property('dynamic.date', '日期:{date}');
expect(messages).to.have.property('validation.required', '{field} 是必填项');
expect(messages).to.have.property('validation.minLength', '{field} 至少需要 {min} 个字符');
// 验证占位符格式一致性
Object.values(messages).forEach((value: any) => {
if (value.includes('{')) {
// 确保占位符格式正确:{变量名}
const placeholders = value.match(/\{[^}]+\}/g);
if (placeholders) {
placeholders.forEach((placeholder: string) => {
expect(placeholder).to.match(/^\{[a-zA-Z][a-zA-Z0-9]*\}$/);
});
}
}
});
});
});
});