age-dob-sync.cy.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. import dayjs from 'dayjs';
  2. import { mockLoginSuccess } from '../../support/mock/handlers/user';
  3. describe('年龄和出生日期联动功能测试', () => {
  4. beforeEach(() => {
  5. // 设置登录 Mock
  6. mockLoginSuccess();
  7. // 登录并进入注册页面
  8. cy.visit('/');
  9. cy.get('[data-testid="username"]').type('admin');
  10. cy.get('[data-testid="password"]').type('123456');
  11. cy.get('[data-testid="login-button"]').click();
  12. cy.wait('@loginSuccess');
  13. // 导航到患者管理 -> 注册页面
  14. cy.get('[data-testid="patient-management"]').click();
  15. cy.get('[data-testid="register"]').click();
  16. cy.wait(1000); // 等待页面加载
  17. });
  18. describe('场景1:修改年龄自动更新出生日期', () => {
  19. it('应该在修改年龄为25年时,自动更新出生日期为25年前', () => {
  20. // 获取年龄输入框和出生日期选择器
  21. const ageInput = cy.get('[data-testid="patient_age-number"]').should('exist');
  22. const ageUnitSelect = cy.get('[data-testid="patient_age-unit"]').should('exist');
  23. const dobPicker = cy.get('[data-testid="patient_dob"]').should('exist');
  24. // 修改年龄为25
  25. ageInput.clear().type('25');
  26. // 确认单位为"年"
  27. ageUnitSelect.click();
  28. cy.contains('.ant-select-item-option-content', '年').click();
  29. // 等待联动更新
  30. cy.wait(500);
  31. // 验证出生日期已更新(应该是25年前的日期)
  32. const expectedDate = dayjs().subtract(25, 'year');
  33. dobPicker.should(($input) => {
  34. const value = $input.val() as string;
  35. const selectedDate = dayjs(value);
  36. // 允许1天的误差
  37. expect(Math.abs(selectedDate.diff(expectedDate, 'day'))).to.be.lessThan(2);
  38. });
  39. // 验证Redux store
  40. cy.window().its('store').invoke('getState').its('form').its('formData').its('patient_dob').should('exist');
  41. });
  42. it('应该在修改年龄为6月时,自动更新出生日期为6个月前', () => {
  43. const ageInput = cy.get('[data-testid="patient_age-number"]').should('exist');
  44. const ageUnitSelect = cy.get('[data-testid="patient_age-unit"]').should('exist');
  45. const dobPicker = cy.get('[data-testid="patient_dob"]').should('exist');
  46. // 修改年龄为6月
  47. ageInput.clear().type('6');
  48. ageUnitSelect.click();
  49. cy.contains('.ant-select-item-option-content', '月').click();
  50. cy.wait(500);
  51. // 验证出生日期(应该是6个月前)
  52. const expectedDate = dayjs().subtract(6, 'month');
  53. dobPicker.should(($input) => {
  54. const value = $input.val() as string;
  55. const selectedDate = dayjs(value);
  56. expect(Math.abs(selectedDate.diff(expectedDate, 'day'))).to.be.lessThan(2);
  57. });
  58. });
  59. it('应该在修改年龄为15天时,自动更新出生日期为15天前', () => {
  60. const ageInput = cy.get('[data-testid="patient_age-number"]').should('exist');
  61. const ageUnitSelect = cy.get('[data-testid="patient_age-unit"]').should('exist');
  62. const dobPicker = cy.get('[data-testid="patient_dob"]').should('exist');
  63. // 修改年龄为15天
  64. ageInput.clear().type('15');
  65. ageUnitSelect.click();
  66. cy.contains('.ant-select-item-option-content', '天').click();
  67. cy.wait(500);
  68. // 验证出生日期(应该是15天前)
  69. const expectedDate = dayjs().subtract(15, 'day');
  70. dobPicker.should(($input) => {
  71. const value = $input.val() as string;
  72. const selectedDate = dayjs(value);
  73. expect(Math.abs(selectedDate.diff(expectedDate, 'day'))).to.be.lessThan(2);
  74. });
  75. });
  76. });
  77. describe('场景2:修改出生日期自动更新年龄', () => {
  78. it('应该在选择出生日期为2000-01-01时,自动计算并更新年龄', () => {
  79. const dobPicker = cy.get('[data-testid="patient_dob"]').should('exist');
  80. const ageInput = cy.get('[data-testid="patient_age-number"]').should('exist');
  81. const ageUnitSelect = cy.get('[data-testid="patient_age-unit"]').should('exist');
  82. // 点击出生日期选择器
  83. dobPicker.click();
  84. // 选择年份2000
  85. cy.get('.ant-picker-year-btn').click();
  86. cy.contains('.ant-picker-cell', '2000').click();
  87. // 选择月份1月
  88. cy.get('.ant-picker-month-btn').click();
  89. cy.contains('.ant-picker-cell', '一月').click();
  90. // 选择日期1日
  91. cy.contains('.ant-picker-cell', '1').first().click();
  92. cy.wait(500);
  93. // 验证年龄自动更新
  94. const expectedYears = dayjs().diff(dayjs('2000-01-01'), 'year');
  95. ageInput.should('have.value', expectedYears.toString());
  96. // 验证单位为"年"
  97. ageUnitSelect.should(($select) => {
  98. const text = $select.text();
  99. expect(text).to.contain('年');
  100. });
  101. });
  102. it('应该在选择6个月前的日期时,年龄单位自动设置为"月"', () => {
  103. const dobPicker = cy.get('[data-testid="patient_dob"]').should('exist');
  104. const ageInput = cy.get('[data-testid="patient_age-number"]').should('exist');
  105. const ageUnitSelect = cy.get('[data-testid="patient_age-unit"]').should('exist');
  106. // 选择6个月前的日期
  107. const targetDate = dayjs().subtract(6, 'month');
  108. dobPicker.click();
  109. // 选择年份
  110. cy.get('.ant-picker-year-btn').click();
  111. cy.contains('.ant-picker-cell', targetDate.year().toString()).click();
  112. // 选择月份
  113. cy.get('.ant-picker-month-btn').click();
  114. const monthNames = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
  115. cy.contains('.ant-picker-cell', monthNames[targetDate.month()]).click();
  116. // 选择日期
  117. cy.contains('.ant-picker-cell', targetDate.date().toString()).click();
  118. cy.wait(500);
  119. // 验证年龄约为6个月
  120. ageInput.should(($input) => {
  121. const value = parseInt($input.val() as string);
  122. expect(value).to.be.closeTo(6, 1);
  123. });
  124. // 验证单位为"月"
  125. ageUnitSelect.should(($select) => {
  126. const text = $select.text();
  127. expect(text).to.contain('月');
  128. });
  129. });
  130. it('应该在选择未来日期时,年龄显示为0天', () => {
  131. const dobPicker = cy.get('[data-testid="patient_dob"]').should('exist');
  132. const ageInput = cy.get('[data-testid="patient_age-number"]').should('exist');
  133. const ageUnitSelect = cy.get('[data-testid="patient_age-unit"]').should('exist');
  134. // 选择明年的日期
  135. const futureDate = dayjs().add(1, 'year');
  136. dobPicker.click();
  137. cy.get('.ant-picker-year-btn').click();
  138. cy.contains('.ant-picker-cell', futureDate.year().toString()).click();
  139. cy.get('.ant-picker-month-btn').click();
  140. const monthNames = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
  141. cy.contains('.ant-picker-cell', monthNames[futureDate.month()]).click();
  142. cy.contains('.ant-picker-cell', futureDate.date().toString()).click();
  143. cy.wait(500);
  144. // 验证年龄为0
  145. ageInput.should('have.value', '0');
  146. // 验证单位为"天"
  147. ageUnitSelect.should(($select) => {
  148. const text = $select.text();
  149. expect(text).to.contain('天');
  150. });
  151. });
  152. });
  153. describe('场景3:快速连续修改不产生循环', () => {
  154. it('应该能够连续修改年龄和出生日期而不出错', () => {
  155. const ageInput = cy.get('[data-testid="patient_age-number"]').should('exist');
  156. const ageUnitSelect = cy.get('[data-testid="patient_age-unit"]').should('exist');
  157. const dobPicker = cy.get('[data-testid="patient_dob"]').should('exist');
  158. // 第一次:修改年龄为25
  159. ageInput.clear().type('25');
  160. ageUnitSelect.click();
  161. cy.contains('.ant-select-item-option-content', '年').click();
  162. cy.wait(300);
  163. // 第二次:修改出生日期
  164. dobPicker.click();
  165. cy.get('.ant-picker-year-btn').click();
  166. cy.contains('.ant-picker-cell', '2000').click();
  167. cy.get('.ant-picker-month-btn').click();
  168. cy.contains('.ant-picker-cell', '一月').click();
  169. cy.contains('.ant-picker-cell', '1').first().click();
  170. cy.wait(300);
  171. // 第三次:再次修改年龄为30
  172. ageInput.clear().type('30');
  173. cy.wait(300);
  174. // 验证最终状态一致
  175. ageInput.should('have.value', '30');
  176. // 不应该有控制台错误
  177. cy.window().then((win) => {
  178. expect(win.console.error).not.to.be.called;
  179. });
  180. });
  181. });
  182. describe('场景4:表单提交时数据正确', () => {
  183. it('应该在提交表单时包含正确的年龄和出生日期数据', () => {
  184. // 填写必填项
  185. cy.get('input[name="accession_number"]').type('ACC001');
  186. cy.get('input[name="patient_id"]').type('P001');
  187. cy.get('input[name="patient_name"]').type('测试患者');
  188. // 修改年龄为25岁
  189. const ageInput = cy.get('[data-testid="patient_age-number"]');
  190. const ageUnitSelect = cy.get('[data-testid="patient_age-unit"]');
  191. ageInput.clear().type('25');
  192. ageUnitSelect.click();
  193. cy.contains('.ant-select-item-option-content', '年').click();
  194. cy.wait(500);
  195. // 验证Redux store中的数据
  196. cy.window().its('store').invoke('getState').its('form').its('formData').should((formData) => {
  197. // 验证年龄数据
  198. expect(formData.patient_age).to.exist;
  199. expect(formData.patient_age.number).to.equal(25);
  200. expect(formData.patient_age.unit).to.equal('Y');
  201. // 验证出生日期数据
  202. expect(formData.patient_dob).to.exist;
  203. });
  204. });
  205. });
  206. describe('场景5:边界情况处理', () => {
  207. it('应该正确处理年龄为0的情况', () => {
  208. const ageInput = cy.get('[data-testid="patient_age-number"]');
  209. const dobPicker = cy.get('[data-testid="patient_dob"]');
  210. // 设置年龄为0
  211. ageInput.clear().type('0');
  212. cy.wait(500);
  213. // 出生日期应该是今天
  214. dobPicker.should(($input) => {
  215. const value = $input.val() as string;
  216. const selectedDate = dayjs(value);
  217. const today = dayjs();
  218. expect(Math.abs(selectedDate.diff(today, 'day'))).to.be.lessThan(1);
  219. });
  220. });
  221. it('应该正确处理极大年龄(如100岁)', () => {
  222. const ageInput = cy.get('[data-testid="patient_age-number"]');
  223. const ageUnitSelect = cy.get('[data-testid="patient_age-unit"]');
  224. const dobPicker = cy.get('[data-testid="patient_dob"]');
  225. // 设置年龄为100岁
  226. ageInput.clear().type('100');
  227. ageUnitSelect.click();
  228. cy.contains('.ant-select-item-option-content', '年').click();
  229. cy.wait(500);
  230. // 出生日期应该是100年前
  231. const expectedDate = dayjs().subtract(100, 'year');
  232. dobPicker.should(($input) => {
  233. const value = $input.val() as string;
  234. const selectedDate = dayjs(value);
  235. expect(Math.abs(selectedDate.diff(expectedDate, 'day'))).to.be.lessThan(2);
  236. });
  237. });
  238. it('应该正确处理1岁以下年龄的单位切换', () => {
  239. const ageInput = cy.get('[data-testid="patient_age-number"]');
  240. const ageUnitSelect = cy.get('[data-testid="patient_age-unit"]');
  241. // 设置年龄为11月
  242. ageInput.clear().type('11');
  243. ageUnitSelect.click();
  244. cy.contains('.ant-select-item-option-content', '月').click();
  245. cy.wait(500);
  246. // 修改出生日期,触发反向计算
  247. const dobPicker = cy.get('[data-testid="patient_dob"]');
  248. const targetDate = dayjs().subtract(11, 'month');
  249. dobPicker.click();
  250. cy.get('.ant-picker-year-btn').click();
  251. cy.contains('.ant-picker-cell', targetDate.year().toString()).click();
  252. cy.get('.ant-picker-month-btn').click();
  253. const monthNames = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
  254. cy.contains('.ant-picker-cell', monthNames[targetDate.month()]).click();
  255. cy.contains('.ant-picker-cell', targetDate.date().toString()).click();
  256. cy.wait(500);
  257. // 验证年龄约为11个月
  258. ageInput.should(($input) => {
  259. const value = parseInt($input.val() as string);
  260. expect(value).to.be.closeTo(11, 1);
  261. });
  262. // 验证单位为"月"
  263. ageUnitSelect.should(($select) => {
  264. const text = $select.text();
  265. expect(text).to.contain('月');
  266. });
  267. });
  268. });
  269. describe('场景6:初始化时的联动', () => {
  270. it('应该在表单加载时保持初始值的一致性', () => {
  271. const ageInput = cy.get('[data-testid="patient_age-number"]');
  272. const dobPicker = cy.get('[data-testid="patient_dob"]');
  273. // 验证初始值都存在
  274. ageInput.should('have.value');
  275. dobPicker.should('have.value');
  276. // 验证Redux store中的数据
  277. cy.window().its('store').invoke('getState').its('form').its('formData').should((formData) => {
  278. if (formData.patient_age && formData.patient_dob) {
  279. // 如果两个字段都有值,验证它们的一致性
  280. expect(formData.patient_age).to.exist;
  281. expect(formData.patient_dob).to.exist;
  282. }
  283. });
  284. });
  285. });
  286. });