xyh 3 роки тому
батько
коміт
73b124c7e7

+ 121 - 0
cypress/e2e/User.cy.ts

@@ -0,0 +1,121 @@
+import {
+  beforeSetup,
+  exportIntercept,
+  generateNetworkResult,
+  intercept,
+  intoMenu,
+  selectAllFilters,
+  successIntercept,
+  tableBtnClick,
+  validateDelete,
+  validateDialog,
+  validateExport,
+  validateMessageContent,
+  validatePut,
+  validateTableList,
+  validateTableSearch,
+} from './utils';
+
+const basicData = {
+  id: '83',
+  code: 'YH000083',
+  userName: 'admin2',
+  password: 'F6BE46C2F900E518',
+  newPassword: null,
+  realName: '测试2',
+  email: '1211@163.com',
+  landline: null,
+  phone: '1336131680',
+  department: '采购中心(公共) ',
+  role: 'test账户',
+  roleId: '11',
+  departmentId: '00029999',
+  createTime: '2023-04-03 14:01:45',
+  token: null,
+  menu: null,
+  modifyUser: 'admin',
+  modifyTime: '2023-04-03 14:18:21',
+  page: 0,
+  limit: 0,
+};
+
+const TABLE_NAME = 'user_table',
+  MODAL_NAME = 'user_add_modal',
+  LABEL = '用户',
+  TOOL_ID = 'user_filter';
+
+describe('首页', function () {
+  beforeEach(function () {
+    beforeSetup(true);
+    intoMenu('系统设置', '用户管理');
+  });
+
+  beforeEach(function () {
+    intercept('/user/getAllUser', function ({search, reply}) {
+      generateNetworkResult({search, reply, basicData, title: 'code'});
+    });
+
+    exportIntercept('/user/resetPassword');
+    successIntercept([
+      '/user/addUser',
+      '/user/updateUser',
+      '/user/delUser',
+      '/user/resetPassword',
+    ]);
+  });
+
+  it('table', function () {
+    selectAllFilters(TOOL_ID, 8);
+    validateTableList(TABLE_NAME);
+
+    validateTableSearch(
+      TABLE_NAME,
+      [
+        'userName',
+        'realName',
+        'code',
+        {id: 'department', type: 'select', value: '00029999'},
+        'role',
+        'email',
+        'phone',
+        'modifyUser',
+      ],
+      {toolId: TOOL_ID, url: '/user/getAllUser'},
+    );
+  });
+
+  it('operation', function () {
+    validateExport(TABLE_NAME);
+
+    const {validateAdd, validateEdit} = validatePut(MODAL_NAME, TABLE_NAME, {
+      label: LABEL,
+    });
+
+    validateAdd([
+      'userName',
+      'userRealName',
+      'userPassword',
+      {id: 'userDepartment', type: 'select'},
+      {id: 'userRole', type: 'select'},
+      'userEmail',
+      'userPhone',
+    ]);
+
+    validateEdit([
+      {id: 'userName', type: 'field', value: basicData.userName},
+      {id: 'userRealName', type: 'field', value: basicData.realName},
+      {id: 'userDepartment', type: 'select', value: basicData.department},
+      {id: 'userRole', type: 'select', value: basicData.role},
+      {id: 'userEmail', type: 'field', value: basicData.email},
+      {id: 'userPhone', type: 'field', value: basicData.phone},
+    ]);
+
+    // 重置密码
+    const resetBtn = tableBtnClick(TABLE_NAME, 1);
+    validateDialog('重置密码', '你确定要将测试2的密码重置为123456吗?');
+    resetBtn().should('have.class', 'ant-btn-loading');
+    validateMessageContent('重置成功');
+
+    validateDelete(TABLE_NAME, LABEL, {eq: 2, title: 'admin2'});
+  });
+});

+ 18 - 11
cypress/e2e/utils/setup.ts

@@ -14,8 +14,15 @@ export function normalIntercept(
   return cy.intercept(parseUrl(url), {fixture, ...(options ?? {})});
 }
 
-export function successIntercept(url: string) {
-  return normalIntercept(url, 'success', {delay: 100});
+export function successIntercept(urls: string | string[]) {
+  if (Array.isArray(urls)) {
+    urls.forEach(function (url) {
+      normalIntercept(url, 'success', {delay: 100});
+    });
+    return;
+  }
+
+  return normalIntercept(urls, 'success', {delay: 100});
 }
 
 export function intercept(
@@ -34,7 +41,7 @@ export function intercept(
     const search = new URLSearchParams(url.search);
 
     response({url: res.url, reply, search});
-  });
+  }).as(url);
 }
 
 export function dictionaryIntercept() {
@@ -42,12 +49,8 @@ export function dictionaryIntercept() {
     const type = search.get('type');
 
     switch (type) {
-      case '物料字典':
-        return reply({fixture: 'dictonary/goods'});
       case '部门字典':
         return reply({fixture: 'dictonary/department'});
-      case '物料类型':
-        return reply({fixture: 'dictonary/goodsType'});
     }
   });
 }
@@ -70,16 +73,20 @@ export function menuIntercept() {
 }
 
 export function optionsIntercept() {
-  normalIntercept('/role/roleBefore', 'role/options');
-  normalIntercept('/department/getDepartBefor', 'department/options');
-  normalIntercept('/storage/getStorageAll', 'storage/options');
+  normalIntercept('/role/roleBefore', 'options/role');
+  // normalIntercept('/storage/getStorageAll', 'storage/options');
 }
 
 export function exportIntercept(url: string) {
   successIntercept(url).as('export');
 }
 
-export function beforeSetup() {
+export function beforeSetup(autoLogin = false) {
   loginIntercept();
   menuIntercept();
+  dictionaryIntercept();
+  optionsIntercept();
+  if (autoLogin) {
+    loginSetup();
+  }
 }

+ 285 - 65
cypress/e2e/utils/utils.ts

@@ -1,3 +1,6 @@
+import {StaticResponse} from 'cypress/types/net-stubbing';
+
+/** 点击select具体项 */
 export function selectClick(testid: string, eq = 0) {
   cy.getTestId(testid).click();
   cy.getTestId(testid)
@@ -7,6 +10,7 @@ export function selectClick(testid: string, eq = 0) {
     .click();
 }
 
+/** 进入具体菜单 */
 export function intoMenu(parent: string, child: string) {
   cy.getTestId('menu')
     .children()
@@ -20,6 +24,7 @@ export function intoMenu(parent: string, child: string) {
     });
 }
 
+/** 校验select */
 export function validateSelect(testid: string, value: string) {
   cy.getTestId(testid)
     .find('.ant-select-selection-item')
@@ -27,16 +32,16 @@ export function validateSelect(testid: string, value: string) {
     .and('have.text', value);
 }
 
-export function validateTableList(
-  tableName: string,
-  firstPageNumber = 3,
-  secondPageNumber = 2,
-) {
+/** 校验table内容 */
+export function validateTableList(tableName: string) {
   cy.getTestId(tableName)
     .find('table')
     .find('.ant-table-tbody')
     .children('.ant-table-row')
-    .should('have.length', firstPageNumber);
+    .first()
+    .find('td')
+    .eq(1)
+    .should('include.text', 'page-1');
 
   cy.getTestId(tableName)
     .siblings('.ant-pagination')
@@ -47,26 +52,57 @@ export function validateTableList(
     .find('table')
     .find('.ant-table-tbody')
     .children('.ant-table-row')
-    .should('have.length', secondPageNumber);
+    .first()
+    .find('td')
+    .eq(1)
+    .should('include.text', 'page-2');
 }
 
+/** 校验table search */
 export function validateTableSearch(
   tableName: string,
-  value?: string,
-  options?: {btnTestId?: string},
+  keys: ({id: string; type: 'select' | 'date'; value?: string} | string)[],
+  options: {
+    toolId: string;
+    url: string;
+  },
 ) {
+  const {toolId, url} = options;
+
   cy.getTestId(tableName)
     .siblings('.ant-pagination')
     .find('li[title="2"]')
     .click();
-  const {btnTestId} = options ?? {};
 
-  return function (text?: string) {
-    cy.getTestId(btnTestId ?? 'search_btn').click();
-    cy.getTestId(btnTestId ?? 'search_btn').should(
-      'have.class',
-      'ant-btn-loading',
-    );
+  function clear(data?: (typeof keys)[0]) {
+    function clearData(key: (typeof keys)[0]) {
+      if (typeof key === 'string') {
+        cy.getTestId(`filter_${key}`).clear();
+      } else {
+        const {id, type} = key;
+
+        if (type === 'select') {
+          cy.getTestId(`filter_${id}`)
+            .trigger('mouseover')
+            .find('.ant-select-clear')
+            .click();
+        }
+      }
+    }
+
+    if (data) {
+      return clearData(data);
+    }
+
+    keys.forEach(clearData);
+  }
+
+  function validate(text: string, reset?: boolean) {
+    !reset && cy.getTestId(toolId).getTestId('search_btn').click();
+
+    cy.getTestId(toolId)
+      .getTestId('search_btn')
+      .should('have.class', 'ant-btn-loading');
 
     cy.getTestId(tableName)
       .find('table')
@@ -74,33 +110,72 @@ export function validateTableSearch(
       .children('.ant-table-row')
       .first()
       .find('td')
-      .first()
-      .should('include.text', text ?? value);
-    cy.getTestId(btnTestId ?? 'search_btn').should(
-      'not.have.class',
-      'ant-btn-loading',
-    );
+      .eq(1)
+      .should('include.text', text);
 
     cy.getTestId(tableName)
       .siblings('.ant-pagination')
       .find('li[title="1"]')
       .should('have.class', 'ant-pagination-item-active');
-  };
+
+    cy.getTestId(toolId)
+      .getTestId('search_btn')
+      .should('not.have.class', 'ant-btn-loading');
+  }
+
+  keys.forEach(function (key, idx) {
+    if (idx > 0) {
+      clear(keys[idx - 1]);
+    }
+
+    if (typeof key === 'string') {
+      cy.getTestId(`filter_${key}`).type(key);
+      validate(key);
+    } else {
+      const {id, type, value} = key;
+
+      if (type === 'select') {
+        selectClick(`filter_${id}`, 0);
+        validate(value);
+      }
+    }
+  });
+
+  // 校验重置功能
+  cy.getTestId(toolId).getTestId('reset_btn').click();
+  validate('page-1', true);
+
+  // 校验刷新功能
+  const parentCard = cy.getTestId(tableName).closest('.ant-card-body');
+  parentCard.getTestId('refresh_btn').click();
+  parentCard.getTestId('refresh_btn').should('have.class', 'ant-btn-loading');
+  cy.wait(`@${url}`);
+  parentCard
+    .getTestId('refresh_btn')
+    .should('not.have.class', 'ant-btn-loading');
 }
 
+/** 表格内按钮点击 */
 export function tableBtnClick(tableName: string, index: number) {
-  cy.getTestId(tableName)
-    .find('table')
-    .find('.ant-table-tbody')
-    .children('.ant-table-row')
-    .first()
-    .find('td')
-    .last()
-    .children()
-    .eq(index)
-    .click();
+  function getBtn() {
+    return cy
+      .getTestId(tableName)
+      .find('table')
+      .find('.ant-table-tbody')
+      .children('.ant-table-row')
+      .first()
+      .find('td')
+      .last()
+      .children()
+      .eq(index);
+  }
+
+  getBtn().click();
+
+  return getBtn;
 }
 
+/** 弹窗按钮校验 */
 export function validateModalBtnGroup(modalName: string) {
   cy.getTestId(modalName)
     .getTestId('modal_btn_group')
@@ -108,40 +183,73 @@ export function validateModalBtnGroup(modalName: string) {
     .should('have.class', 'ant-btn-loading');
 }
 
+// 校验antd message内容
+export function validateMessageContent(msg: string) {
+  cy.get('.ant-message-notice-content').should('include.text', msg);
+}
+
+// 校验modal的操作结果
 export function validateModalOperation(modalName: string, text: string) {
   cy.getTestId(modalName).find('form').submit();
 
   validateModalBtnGroup(modalName);
-
-  cy.get('.ant-message-notice-content').should('include.text', text);
+  validateMessageContent(text);
   cy.getTestId(modalName).should('not.exist');
 }
 
+/** 校验新增或修改事件 */
 export function validatePut(
   modalName: string,
-  label: string,
-  options?: {addBtnTestId?: string},
+  tableName: string,
+  options: {label: string},
 ) {
-  const {addBtnTestId} = options ?? {};
+  const {label} = options;
 
-  function validateAdd(fn: () => void) {
-    cy.getTestId(addBtnTestId ?? 'add_btn').click();
+  function validateAdd(keys: (string | {id: string; type: 'select'})[]) {
+    cy.getTestId(tableName)
+      .closest('.ant-card-body')
+      .getTestId('add_btn')
+      .click();
 
     cy.getTestId(modalName).should('exist').and('be.visible');
     cy.getTestId(modalName).find('h3').should('include.text', `新增${label}`);
 
-    fn();
+    keys.forEach(function (key) {
+      if (typeof key === 'string') {
+        cy.getTestId(`field_${key}`).type(key);
+      } else {
+        const {type, id} = key;
+
+        switch (type) {
+          case 'select':
+            selectClick(`field_${id}`, 0);
+            break;
+        }
+      }
+    });
 
     validateModalOperation(modalName, '新增成功');
   }
 
-  function validateEdit(tableName: string, validateFn: () => void) {
-    tableBtnClick(tableName, 0);
+  function validateEdit(
+    keys: {id: string; type: 'field' | 'select'; value: string}[],
+    eq = 0,
+  ) {
+    tableBtnClick(tableName, eq);
 
     cy.getTestId(modalName).should('exist').and('be.visible');
     cy.getTestId(modalName).find('h3').should('include.text', `修改${label}`);
 
-    validateFn();
+    keys.forEach(function ({id, type, value}) {
+      switch (type) {
+        case 'field':
+          cy.getTestId(`field_${id}`).should('have.value', value);
+          break;
+        case 'select':
+          validateSelect(`field_${id}`, value);
+          break;
+      }
+    });
 
     validateModalOperation(modalName, '修改成功');
   }
@@ -149,19 +257,36 @@ export function validatePut(
   return {validateAdd, validateEdit};
 }
 
-export function validateDelete(tableName: string, label: string) {
-  tableBtnClick(tableName, 1);
+/** 校验antd dialog信息 */
+export function validateDialog(
+  title: string,
+  content: string,
+  options?: {confirm?: boolean},
+) {
+  const {confirm = true} = options ?? {};
 
-  cy.get('.ant-modal-content').should('be.visible');
+  cy.get('.ant-modal-confirm-title').should('include.text', title);
+  cy.get('.ant-modal-confirm-content').should('include.text', content);
+  cy.get('.ant-modal-confirm-btns')
+    .children()
+    .eq(confirm ? 1 : 0)
+    .click();
+}
 
-  cy.get('.ant-modal-confirm-title').should('include.text', `删除${label}`);
-  cy.get('.ant-modal-confirm-content').should(
-    'include.text',
-    `你确定要删除当前${label}吗?`,
-  );
+/** 校验删除 */
+export function validateDelete(
+  tableName: string,
+  label: string,
+  options: {eq?: number; title?: string},
+) {
+  const {eq = 1, title} = options;
+  tableBtnClick(tableName, eq);
 
-  cy.get('.ant-modal-confirm-btns').children().last().trigger('click');
+  cy.get('.ant-modal-content').should('be.visible');
+
+  validateDialog(title ?? `删除${label}`, `你确定要删除当前${label}吗?`);
 
+  // 删除按钮在加载
   cy.getTestId(tableName)
     .find('table')
     .find('.ant-table-tbody')
@@ -170,9 +295,10 @@ export function validateDelete(tableName: string, label: string) {
     .find('td')
     .last()
     .children()
-    .eq(1)
+    .eq(eq)
     .should('have.class', 'ant-btn-loading');
 
+  // 其他按钮禁用
   cy.getTestId(tableName)
     .find('table')
     .find('.ant-table-tbody')
@@ -181,27 +307,30 @@ export function validateDelete(tableName: string, label: string) {
     .find('td')
     .last()
     .children()
-    .first()
-    .should('have.attr', 'disabled');
+    .each(function (el, idx) {
+      if (idx !== eq) {
+        expect(el).to.have.attr('disabled');
+      }
+    });
 
-  cy.get('.ant-message-notice-content').should('include.text', '删除成功');
+  validateMessageContent('删除成功');
 }
 
-export function validateExport(testid?: string) {
-  cy.getTestId(testid ?? 'export_btn').click();
-
-  cy.getTestId(testid ?? 'export_btn').should('have.class', 'ant-btn-loading');
+/** 校验导出 */
+export function validateExport(tableName: string) {
+  const card = cy.getTestId(tableName).closest('.ant-card-body');
 
-  cy.getTestId(testid ?? 'export_btn').should(
-    'not.have.class',
-    'ant-btn-loading',
-  );
+  card.getTestId('export_btn').click();
+  card.getTestId('export_btn').should('have.class', 'ant-btn-loading');
+  card.getTestId('export_btn').should('not.have.class', 'ant-btn-loading');
 }
 
+/** 关闭modal */
 export function closeModal() {
   cy.get('.ReactModal__Overlay').trigger('click', 'topRight');
 }
 
+/** 选择时间组件 */
 export function clickDatePicker(id: string) {
   cy.getTestId(id).click();
 
@@ -223,3 +352,94 @@ export function clickDatePicker(id: string) {
     .eq(0)
     .click();
 }
+
+/** 选择所有的筛选框 */
+export function selectAllFilters(toolId: string, count: number) {
+  indexedDB.deleteDatabase('filterGroup');
+
+  cy.getTestId(toolId).getTestId('filter_btn').click();
+  cy.get('.ant-transfer')
+    .find('.ant-transfer-list')
+    .first()
+    .find('.ant-transfer-list-header')
+    .find('input[type="checkbox"]')
+    .check();
+  cy.get('.ant-transfer')
+    .find('.ant-transfer-operation')
+    .find('button')
+    .first()
+    .click();
+  cy.getTestId('filter_select_modal').find('form').submit();
+
+  cy.getTestId(toolId)
+    .children('.ant-space')
+    .first()
+    .children()
+    .should('have.length', count + 1);
+}
+
+/** 生成返回内容 */
+export function generateResult(
+  data: Record<string, any>,
+  length: number,
+  options: {
+    limit: string;
+    key?: string;
+    isList?: boolean;
+    title?: string;
+    value?: string;
+  },
+) {
+  const {key = 'id', isList = false, title, value, limit} = options;
+
+  const result = Array.from({length: Number(limit)}, function (_, idx) {
+    const temp = {...data, [key]: idx + 1};
+
+    return title ? {...temp, [title]: value ?? ''} : temp;
+  });
+
+  return {msg: '200', data: isList ? {total: length, list: result} : result};
+}
+
+/** 生成请求结果 */
+export function generateNetworkResult(options: {
+  search: URLSearchParams;
+  basicData: Record<string, unknown>;
+  reply: (params: StaticResponse) => void;
+  title: string;
+}) {
+  const {search, basicData, reply, title} = options;
+
+  const page = search.get('page'),
+    limit = search.get('limit');
+
+  for (const [name, searchValue] of search.entries()) {
+    if (name === 'page' || name === 'limit' || name === 'id') continue;
+
+    if (searchValue) {
+      return reply({
+        body: generateResult(basicData, Number(limit) * 3, {
+          limit,
+          isList: true,
+          title,
+          value: searchValue,
+        }),
+      });
+    }
+  }
+
+  if (search.has('id') && search.get('id').length > 0) {
+    return reply({
+      body: generateResult(basicData, 1, {limit: '1', isList: true}),
+    });
+  }
+
+  reply({
+    body: generateResult(basicData, Number(limit) * 3, {
+      limit,
+      isList: true,
+      title,
+      value: `page-${page}`,
+    }),
+  });
+}

Різницю між файлами не показано, бо вона завелика
+ 2412 - 0
cypress/fixtures/dictonary/department.json


+ 117 - 0
cypress/fixtures/options/role.json

@@ -0,0 +1,117 @@
+{
+  "msg": "200",
+  "data": [
+    {
+      "id": 16,
+      "roleCode": "BH000016",
+      "roleName": "测试权限组",
+      "createTime": "2023-04-03 14:22:51",
+      "remarks": "",
+      "menu": null,
+      "menuBefore": null,
+      "menuPda": null,
+      "modifyUser": "admin",
+      "modifyTime": "2023-04-03 14:22:51",
+      "page": 0,
+      "limit": 0
+    },
+    {
+      "id": 13,
+      "roleCode": "BH000013",
+      "roleName": "LEE",
+      "createTime": "2023-03-30 14:53:26",
+      "remarks": "",
+      "menu": null,
+      "menuBefore": null,
+      "menuPda": null,
+      "modifyUser": "admin",
+      "modifyTime": "2023-03-30 14:53:26",
+      "page": 0,
+      "limit": 0
+    },
+    {
+      "id": 12,
+      "roleCode": "BH000012",
+      "roleName": "牟洪艳",
+      "createTime": "2023-03-30 14:52:08",
+      "remarks": "测试",
+      "menu": null,
+      "menuBefore": null,
+      "menuPda": null,
+      "modifyUser": "admin",
+      "modifyTime": "2023-03-30 14:52:08",
+      "page": 0,
+      "limit": 0
+    },
+    {
+      "id": 11,
+      "roleCode": "BH000011",
+      "roleName": "test账户",
+      "createTime": "2023-03-30 14:50:46",
+      "remarks": "测试用账户",
+      "menu": null,
+      "menuBefore": null,
+      "menuPda": null,
+      "modifyUser": "admin",
+      "modifyTime": "2023-03-30 14:50:46",
+      "page": 0,
+      "limit": 0
+    },
+    {
+      "id": 10,
+      "roleCode": "BH000010",
+      "roleName": "PDA使用者",
+      "createTime": "2023-03-30 09:23:56",
+      "remarks": "PDA测试用",
+      "menu": null,
+      "menuBefore": null,
+      "menuPda": "97,94,90,29,30,31,32,33,34,35,36,38,39,77,87,",
+      "modifyUser": "admin",
+      "modifyTime": "2023-04-11 11:37:57",
+      "page": 0,
+      "limit": 0
+    },
+    {
+      "id": 9,
+      "roleCode": "BH000009",
+      "roleName": "员工",
+      "createTime": "2023-03-30",
+      "remarks": "员工",
+      "menu": null,
+      "menuBefore": null,
+      "menuPda": null,
+      "modifyUser": null,
+      "modifyTime": null,
+      "page": 0,
+      "limit": 0
+    },
+    {
+      "id": 8,
+      "roleCode": "BH000008",
+      "roleName": "系统超级管理员",
+      "createTime": "2023-03-30",
+      "remarks": "系统超管",
+      "menu": null,
+      "menuBefore": null,
+      "menuPda": null,
+      "modifyUser": null,
+      "modifyTime": null,
+      "page": 0,
+      "limit": 0
+    },
+    {
+      "id": 1,
+      "roleCode": "BH000001",
+      "roleName": "超级管理员",
+      "createTime": "2023-03-20",
+      "remarks": "超管",
+      "menu": "28,7,27,65,45,64,63,44,62,61,59,58,43,57,56,55,54,52,50,46,51,49,48,47,42,41,66,69,76,75,74,73,72,71,70,79,78,80,81,83,85,88,89,93,95,96,",
+      "menuBefore": "28,27,65,64,63,62,61,59,58,57,56,55,54,52,50,51,49,48,47,42,41,66,69,76,75,74,73,72,71,70,79,80,81,83,85,88,89,93,95,96",
+      "menuPda": "87,29,30,31,32,33,34,35,36,38,39,77,",
+      "modifyUser": "admin",
+      "modifyTime": "2023-04-04 13:28:02",
+      "page": 0,
+      "limit": 0
+    }
+  ]
+}

+ 15 - 4
cypress/tsconfig.json

@@ -2,8 +2,19 @@
   "compilerOptions": {
     "baseUrl": ".",
     "target": "ES5",
-    "lib": ["ES5", "DOM"],
-    "types": ["cypress", "./support"]
+    "downlevelIteration": true,
+    "lib": [
+      "ES5",
+      "DOM"
+    ],
+    "types": [
+      "cypress",
+      "./support"
+    ]
   },
-  "include": ["../node_modules/cypress", "./**/*.ts", "../cypress.config.ts"]
-}
+  "include": [
+    "../node_modules/cypress",
+    "./**/*.ts",
+    "../cypress.config.ts"
+  ]
+}