utils.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. import {StaticResponse} from 'cypress/types/net-stubbing';
  2. import menuJson from '../../fixtures/menu/basic.json';
  3. /** 点击select具体项 */
  4. export function selectClick(testid: string, eq = 0) {
  5. cy.getTestId(testid).click();
  6. cy.getTestId(testid)
  7. .find('.rc-virtual-list-holder-inner')
  8. .children('.ant-select-item')
  9. .eq(eq)
  10. .click();
  11. }
  12. /** 进入具体菜单 */
  13. export function intoMenu(parent: string, child: string) {
  14. cy.wait('@loginIntercept');
  15. const list = menuJson.data;
  16. const menu = list.find(val => val.name === child);
  17. menu && cy.visit(menu);
  18. }
  19. export function clickMenu(parent: string, child: string) {
  20. cy.getTestId('menu')
  21. .children()
  22. .each(function(el) {
  23. const titleElement = el.find('.ant-menu-submenu-title');
  24. if (titleElement.text() === parent) {
  25. titleElement.trigger('click');
  26. el.find(`ul>li[title="${child}"]`).trigger('click');
  27. }
  28. });
  29. }
  30. /** 校验select */
  31. export function validateSelect(testid: string, value: string) {
  32. cy.getTestId(testid)
  33. .find('.ant-select-selection-item')
  34. .should('have.attr', 'title', value)
  35. .and('have.text', value);
  36. }
  37. /** 校验table内容 */
  38. export function validateTableList(tableName: string) {
  39. cy.getTestId(tableName)
  40. .find('table')
  41. .find('tbody')
  42. .children('tr')
  43. .first()
  44. .find('td')
  45. .eq(1)
  46. .should('have.text', 'page-1');
  47. cy.getTestId(tableName)
  48. .siblings('.ant-pagination')
  49. .find('li[title="2"]')
  50. .click();
  51. cy.getTestId(tableName)
  52. .find('table')
  53. .find('tbody')
  54. .children('tr')
  55. .first()
  56. .find('td')
  57. .eq(1)
  58. .should('have.text', 'page-2');
  59. }
  60. /** 选择时间组件 */
  61. export function clickDatePicker(id: string, enableTime = false) {
  62. cy.getTestId(id).click();
  63. if (enableTime) {
  64. cy.get('.ant-picker-datetime-panel')
  65. .children()
  66. .eq(0)
  67. .find('.ant-picker-content')
  68. .find('tbody')
  69. .find('td')
  70. .eq(0)
  71. .click();
  72. cy.get('.ant-picker-footer').find('.ant-picker-ok').find('button').click();
  73. cy.get('.ant-picker-datetime-panel')
  74. .children()
  75. .eq(0)
  76. .find('.ant-picker-content')
  77. .find('tbody')
  78. .find('td')
  79. .eq(1)
  80. .click();
  81. cy.get('.ant-picker-footer').find('.ant-picker-ok').find('button').click();
  82. return;
  83. }
  84. cy.get('.ant-picker-panels')
  85. .children()
  86. .eq(0)
  87. .find('.ant-picker-content')
  88. .find('tbody')
  89. .find('td')
  90. .eq(0)
  91. .click();
  92. cy.get('.ant-picker-panels')
  93. .children()
  94. .eq(1)
  95. .find('.ant-picker-content')
  96. .find('tbody')
  97. .find('td')
  98. .eq(0)
  99. .click();
  100. }
  101. /** 校验table search */
  102. export function validateTableSearch(
  103. tableName: string,
  104. keys: (
  105. | {
  106. id: string;
  107. type: 'select';
  108. value: string;
  109. eq?: number;
  110. defaultValue?: string;
  111. defaultEq?: number;
  112. }
  113. | {id: string; type: 'date'; enableTime?: boolean}
  114. | string
  115. )[],
  116. options: {
  117. toolId: string;
  118. url: string;
  119. },
  120. ) {
  121. const {toolId, url} = options;
  122. cy.getTestId(tableName)
  123. .siblings('.ant-pagination')
  124. .find('li[title="2"]')
  125. .click();
  126. function clear(data?: (typeof keys)[0]) {
  127. function clearData(key: (typeof keys)[0]) {
  128. if (typeof key === 'string') {
  129. cy.getTestId(toolId).find(`[data-testid="filter_${key}"]`).clear();
  130. } else {
  131. if (key.type === 'select' && key.defaultEq !== void 0) {
  132. selectClick(`filter_${key.id}`, key.defaultEq);
  133. return;
  134. }
  135. const {id, type} = key;
  136. const clearId
  137. = type === 'select' ? '.ant-select-clear' : '.ant-picker-clear';
  138. cy.getTestId(toolId)
  139. .find(`[data-testid="filter_${id}"]`)
  140. .trigger('mouseover')
  141. .find(clearId)
  142. .click();
  143. }
  144. }
  145. if (data) {
  146. return clearData(data);
  147. }
  148. keys.forEach(clearData);
  149. }
  150. function validate(text: string, reset?: boolean) {
  151. !reset && cy.getTestId(toolId).find('[data-testid="search_btn"]').click();
  152. cy.getTestId(toolId)
  153. .find('[data-testid="search_btn"]')
  154. .should('have.class', 'ant-btn-loading');
  155. cy.getTestId(tableName)
  156. .find('table')
  157. .find('tbody')
  158. .children('tr')
  159. .first()
  160. .find('td')
  161. .eq(1)
  162. .should('have.text', text);
  163. cy.getTestId(tableName)
  164. .siblings('.ant-pagination')
  165. .find('li[title="1"]')
  166. .should('have.class', 'ant-pagination-item-active');
  167. cy.getTestId(toolId)
  168. .getTestId('search_btn')
  169. .should('not.have.class', 'ant-btn-loading');
  170. }
  171. function eachAllField(skipValidate = false) {
  172. keys.forEach(function(key, idx) {
  173. let validateText: string;
  174. if (typeof key === 'string') {
  175. cy.getTestId(toolId).find(`[data-testid="filter_${key}"]`).type(key);
  176. validateText = key;
  177. } else {
  178. const {id, type} = key;
  179. switch (type) {
  180. case 'select':
  181. selectClick(`filter_${id}`, key?.eq ?? 0);
  182. validateText = key.value;
  183. break;
  184. case 'date':
  185. clickDatePicker(`filter_${id}`, key.enableTime);
  186. validateText = 'searchTime';
  187. break;
  188. }
  189. }
  190. if (!skipValidate) {
  191. validate(validateText);
  192. clear(keys[idx]);
  193. }
  194. });
  195. }
  196. eachAllField();
  197. // 校验重置功能
  198. eachAllField(true);
  199. cy.getTestId(toolId).find('[data-testid="reset_btn"]').click();
  200. keys.forEach(function(key) {
  201. if (typeof key === 'string') {
  202. cy.getTestId(`filter_${key}`).invoke('val').should('be.empty');
  203. } else {
  204. switch (key.type) {
  205. case 'select':
  206. if (key.defaultValue) {
  207. validateSelect(`filter_${key.id}`, key.defaultValue);
  208. break;
  209. }
  210. cy.getTestId(`filter_${key.id}`)
  211. .find('.ant-select-selection-placeholder')
  212. .should('exist');
  213. break;
  214. case 'date':
  215. cy.getTestId(`filter_${key.id}`)
  216. .children('.ant-picker-input')
  217. .first()
  218. .find('input')
  219. .invoke('val')
  220. .should('be.empty');
  221. cy.getTestId(`filter_${key.id}`)
  222. .children('.ant-picker-input')
  223. .last()
  224. .find('input')
  225. .invoke('val')
  226. .should('be.empty');
  227. break;
  228. }
  229. }
  230. });
  231. validate('page-1', true);
  232. // 校验刷新功能
  233. cy.getTestId(tableName)
  234. .closest('.ant-card-body')
  235. .find('[data-testid="refresh_btn"]')
  236. .click();
  237. cy.getTestId(tableName)
  238. .closest('.ant-card-body')
  239. .find('[data-testid="refresh_btn"]')
  240. .should('have.class', 'ant-btn-loading');
  241. cy.wait(`@${url}`);
  242. cy.getTestId(tableName)
  243. .closest('.ant-card-body')
  244. .find('[data-testid="refresh_btn"]')
  245. .should('not.have.class', 'ant-btn-loading');
  246. // 校验保存配置
  247. cy.getTestId(tableName)
  248. .closest('.ant-card-body')
  249. .find('[data-testid="save_setting_btn"]')
  250. .click();
  251. cy.getTestId(tableName)
  252. .closest('.ant-card-body')
  253. .find('[data-testid="save_setting_btn"]')
  254. .should('have.class', 'ant-btn-loading');
  255. cy.getTestId(tableName)
  256. .closest('.ant-card-body')
  257. .find('[data-testid="save_setting_btn"]')
  258. .should('not.have.class', 'ant-btn-loading');
  259. }
  260. /** 表格内按钮点击 */
  261. export function tableBtnClick(tableName: string, index: number) {
  262. function getBtn() {
  263. return cy
  264. .getTestId(tableName)
  265. .find('table')
  266. .find('tbody')
  267. .children('tr')
  268. .first()
  269. .find('td')
  270. .last()
  271. .children()
  272. .eq(index);
  273. }
  274. getBtn().click();
  275. return getBtn;
  276. }
  277. /** 弹窗按钮校验 */
  278. export function validateModalBtnGroup(modalName: string) {
  279. cy.getTestId(modalName)
  280. .getTestId('modal_btn_group')
  281. .find('.ant-btn')
  282. .should('have.class', 'ant-btn-loading');
  283. }
  284. // 校验antd message内容
  285. export function validateMessageContent(msg: string) {
  286. cy.get('.ant-message-notice-content').should('include.text', msg);
  287. }
  288. // 校验modal的操作结果
  289. export function validateModalOperation(modalName: string, text: string) {
  290. cy.getTestId(modalName).find('form').submit();
  291. validateModalBtnGroup(modalName);
  292. validateMessageContent(text);
  293. cy.getTestId(modalName).should('not.exist');
  294. }
  295. /** 校验新增或修改事件 */
  296. export function validatePut(
  297. modalName: string,
  298. tableName: string,
  299. options: {label: string},
  300. ) {
  301. const {label} = options;
  302. function validateAdd(
  303. keys: (
  304. | string
  305. | {id: string; type: 'select'}
  306. | {id: string; type: 'keySelect'}
  307. | {id: string; type: 'field'; value: string}
  308. )[],
  309. ) {
  310. cy.getTestId(tableName)
  311. .closest('.ant-card-body')
  312. .find('[data-testid="add_btn"]')
  313. .click();
  314. cy.getTestId(modalName).should('exist').and('be.visible');
  315. cy.getTestId(modalName).find('h3').should('have.text', `新增${label}`);
  316. keys.forEach(function(key) {
  317. if (typeof key === 'string') {
  318. cy.getTestId(`field_${key}`).type(key);
  319. } else {
  320. const {type, id} = key;
  321. switch (type) {
  322. case 'select':
  323. selectClick(`field_${id}`, 0);
  324. break;
  325. case 'field':
  326. cy.getTestId(`field_${id}`).clear().type(key.value);
  327. break;
  328. case 'keySelect':
  329. cy.get(`#field_${id}`).clear().type(id);
  330. selectClick(`field_${id}`, 0);
  331. break;
  332. }
  333. }
  334. });
  335. validateModalOperation(modalName, '新增成功');
  336. }
  337. function validateEdit(
  338. keys: {id: string; type: 'field' | 'select'; value: string}[],
  339. eq = 0,
  340. ) {
  341. tableBtnClick(tableName, eq);
  342. cy.getTestId(modalName).should('exist').and('be.visible');
  343. cy.getTestId(modalName).find('h3').should('include.text', `修改${label}`);
  344. keys.forEach(function({id, type, value}) {
  345. switch (type) {
  346. case 'field':
  347. cy.getTestId(`field_${id}`).should('have.value', value);
  348. break;
  349. case 'select':
  350. validateSelect(`field_${id}`, value);
  351. break;
  352. }
  353. });
  354. validateModalOperation(modalName, '修改成功');
  355. }
  356. return {validateAdd, validateEdit};
  357. }
  358. /** 校验antd dialog信息 */
  359. export function validateDialog(
  360. title: string,
  361. content: string,
  362. options?: {confirm?: boolean},
  363. ) {
  364. const {confirm = true} = options ?? {};
  365. cy.get('.ant-modal-confirm-title').should('include.text', title);
  366. cy.get('.ant-modal-confirm-content').should('include.text', content);
  367. cy.get('.ant-modal-confirm-btns')
  368. .children()
  369. .eq(confirm ? 1 : 0)
  370. .click();
  371. }
  372. /** 校验删除 */
  373. export function validateDelete(
  374. tableName: string,
  375. label: string,
  376. options: {eq?: number; title: string},
  377. ) {
  378. const {eq = 1, title} = options;
  379. tableBtnClick(tableName, eq);
  380. cy.get('.ant-modal-content').should('be.visible');
  381. validateDialog(title, `你确定要删除当前${label}吗?`);
  382. // 删除按钮在加载
  383. cy.getTestId(tableName)
  384. .find('table')
  385. .find('tbody')
  386. .children('tr')
  387. .first()
  388. .find('td')
  389. .last()
  390. .children()
  391. .eq(eq)
  392. .should('have.class', 'ant-btn-loading');
  393. // 其他按钮禁用
  394. cy.getTestId(tableName)
  395. .find('table')
  396. .find('tbody')
  397. .children('tr')
  398. .first()
  399. .find('td')
  400. .last()
  401. .children()
  402. .each(function(el, idx) {
  403. if (idx !== eq) {
  404. expect(el).to.have.attr('disabled');
  405. }
  406. });
  407. validateMessageContent('删除成功');
  408. }
  409. /** 校验导出 */
  410. export function validateExport(tableName: string) {
  411. cy.getTestId(tableName)
  412. .closest('.ant-card-body')
  413. .find('[data-testid="export_btn"]')
  414. .click();
  415. cy.getTestId(tableName)
  416. .closest('.ant-card-body')
  417. .find('[data-testid="export_btn"]')
  418. .should('have.class', 'ant-btn-loading');
  419. cy.getTestId(tableName)
  420. .closest('.ant-card-body')
  421. .find('[data-testid="export_btn"]')
  422. .should('not.have.class', 'ant-btn-loading');
  423. }
  424. /** 关闭modal */
  425. export function closeModal() {
  426. cy.get('.ReactModal__Overlay').trigger('click', 'topRight');
  427. }
  428. /** 选择所有的筛选框 */
  429. export function selectAllFilters(toolId: string, count: number) {
  430. cy.getTestId(toolId).getTestId('filter_btn').click();
  431. cy.get('.ant-transfer')
  432. .find('.ant-transfer-list')
  433. .first()
  434. .find('.ant-transfer-list-header')
  435. .find('input[type="checkbox"]')
  436. .check();
  437. cy.get('.ant-transfer')
  438. .find('.ant-transfer-operation')
  439. .find('button')
  440. .first()
  441. .click();
  442. cy.getTestId('filter_select_modal').find('form').submit();
  443. cy.getTestId(toolId)
  444. .children('.ant-space')
  445. .first()
  446. .children()
  447. .should('have.length', count + 1);
  448. }
  449. /** 生成返回内容 */
  450. export function generateResult<T extends Record<string, any>>(
  451. data: T,
  452. length: number,
  453. options: {
  454. limit: string;
  455. key?: string;
  456. isList?: boolean;
  457. title?: keyof T;
  458. value?: string;
  459. },
  460. ) {
  461. const {key = 'id', isList = false, title, value, limit} = options;
  462. const result = Array.from({length: Number(limit)}, function(_, idx) {
  463. const temp = {...data, [key]: idx + 1};
  464. return title ? {...temp, [title]: value ?? ''} : temp;
  465. });
  466. return {msg: '200', data: isList ? {total: length, list: result} : result};
  467. }
  468. /** 生成请求结果 */
  469. export function generateNetworkResult<
  470. T extends Record<string, unknown>,
  471. >(options: {
  472. search: URLSearchParams;
  473. basicData: T;
  474. reply: (params: StaticResponse) => void;
  475. title: keyof T;
  476. skipCondition?: (name: string) => boolean;
  477. replaceValue?: string;
  478. }) {
  479. const {
  480. search,
  481. basicData,
  482. reply,
  483. title,
  484. skipCondition = () => false,
  485. replaceValue,
  486. } = options;
  487. const page = search.get('page'),
  488. limit = search.get('limit');
  489. for (const [name, searchValue] of search.entries()) {
  490. if (
  491. name === 'page'
  492. || name === 'limit'
  493. || name === 'id'
  494. || skipCondition(name)
  495. ) {
  496. continue;
  497. }
  498. if (searchValue) {
  499. return reply({
  500. body: generateResult(basicData, Number(limit) * 3, {
  501. limit,
  502. isList: true,
  503. title,
  504. value:
  505. name === 'startTime' || name === 'endTime'
  506. ? 'searchTime'
  507. : replaceValue ?? searchValue,
  508. }),
  509. });
  510. }
  511. }
  512. if (search.has('id') && search.get('id').length > 0) {
  513. return reply({
  514. body: generateResult(basicData, 1, {limit: '1', isList: true}),
  515. });
  516. }
  517. reply({
  518. body: generateResult(basicData, Number(limit) * 3, {
  519. limit,
  520. isList: true,
  521. title,
  522. value: replaceValue ?? `page-${page}`,
  523. }),
  524. });
  525. }