/** * 测试文件: 进入检查 - History双击进入处理(已曝光) * 场景: 从History双击已曝光任务,系统应进入处理界面 * * 路径分析: * - POM: LoginPage, MainPage, HistoryPage * - Mock: * - mockLoginSuccess() - 登录成功 * - mockFetchHistoryDataWithUnlocked() - 获取History列表 * - mockGetStudyDetailsExposed() - 获取已曝光检查详情 * - 规格: * ✓ 登录成功 * ✓ 导航到History列表 * ✓ History列表显示至少2条记录 * ✓ 双击第一条已曝光记录 * ✓ 系统加载任务详细信息(已曝光状态) * ✓ 进入处理界面(businessFlow: 'process') * ✓ 验证Redux状态正确 * ✓ 验证bodyPositionList已转换 * * @see docs/测试/进入检查功能测试方案.md - 场景4 */ import { mockLoginSuccess } from '../../support/mock/handlers/user'; import { mockFetchHistoryDataWithUnlocked } from '../../support/mock/handlers/worklist'; import { mockGetStudyDetailsExposed } from '../../support/mock/handlers/study'; import LoginPage from '../../support/pageObjects/LoginPage'; import MainPage from '../../support/pageObjects/MainPage'; import HistoryPage from '../../support/pageObjects/HistoryPage'; describe('进入检查:History双击进入处理(已曝光)', () => { const loginPage = new LoginPage(); const mainPage = new MainPage(); const historyPage = new HistoryPage(); beforeEach(() => { // 设置所有必要的Mock mockLoginSuccess(); mockFetchHistoryDataWithUnlocked(); // 使用第一条History记录的StudyID,返回已曝光数据 mockGetStudyDetailsExposed('HIST20250912001'); }); it('应该通过双击History已曝光条目进入处理界面', () => { /** * Given: 用户已登录 * 步骤1(前置): 打开登录界面,完成登录 */ loginPage.visit(); loginPage.getUsernameInput().should('be.visible'); loginPage.login('admin', '123456'); // 等待登录成功 cy.wait('@loginSuccess'); cy.contains('登录成功').should('be.visible', { timeout: 10000 }); /** * When: 导航到History * 步骤1: 打开 History */ mainPage.clickPatientManagementButton(); mainPage.clickHistorylistButton(); /** * Then: 系统加载History任务信息 * 步骤2(前置): 验证History列表加载 */ cy.wait('@getHistoryUnlocked').then((interception) => { expect(interception.response?.statusCode).to.eq(200); }); // 验证History列表显示(至少2条记录) historyPage.getTable().should('be.visible'); historyPage.getTable().find('tr').should('have.length.at.least', 2); /** * When: 用户双击第一条已曝光任务 * 步骤2: 双击任务条目 */ historyPage.findTableAndDoubleClickFirstRow(); /** * Then: 系统加载任务详细信息(已曝光状态) * 步骤3: 验证API调用和返回数据 */ cy.wait('@getStudyDetailsExposed').then((interception) => { expect(interception.response?.statusCode).to.eq(200); // 验证返回的数据包含已曝光的检查信息 const studyData = interception.response?.body.data; expect(studyData).to.have.property('study_id'); expect(studyData).to.have.property('series'); expect(studyData.series).to.be.an('array'); // 验证所有images的expose_status为'Exposed' studyData.series.forEach((series: any) => { series.images.forEach((image: any) => { expect(image.expose_status).to.eq('Exposed'); // 已曝光的图像应该有文件路径 expect(image.image_file_path).to.not.be.empty; }); }); }); /** * Then: 验证Redux状态 - examWorksCache * 步骤4: 验证任务数据已缓存 */ cy.window() .its('store') .invoke('getState') .its('examWorksCache') .its('works') .should('have.length', 1) .its(0) .should('have.property', 'StudyID', 'HIST20250912001'); /** * Then: 验证Redux状态 - businessFlow * 步骤5: 验证进入处理流程(process模式) */ cy.window() .its('store') .invoke('getState') .its('businessFlow') .its('currentFlow') .should('eq', 'process'); /** * Then: 验证Redux状态 - bodyPositionList * 步骤6: 验证体位列表已正确转换 */ cy.window() .its('store') .invoke('getState') .its('bodyPositionList') .its('positions') .should('have.length.greaterThan', 0); }); it('应该在Redux中正确保存已曝光任务的Views数据', () => { /** * 这个测试用例专注于验证已曝光数据的正确性 */ loginPage.visit(); loginPage.login('admin', '123456'); cy.wait('@loginSuccess'); mainPage.clickPatientManagementButton(); mainPage.clickHistorylistButton(); cy.wait('@getHistoryUnlocked'); historyPage.findTableAndDoubleClickFirstRow(); cy.wait('@getStudyDetailsExposed'); /** * 验证Views数组包含已曝光数据 */ cy.window() .its('store') .invoke('getState') .its('examWorksCache') .its('works') .its(0) .its('Views') .should('be.an', 'array') .should('have.length.greaterThan', 0) .then((views: any[]) => { // 验证每个View都是已曝光状态 views.forEach((view) => { expect(view).to.have.property('view_id'); expect(view).to.have.property('view_description'); expect(view).to.have.property('expose_status', 'Exposed'); expect(view).to.have.property('study_id'); expect(view).to.have.property('series_instance_uid'); // 已曝光的View应该有图像文件路径 expect(view).to.have.property('image_file_path'); expect(view.image_file_path).to.not.be.empty; }); }); }); it('应该正确判断所有体位已曝光并进入处理流程', () => { /** * 这个测试用例验证曝光状态判断逻辑 */ loginPage.visit(); loginPage.login('admin', '123456'); cy.wait('@loginSuccess'); mainPage.clickPatientManagementButton(); mainPage.clickHistorylistButton(); cy.wait('@getHistoryUnlocked'); historyPage.findTableAndDoubleClickFirstRow(); cy.wait('@getStudyDetailsExposed'); /** * 验证所有体位都是已曝光状态 */ cy.window() .its('store') .invoke('getState') .its('examWorksCache') .its('works') .its(0) .its('Views') .then((views: any[]) => { // 确认Views不为空 expect(views.length).to.be.greaterThan(0); // 确认所有Views都是已曝光 const allExposed = views.every( (view) => view.expose_status === 'Exposed' ); expect(allExposed).to.be.true; }); /** * 验证系统正确进入处理流程 */ cy.window() .its('store') .invoke('getState') .its('businessFlow') .its('currentFlow') .should('eq', 'process'); }); it('应该正确从History进入处理流程', () => { /** * 验证从History进入处理流程的完整场景 */ loginPage.visit(); loginPage.login('admin', '123456'); cy.wait('@loginSuccess'); mainPage.clickPatientManagementButton(); mainPage.clickHistorylistButton(); cy.wait('@getHistoryUnlocked'); // 验证History记录的状态(已完成) cy.window() .its('store') .invoke('getState') .its('historyEntities') .its('data') .should('have.length.greaterThan', 0) .its(0) .should('have.property', 'study_status', 'Completed'); historyPage.findTableAndDoubleClickFirstRow(); cy.wait('@getStudyDetailsExposed'); // 验证进入处理流程 cy.window() .its('store') .invoke('getState') .its('businessFlow') .its('currentFlow') .should('eq', 'process'); // 验证examWorksCache包含从History加载的数据 cy.window() .its('store') .invoke('getState') .its('examWorksCache') .its('works') .its(0) .should('have.property', 'StudyID', 'HIST20250912001'); // 验证bodyPositionList已转换 cy.window() .its('store') .invoke('getState') .its('bodyPositionList') .its('positions') .should('have.length.greaterThan', 0); }); });