utils.ts 12 KB

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