Merge "docs: Add en test docs"

This commit is contained in:
Zuul 2021-07-07 08:09:05 +00:00 committed by Gerrit Code Review
commit 04e2a0004a
82 changed files with 1923 additions and 77 deletions

View File

@ -0,0 +1,142 @@
English | [简体中文](/docs/zh/test/1-ready-to-work.md)
# Two kinds of tests
We provide two test methods
- E2E test
- Focus on function point testing
- Can provide code coverage data
- User `Cypress` frame
- Test results are saved in a static page for easy preview
- Unit test
- Focus on basic function testing
- User `Jest` frame
# E2E test
## Set up E2E test environment
E2E test environment has been successfully built in Centos and wsl2 of Windows
- node environment
- requirement in package.json: `"node": ">=10.22.0"`
- verify nodejs version
```shell
node -v
```
- yarn
- install yarn
```shell
npm install -g yarn
```
- Install dependencies
- Execute in the project root directory, which is the same level as `package.json`, and wait patiently for the installation to complete
```shell
yarn install
```
- Install system dependencies
- `Ubuntu/Debian`
```shell
sudo apt-get install libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb
```
- `CentOS`
```shell
yum install -y xorg-x11-server-Xvfb gtk2-devel gtk3-devel libnotify-devel GConf2 nss libXScrnSaver alsa-lib
```
- Adjust the access path, account and other information
- E2E configuration files are stored in `test/e2e/config/config.yaml`, Configured in it:
- `baseUrl`, test access path
- `env`, environment variable
- `switchToAdminProject`, Do you need to switch to the `admin` project after logging in
- `username`, User name to access the console, a user with console operation permissions is required
- `password`, Password to access the console
- `usernameAdmin`, The user name to access the management platform, a user with the operation authority of the management platform is required
- `passwordAdmin`, Password to access the management platform
- `testFiles`, Test files list
- The configuration change can be completed by directly modifying the corresponding value in `config.yaml`
- You can also complete configuration changes through `local_config.yaml`
- Copy `test/e2e/config/config.yaml` to `test/e2e/config/local_config.yaml`
- Modify the corresponding variables in `local_config.yaml`
- For the value of the variable, the priority is: `local_config.yaml`> `config.yaml`
## Command line run E2E
```shell
yarn run test:e2e
```
![console](images/e2e/console.png)
## GUI running E2E
```shell
yarn run test:e2e:open
```
Cypress provide GUI
![gui](images/e2e/gui-list.png)
![work](images/e2e/gui-work.png)
## E2E test results
After the test run is over, visit `test/e2e/report/merge-report.html` to view
![result](images/e2e/result.png)
## E2E Code coverage test results
After the test run is over, visit `coverage/lcov-report/index.html` to view
> Note: Code coverage, the front-end package corresponding to `baseUrl` that needs E2E access, is `dist` package with a detectable code coverage version
```shell
yarn run build:test
```
The file packaged in the above way is a front-end package with testable code coverage
Below, the nginx configuration for front-end access to the front-end package with code coverage function is given
```nginx
server {
listen 0.0.0.0:8088 default_server;
root /path/to/skyline-console/dist;
index index.html;
server_name _;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://<backend_address>;
}
}
```
# Unit test
## Command line run unit tests
```shell
yarn run test:unit
```
## Unit test results
You can view the running results directly in the command line console
![Unit test results](images/unit/result.png)

View File

@ -0,0 +1,91 @@
English | [简体中文](/docs/zh/test/2-catalog-introduction.md)
```
test
├── e2e E2E code storage location
│ ├── config
│ │ ├── config.yaml (Part of the configuration when E2E running, mainly configures the test case file list, login account and other information)
│ │ └── local_config.yaml (Part of the configuration when E2E running, mainly configures the test case file list, login account and other information, which is gitignore and has a higher priority than config.yaml)
│ ├── fixtures (Store upload files, read files, etc. required during operation)
│ │ ├── keypair (Test file read by key)
│ │ ├── metadata.json (Test metadata read file)
│ │ ├── stack-content.yaml (Files read by the test stack)
│ │ └── stack-params.yaml (Files read by the test stack)
│ ├── integration (Storage unit test)
│ │ └── pages (Adjust the directory according to the webpage menu structure)
│ │ ├── compute (compute)
│ │ │ ├── aggregate.spec.js (aggregate)
│ │ │ ├── baremetal.spec.js (baremetal)
│ │ │ ├── flavor.spec.js (instance flavor)
│ │ │ ├── hypervisor.spec.js (hypervisor)
│ │ │ ├── image.spec.js (image)
│ │ │ ├── instance.spec.js (instance)
│ │ │ ├── ironic.spec.js (ironic)
│ │ │ ├── keypair.spec.js (keypair)
│ │ │ └── server-group.spec.js (server group)
│ │ ├── configuration (Platform configuration)
│ │ │ ├── metadata.spec.js (metedata)
│ │ │ └── system.spec.js (system info)
│ │ ├── error.spec.js (error page)
│ │ ├── heat (heat)
│ │ │ └── stack.spec.js (stack)
│ │ ├── identity (identity)
│ │ │ ├── domain.spec.js (Domain)
│ │ │ ├── project.spec.js (Project)
│ │ │ ├── role.spec.js (Role)
│ │ │ ├── user-group.spec.js (User group)
│ │ │ └── user.spec.js (User)
│ │ ├── login.spec.js (Login)
│ │ ├── management (Operation management)
│ │ │ └── recycle-bin.spec.js (Recycle)
│ │ ├── network (Network)
│ │ │ ├── floatingip.spec.js (Floating ip)
│ │ │ ├── lb.spec.js (Loadbalance)
│ │ │ ├── network.spec.js (Network)
│ │ │ ├── qos-policy.spec.js (Qos policy)
│ │ │ ├── router.spec.js (Router)
│ │ │ ├── security-group.spec.js (Security group)
│ │ │ ├── topology.spec.js (Network topology)
│ │ │ ├── virtual-adapter.spec.js (Virtual Adapter)
│ │ │ └── vpn.spec.js (VPN)
│ │ └── storage (Storage)
│ │ ├── backup.spec.js (Backup)
│ │ ├── qos.spec.js (QoS)
│ │ ├── snapshot.spec.js (Volume snapshot)
│ │ ├── storage.spec.js (Storage)
│ │ ├── volume-type.spec.js (Volume tyoe)
│ │ └── volume.spec.js (Volume)
│ ├── plugins (Cypress plugins)
│ │ └── index.js (Configured to read the configuration file, configured to use the code coverage function)
│ ├── report (Store E2E test report)
│ │ ├── merge-report.html (The final test report that records the execution of each use case)
│ │ └── merge-report.json (Summary of test results in the results directory)
│ ├── results (Store test result files)
│ ├── screenshots (Store a snapshot of the test error)
│ ├── support (When writing a test case, double-wrapped function)
│ │ ├── commands.js (Storage login, logout and other operation functions)
│ │ ├── common.js (Storage base functions)
│ │ ├── constants.js (Storage the route of each resource)
│ │ ├── detail-commands.js (Storage the functions related to the resource detail page, based on the framework, the operation of the detail page is consistent)
│ │ ├── form-commands.js (Stores form-related functions, based on the framework, consistent with the operation of form items)
│ │ ├── index.js
│ │ ├── resource-commands.js (Storage functions related to resource operations, such as creating cloud hosts, creating routes, deleting resources, etc.)
│ │ └── table-commands.js (Storage the functions related to the resource list, based on the framework, have consistency in the operation of the list)
│ └── utils (Store the read function for the configuration file)
│ └── index.js
└── unit (Unit test)
├── local-storage-mock.js ( Storeage mock function in local)
├── locales (Translation files used when testing internationalization)
│ ├── en-US.js
│ └── zh-CN.js
├── setup-tests.js (setup uni test)
└── svg-mock.js (Mock of image loading)
```
- E2E test code, storaged in the `test/e2e` directory
- Other global configurations of E2E storaged in `cypress.json`
- The basic code of the unit test storaged in the `test/unit` directory
- Other global configuration of unit test, storaged in `jest.config.js`
- The test code of the unit test is usually placed in the same directory as the file to be tested, and has a suffix of `test.js` or `spec.js`
- case`src/utils/index.js`与`src/utils/index.test.js`
- case`src/utils/local-storage.js`与`src/utils/local-storage.spec.js`

View File

@ -0,0 +1,104 @@
English | [简体中文](/docs/zh/test/3-0-how-to-edit-e2e-case.md)
For specific introduction and usage of Cypress, please refer to[Official document](https://docs.cypress.io/guides/overview/why-cypress)
Here we mainly give the E2E use cases corresponding to the resources in the front-end page of Skyline-console, and use function defined in `test/e2e/support`
The following is an introduction, taking the cloud host use case `test/e2e/integration/pages/compute/instance.spec.js` as an example
Generally, when testing the corresponding functions of a resource, follow the following order
1. Prepare relevant variables in text
- Required parameters when creating a resource, such as: name, password
- Required parameters when editing resources, such as: new name
- When creating an associated resource, the name of the associated resource, such as: network name, router name, cloud disk name
```javascript
const uuid = Cypress._.random(0, 1e6);
const name = `e2e-instance-${uuid}`;
const newname = `${name}-1`;
const password = 'passw0rd_1';
const volumeName = `e2e-instance-attach-volume-${uuid}`;
const networkName = `e2e-network-for-instance-${uuid}`;
const routerName = `e2e-router-for-instance-${uuid}`;
```
2. Login before operation
- If is operate console resource, use`cy.login`
- If is operate administrator resource, use`cy.loginAdmin`
- Generally, the variable `listUrl` is used in the `login` and `loginAdmin` functions, that is, directly access the page where the resource is located after logging in
```javascript
beforeEach(() => {
cy.login(listUrl);
});
```
3. Create associated resources, use the resource creation function provided in `resource-commands.js`, take the test instance as an example
- Create a network for testing to create a instance, attach interface
```javascript
cy.createNetwork({ name: networkName });
```
- Create router`cy.createRouter`Used to ensure that the floating IP is reachable when testing the associated floating IP
- The router created in the following way will open the external network gateway and bind the subnet of the `networkName` network
```javascript
cy.createRouter({ name: routerName, network: networkName });
```
- Create floating ip`cy.createFip`Used to test associat floating ip
```javascript
cy.createFip();
```
- Create volumr `cy.createVolume`(Used to test attach volume)
```javascript
cy.createVolume(volumeName);
```
4. Write cases for creating resources
5. Write use cases for accessing resource details
6. Write use cases corresponding to all operations of resources separately
- Generally, the use case of the `edit` operation is written at the back, and then the use case of the `delete` operation is written, so that you can test whether the editing is effective
7. To delete associated resources, use the resource-deleting function provided in `resource-commands.js`, this is to make the resources in the test account as clean as possible after the test case is executed
- Delete Floating IP
```javascript
cy.deleteAll('fip');
```
- Delete Router`routerName`
```javascript
cy.deleteRouter(routerName, networkName);
```
- Delete Network`networkName`
```javascript
cy.deleteAll('network', networkName);
```
- Delete Volume`volumeName`
```javascript
cy.deleteAll('volume', volumeName);
```
- Delete all available volume
```javascript
cy.deleteAllAvailableVolume();
```
The `4`, `5`, and `6` in the above steps are mainly used
- The function operation form in `test/e2e/support/form-commands.js`, please refer to the detailed introduction[3-1-E2E-表单操作](3-1-E2E-表单操作.md)
- The functions in `test/e2e/support/table-commands.js`, click on the buttons in the operation table, search, and enter for details. please refer to the detailed introduction[3-2-E2E-表格操作](3-2-E2E-表格操作.md)
- The functions in `test/e2e/support/detail-commands.js`, the operation returns the list page, the detection details, and the switching details Tab. please refer to the detailed introduction[3-3-E2E-详情操作](3-3-E2E-详情操作.md)
Create and delete associated resources mainly use the functions in `test/e2e/support/resource-commands.js`,. please refer to the detailed introduction[3-4-E2E-资源操作](3-4-E2E-资源操作.md)

View File

@ -0,0 +1,591 @@
English | [简体中文](/docs/zh/test/3-1-E2E-form-operation.md)
Because of the consistency of the front-end framework, when we write related use cases for form operations, select elements and operate, we often find that there is a strong regularity, so we have written corresponding Cypress functions for most of the form operations. It greatly reduces the difficulty of writing test cases. The following will give a detailed description of the main form operation functions.
> Note: The functions written are based on the principle that the operation of a form item can be completed completely
## Click the button operation
- `closeNotice`
- Close the prompt message of successful operation in the upper right corner
![notice](images/e2e/form/notice.png)
- `waitFormLoading`
- Wait for the form request to complete
- After the form is filled in and verified, click the confirm button to initiate a corresponding request to the server. At this time, the confirm button of the form item will be in the state of `Loading`
- Using this function, instead of `cy.wait(seconds)`, can more effectively ensure that the synchronization request has been processed completely, thereby ensuring the prerequisites for subsequent use cases
![wait-form-loading](images/e2e/form/wait-form-loading.png)
- `clickFormActionSubmitButton`
- Click the confirm button of the confirm form and wait for the request to complete
![click-form-submit](images/e2e/form/click-form-submit.png)
- `clickModalActionSubmitButton`
- Click the confirma button in the pop-up form and wait for the request to complete
![click-modal-submit](images/e2e/form/click-modal-submit.png)
- `clickModalActionCancelButton`
- Click the cancel button of the pop-up form
- `clickConfirmActionSubmitButton`
- Click the confirmation button of the confirmation form, wait for the request to complete, and close the prompt message that the request is successful
- Parameter `waitTime`, the waiting time after closing the prompt message
![click-confirm-submit](images/e2e/form/click-confirm-submit.png)
- `checkDisableAction`
- When some data does not meet the requirements, use the batch operation, an error will pop up. This function verifies that the data does not meet the operation requirements, and closes the error prompt
- Take the locked instance `test/e2e/integration/pages/compute/instance.spec.js` as an example
- After locking, it no longer supports startup, shutdown, and restart operations
```javascript
it('successfully lock', () => {
cy.tableSearchText(name)
.clickConfirmActionInMoreSub('Lock', 'Instance Status')
.wait(10000);
cy.tableSearchText(name)
.selectFirst()
.clickHeaderButtonByTitle('Start')
.checkDisableAction(2000)
.clickHeaderButtonByTitle('Stop')
.checkDisableAction(2000)
.clickHeaderButtonByTitle('Reboot')
.checkDisableAction(2000);
});
```
![disable-action](images/e2e/form/disable-action.png)
- `clickStepActionNextButton`
- Click the Next/Confirm button of the step-by-step form
- Take the create instance use case `test/e2e/integration/pages/compute/instance.spec.js` as an example
- A total of 3 clicks on the next step and 1 confirmation button
```javascript
it('successfully create', () => {
cy.clickHeaderButton(1)
.url()
.should('include', `${listUrl}/create`)
.wait(5000)
.formTableSelect('flavor')
.formTableSelect('image')
.formSelect('systemDisk')
.formAddSelectAdd('dataDisk')
.formSelect('dataDisk')
.wait(2000)
.clickStepActionNextButton()
.wait(5000)
.formTableSelectBySearch('networkSelect', networkName, 5000)
.formTableSelectBySearch('securityGroup', 'default', 5000)
.wait(2000)
.clickStepActionNextButton()
.formInput('name', name)
.formRadioChoose('loginType', 1)
.formInput('password', password)
.formInput('confirmPassword', password)
.wait(2000)
.clickStepActionNextButton()
.wait(2000)
.clickStepActionNextButton()
.waitFormLoading()
.url()
.should('include', listUrl)
.closeNotice()
.waitStatusActiveByRefresh();
});
```
![click-step-next](images/e2e/form/click-step-next.png)
- `clickStepActionCancelButton`
- Click the cancel button of the step-by-step form
- Take image create instance `test/e2e/integration/pages/compute/image.spec.js`as example
- Only verify that you can successfully enter the create instancepage, and then click the cancel button to complete the use case
```javascript
it('successfully create instance with cancel', () => {
cy.tableSearchText(name)
.clickActionInMore('Create Instance')
.wait(2000)
.clickStepActionCancelButton();
});
```
## Operations on form
Looking at the structure and style of the elements through the page, I found that all form items have an id, And corresponding to the `name` property of the form configuration `formItem` written during development, the `name` can also be obtained directly by viewing the `id` of the element in the page, as shown in the following figure, after the `form-item-col-` The content is `name`
![form-name](images/e2e/form/form-name.png)
- `formInput`
- Input content of form items with `input` input box
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `value`enter value
- Take instance use case`test/e2e/integration/pages/compute/instance.spec.js` as an Example
```javascript
it('successfully edit', () => {
cy.tableSearchText(name)
.clickActionInMore('Edit')
.formInput('name', newname)
.clickModalActionSubmitButton()
.wait(2000);
});
```
![input](images/e2e/form/input.png)
- `formJsonInput`
- The form with the `textarea` input box enters the `json` format content
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `content`, the input object
- Take create stack and write the parameter `test/e2e/integration/pages/heat/stack.spec.js` of type `json` as an example
```javascript
it('successfully create', () => {
const volumeJson = {
name: volumeName,
};
cy.clickHeaderButton(1, 2000)
.formAttachFile('content', contentFile)
.formAttachFile('params', paramFile)
.clickStepActionNextButton()
.wait(2000)
.formInput('name', name)
.formJsonInput('volume_name_spec', volumeJson)
.clickStepActionNextButton()
.waitFormLoading()
.wait(5000)
.tableSearchSelectText('Name', name)
.waitStatusActiveByRefresh();
});
```
![textarea-json](images/e2e/form/textarea-json.png)
- `formCheckboxClick`
- check `checkbox` in form
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `index`, default `0`
- Take instance resize `test/e2e/integration/pages/compute/instance.spec.js` as an enample
```javascript
it('successfully resize', () => {
cy.tableSearchText(name)
.clickActionInMoreSub('Resize', 'Configuration Update')
.wait(5000)
.formTableSelect('newFlavor')
.formCheckboxClick('option')
.clickModalActionSubmitButton()
.waitStatusActiveByRefresh();
});
```
![checkbox](images/e2e/form/checkbox.png)
- `formTableSelectAll`
- Click Select all checkbox of the selection type form select all item
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Take cloud hard disk type modification to access `test/e2e/integration/pages/storage/volume-type.spec.js` as an example
```javascript
it('successfully manage access to projects', () => {
cy.tableSearchText(name)
.clickActionInMore('Manage Access')
.formCheckboxClick('isPublic')
.formTableSelectAll('access')
.clickModalActionSubmitButton();
});
```
![select-all](images/e2e/form/select-all.png)
- `formTableNotSelectAll`
- Click Select all checkbox of the selection type form cancel select all item
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Take the Host Aggregates management instance without selecting the instance `test/e2e/integration/pages/compute/aggregate.spec.js` as an example
```javascript
it('successfully manage host: no host', () => {
cy.tableSearchText(newname)
.clickActionInMore('Manage Host')
.formTableNotSelectAll('hosts')
.clickModalActionSubmitButton();
});
```
![unselect-all](images/e2e/form/unselect-all.png)
- `formTableSelect`
- Click checkbox of the selection type form
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `value`, if you set `value`, select the entry in the table that contains the value, if you dont set `value`, select the first entry in the table
- Take instance attach interface select network`test/e2e/integration/pages/compute/instance.spec.js`as an example
```javascript
it('successfully attach interface', () => {
cy.tableSearchText(name)
.clickActionInMoreSub('Attach Interface', 'Related Resources')
.wait(5000)
.formTableSelect('network')
.clickModalActionSubmitButton();
});
```
![select-table](images/e2e/form/select-table.png)
- `formTableSelectBySearch`
- For the selection type form, first to search operation, and then select the first item in the table
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `value`, search content, generally a search for `name` in the search term
- Parameter `waitTime`, wait time after searching, default wait 2 seconds
- Take instance attach volume select volume `test/e2e/integration/pages/compute/instance.spec.js` as an example
- After the operation is successful, enter the Volume list page to check the status of the volume as "used"
```javascript
it('successfully attach volume', () => {
// prepair volume
cy.visitPage(listUrl)
.tableSearchText(name)
.clickActionInMoreSub('Attach Volume', 'Related Resources')
.wait(5000)
.formTableSelectBySearch('volume', volumeName)
.clickModalActionSubmitButton()
.wait(5000);
// check attach successful
cy.tableSearchText(name)
.goToDetail()
.clickDetailTab('Volume')
.tableSearchText(volumeName)
.checkColumnValue(2, 'In-use');
});
```
![select-table-search](images/e2e/form/select-table-search.png)
- `formTableSelectBySearchOption`
- For the selection type form, first to search operation, and then select the first item in the table
- Search is the selection of search item, which is different from `formTableSelectBySearch` which is based on input
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `name` Search options name
- Parameter `value`Search options value
- Parameter `waitTime`wait time after searching, default wait 2 seconds
- Take create full backup `test/e2e/integration/pages/storage/backup.spec.js` as an example
- Select Volume that status is in used
```javascript
it('successfully create full bakcup', () => {
cy.clickHeaderButton(1, 5000)
.formInput('name', name)
.formTableSelectBySearch('volume', volumeName)
.clickModalActionSubmitButton()
.wait(5000)
.waitTableLoading();
cy.clickHeaderButton(1, 5000)
.formInput('name', nameIns)
.formTableSelectBySearchOption('volume', 'Status', 'In-use')
.clickModalActionSubmitButton();
cy.wait(30000);
});
```
![select-table-option](images/e2e/form/select-table-option.png)
- `formSelect`
- Operations on form items of selector type
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `label`, the selected content, if not set, select the first option, if set, select the option corresponding to `label`
- Take create instance group select policy `test/e2e/integration/pages/compute/server-group.spec.js`as an example
```javascript
it('successfully create', () => {
cy.clickHeaderButton(1)
.formInput('name', name)
.formSelect('policy')
.clickModalActionSubmitButton();
});
```
![select](images/e2e/form/select.png)
- Take the network QoS policy to create the bandwidth limit rule and set the direction to "inbound" `test/e2e/integration/pages/network/qos-policy.spec.js` as an example
```javascript
it('successfully create bandwidth ingress limit rule', () => {
cy.tableSearchText(name)
.clickActionInMore('Create Bandwidth Limit Rule')
.formSelect('direction', 'ingress')
.clickModalActionSubmitButton();
});
```
![select-value](images/e2e/form/select-value.png)
- `formRadioChoose`
- Operations on form items of radio type
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `itemIndex`, which item is selected, the default is 0, that is, the first item is selected
- Take create a key, select "import key" `test/e2e/integration/pages/compute/keypair.spec.js` as an example
```javascript
it('successfully create by file', () => {
cy.clickHeaderButton(1)
.formRadioChoose('type', 1)
.formInput('name', nameByFile)
.formAttachFile('public_key', filename)
.clickModalActionSubmitButton()
.tableSearchText(nameByFile)
.checkTableFirstRow(nameByFile);
});
```
![radio](images/e2e/form/radio.png)
- `formAttachFile`
- Operations on form items of AttachFile type
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- The parameter `filename`, the name of the uploaded file, the file needs to be saved in the `test/e2e/fixtures` directory in advance
- Take the creation of a key selection file as an example `test/e2e/integration/pages/compute/keypair.spec.js` as an example
```javascript
it('successfully create by file', () => {
cy.clickHeaderButton(1)
.formRadioChoose('type', 1)
.formInput('name', nameByFile)
.formAttachFile('public_key', filename)
.clickModalActionSubmitButton()
.tableSearchText(nameByFile)
.checkTableFirstRow(nameByFile);
});
```
![attach-file](images/e2e/form/attach-file.png)
- Take create image select file `test/e2e/integration/pages/compute/image.spec.js` as an example
```javascript
it('successfully create', () => {
cy.clickHeaderButton(1)
.url()
.should('include', `${listUrl}/create`)
.formInput('name', name)
.formAttachFile('file', filename)
.formSelect('disk_format', 'QCOW2 - QEMU Emulator')
.formSelect('os_distro', 'Others')
.formInput('os_version', 'cirros-0.4.0-x86_64')
.formInput('os_admin_user', 'root')
.formSelect('usage_type', 'Common Server')
.formText('description', name)
.clickFormActionSubmitButton()
.wait(2000)
.url()
.should('include', listUrl)
.tableSearchText(name)
.waitStatusActiveByRefresh();
});
```
![attach-file-image](images/e2e/form/attach-file-image.png)
- `formAddSelectAdd`
- Operations on form item of AddSelect type
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Take the Host Aggregates management metedata add custom metadata`test/e2e/integration/pages/compute/aggregate.spec.js`as an example
```javascript
it('successfully manage metadata', () => {
cy.tableSearchText(name)
.clickActionInMore('Manage Metadata')
.wait(5000)
.formAddSelectAdd('customs')
.formInputKeyValue('customs', 'key', 'value')
.formTransferLeftCheck('systems', 0)
.clickModalActionSubmitButton();
});
```
![add-select](images/e2e/form/add-select.png)
- `formSwitch`
- Operations on form item of swith type
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Take the example of creating a network QoS policy `test/e2e/integration/pages/network/qos-policy.spec.js` with shared attributes
```javascript
it('successfully create', () => {
cy.clickHeaderButton(1)
.wait(2000)
.formInput('name', name)
.formText('description', name)
.formSwitch('shared')
.clickModalActionSubmitButton();
});
```
![switch](images/e2e/form/switch.png)
- `formButtonClick`
- Click button on form
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Take the example of expanding/closing the "advanced option" `test/e2e/integration/pages/identity/project.spec.js` when the project update quota
```javascript
it('successfully edit quota', () => {
cy.tableSearchText(name)
.clickActionInMore('Edit Quota')
.formInput('instances', 11)
.formButtonClick('more')
.wait(2000)
.formButtonClick('more')
.clickModalActionSubmitButton();
});
```
![more](images/e2e/form/more.png)
![more-open](images/e2e/form/more-open.png)
- `formTransfer`
- Operation on form item of transfer type
1. Specify the items to be selected based on the search display in the transfer on the left
2. Select the first item
3. Click the direction button in the middle of the transfer to make the selected content enter the transfer on the right
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `value`, search content
- Take peoject management user `test/e2e/integration/pages/identity/project.spec.js`as an example
```javascript
it('successfully manage user', () => {
cy.tableSearchText(name)
.clickActionInMore('Manage User')
.formTransfer('select_user', username)
.formTransferRight('select_user', username)
.formSelect('select_user', 'admin')
.clickModalActionSubmitButton();
});
```
![transfer-left](images/e2e/form/transfer-left.png)
- `formTransferRight`
- Specify the items to be selected based on the search display in the transfer on the right对右侧的穿梭框基于搜索展示指定待选条目
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `value`, search content
- Take the user group management user `test/e2e/integration/pages/identity/user-group.spec.js` as an example
```javascript
it('successfully manage user', () => {
cy.tableSearchText(name)
.clickActionInMore('Manage User')
.formTransfer('select_user', username)
.formTransferRight('select_user', username)
.clickModalActionSubmitButton();
cy.tableSearchText(name)
.goToDetail()
.clickDetailTab('Sub User', 'userGroup');
});
```
![transfer-right](images/e2e/form/transfer-right.png)
- `formTabClick`
- Click tab in the form item with tab
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- The parameter `index`, the subscript of the specified Tab
- Take the example of editing the floating IP and switching to the sharing strategy `test/e2e/integration/pages/network/floatingip.spec.js`
```javascript
it('successfully edit', () => {
cy.clickFirstActionButton()
.formText('description', 'description')
.formTabClick('qos_policy_id', 1)
.wait(5000)
.formTableSelectBySearch('qos_policy_id', policyName)
.clickModalActionSubmitButton()
.wait(2000);
});
```
![tab](images/e2e/form/tab.png)
- `formInputKeyValue`
- Input operations on the form items of the `KeyValue` component, generally used in conjunction with `formAddSelectAdd`, and enter the content of the item of the added new `KeyValue` component
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `key`, the content of input on the left
- Parameter `value`, the content of input on the right
- Take the Host Aggregates management metedata add custom metadata`test/e2e/integration/pages/compute/aggregate.spec.js`as an example
```javascript
it('successfully manage metadata', () => {
cy.tableSearchText(name)
.clickActionInMore('Manage Metadata')
.wait(5000)
.formAddSelectAdd('customs')
.formInputKeyValue('customs', 'key', 'value')
.formTransferLeftCheck('systems', 0)
.clickModalActionSubmitButton();
});
```
![key-value](images/e2e/form/key-value.png)
- `formTransferLeftCheck`
- Operation of the transfer on the left
1. Select the specified item in the transfer on the left
2. Click the direction button in the middle of the transfer to make the selected content enter the transfer on the right
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `index`, the index of the node
- Take the Host Aggregates management metedata add custom metadata`test/e2e/integration/pages/compute/aggregate.spec.js`as an example
```javascript
it('successfully manage metadata', () => {
cy.tableSearchText(name)
.clickActionInMore('Manage Metadata')
.wait(5000)
.formAddSelectAdd('customs')
.formInputKeyValue('customs', 'key', 'value')
.formTransferLeftCheck('systems', 0)
.clickModalActionSubmitButton();
});
```
![transfer-left-click](images/e2e/form/transfer-left-click.png)
- `formTransferRightCheck`
- Operation of the transfer on the rigth
1. Select the specified item in the transfer on the rigth
2. Click the direction button in the middle of the transfer to make the selected content enter the transfer on the left
- Parameter `formItemName`, which is the `name` value of `formItem` in the development code
- Parameter `index`, the index of the transfer table item
- Take instance type modify the metadata `test/e2e/integration/pages/compute/flavor.spec.js` as an example
```javascript
it('successfully manage metadata', () => {
cy.clickTab('Custom')
.tableSearchText(customName)
.clickActionButtonByTitle('Manage Metadata')
.wait(5000)
.formTransferLeftCheck('systems', 0)
.clickModalActionSubmitButton();
// todo: remove key-value metadata
cy.clickTab('Custom')
.tableSearchText(customName)
.clickActionButtonByTitle('Manage Metadata')
.wait(5000)
.formTransferRightCheck('systems', 0)
.clickModalActionSubmitButton();
});
```
![transfer-right-check](images/e2e/form/transfer-right-check.png)
For various operations of resource operations, the functions introduced above are mainly used. For the specific compilation of functions, please see`test/e2e/support/form-commands.js`

View File

@ -0,0 +1,548 @@
English | [简体中文](/docs/zh/test/3-2-E2E-table-operation.md)
Because of the consistent use of the front-end framework, when we write related use cases for form operations, select elements and perform operations, we often find that there is a strong regularity, so we have written corresponding Cypress functions for most table operations. It greatly reduces the difficulty of writing test cases. The following will give a detailed description of the main table operation functions.
## Operations on the table
Mainly include: waiting for the list to load
- `waitTableLoading`
- Wait for the list to load
- During the loading process of the list, there will be a state of `loading`, wait for the end of the state
![wait-table-loading](images/e2e/table/wait-table-loading.png)
- `checkTableFirstRow`
- Verify that the first row of the form contains the specified content, generally used to verify the existence of the created resource after creation
- The parameter `name`, the content that needs to be included in the first line, is generally used to verify the existence of the name
- Take viewing key pair detail `test/e2e/integration/pages/compute/keypair.spec.js` as an example
- After creation, check whether the key exists, and enter the details page after successful verification
```javascript
it('successfully detail', () => {
cy.tableSearchText(name)
.checkTableFirstRow(name)
.goToDetail()
.checkDetailName(name);
cy.goBackToList(listUrl);
});
```
![check-first-row](images/e2e/table/check-first-row.png)
- `tableSearchText`
- Typing in the search bar above the table, and wait for the search to complete
- The parameter `str`, the search content, generally the search name
- By searching, the resource to be operated is located in the first row of the table for subsequent operations
- Take viewing key pair detail `test/e2e/integration/pages/compute/keypair.spec.js` as an example
1. After creation, use the name to search for the key and wait for the search to complete
2. Check if the first row in the table contains the resource with the specified name
3. Go to the detail page and check if the name is consistent with expectations
4. Return list page
```javascript
it('successfully detail', () => {
cy.tableSearchText(name)
.checkTableFirstRow(name)
.goToDetail()
.checkDetailName(name);
cy.goBackToList(listUrl);
});
```
![search](images/e2e/table/search.png)
- `tableSimpleSearchText`
- Type in the search bar above the form and wait for the search to complete
- Some tables use simple search, and the search item only supports text input. At this time, the components used in the search box are different from the search box components in `tableSearchText`
- The parameter `str`, the search content, generally the search name
- By searching, the resource to be operated is located in the first row of the table for subsequent operations
- Take instance `test/e2e/integration/pages/configuration/system.spec.js` in the search system information as an example
```javascript
it('successfully services', () => {
cy.tableSimpleSearchText('nova');
});
```
![simple-search](images/e2e/table/simple-search.png)
- `tableSearchSelect`
- Use the options in the search bar above the table to search and wait for the search to complete
1. Click the input box and select the search item from the search items to be selected
2. Click to select the option under the search category
3. Wait for the search to complete
- Parameter `name`, the name of the search term
- Parameter `value`, the label of the selected item corresponding to the search item
- By searching, the resource to be operated is located in the first row of the table for subsequent operations
- Take instance attach floating IP `test/e2e/integration/pages/network/floatingip.spec.js` as an example
1. In the floating IP table, search for the floating IP whose `status` is `stop`
2. Click the `associate` operation on the first resource in the table
3. Complete the operation of attach instance
```javascript
it('successfully associate instance', () => {
cy.tableSearchSelect('Status', 'Down')
.clickActionInMore('Associate')
.wait(5000)
.formTableSelectBySearch('instance', instanceName)
.wait(5000)
.formTableSelect('port')
.clickModalActionSubmitButton();
});
```
![search-select-1](images/e2e/table/search-select-1.png)
![search-select-2](images/e2e/table/search-select-2.png)
![search-select-3](images/e2e/table/search-select-3.png)
- `tableSearchSelectText`
- Use the search bar above the table to search and wait for the search to complete
1. Click the input box and select the search item from the search items to be selected
2. Enter the search content and press Enter
3. Wait for the search to complete
- Enter directly when you dont select the search item, it is the first search item that supports input
- Parameter `name`, the name of the search term
- Parameter `value`, the content of the input
- By searching, the resource to be operated is located in the first row of the table for subsequent operations
- Take the creation of the stack `test/e2e/integration/pages/heat/stack.spec.js` as an example
1. After creation, enter the resource list page
2. Search by name on the list page
3. Wait for the status of the resource to be available
```javascript
it('successfully create', () => {
const volumeJson = {
name: volumeName,
};
cy.clickHeaderButton(1, 2000)
.formAttachFile('content', contentFile)
.formAttachFile('params', paramFile)
.clickStepActionNextButton()
.wait(2000)
.formInput('name', name)
.formJsonInput('volume_name_spec', volumeJson)
.clickStepActionNextButton()
.waitFormLoading()
.wait(5000)
.tableSearchSelectText('Name', name)
.waitStatusActiveByRefresh();
});
```
![search-text-1](images/e2e/table/search-text-1.png)
![search-text-2](images/e2e/table/search-text-2.png)
![search-text-3](images/e2e/table/search-text-3.png)
- `checkEmptyTable`
- Verify that the form is empty
- Generally used to verify after deleting resources
- Take deleting the router `test/e2e/integration/pages/network/router.spec.js` as an example
1. Turn off the external gateway
2. Delete
3. Search
4. Verify that the form is empty, that is, the deletion is successful
```javascript
it('successfully close external gateway and delete', () => {
cy.tableSearchText(newname)
.clickConfirmActionInMore('Close External Gateway')
.clickConfirmActionInMore('Delete')
.tableSearchText(newname)
.checkEmptyTable();
});
```
- `goToDetail`
- Visit the detail page of the first row of resources and wait for the detail page to load
- Parameter `index`, the subscript of the column where the link is located, the default is `1`
- Parameter `waitTime`, the time to wait after loading the details page
- Take the image `test/e2e/integration/pages/compute/image.spec.js` as an example
1. Search
2. Enter the details page
3. Verification details name
4. Return to the list page
```javascript
it('successfully detail', () => {
cy.tableSearchText(name).goToDetail();
cy.checkDetailName(name);
cy.goBackToList(listUrl);
});
```
![detail-1](images/e2e/table/detail-1.png)
![detail-2](images/e2e/table/detail-2.png)
- `checkColumnValue`
- Verify that the content of the specified column in the first row meets expectations
- Parameter `columnIndex`, which specifies the index of the column
- Parameter `value`, the expected value
- Take the instance `test/e2e/integration/pages/compute/image.spec.js` as an example
1. Search
2. Stop the instance
3. Verify that the status of the instance is `Stop`
4. Verify that the `stop` operation in the batch operation is unavailable
```javascript
it('successfully stop', () => {
cy.tableSearchText(name)
.clickConfirmActionInMoreSub('Stop', 'Instance Status')
.wait(10000)
.tableSearchText(name)
.checkColumnValue(6, 'Shutoff')
.selectFirst()
.clickHeaderButtonByTitle('Stop')
.checkDisableAction(2000);
});
```
![check-value](images/e2e/table/check-value.png)
- `selectFirst`
- Select the first row in the table for subsequent batch operations
- Take instance `test/e2e/integration/pages/compute/image.spec.js` as an example
1. Search
2. Stop the instance
3. Verify that the status of the instance is `Stop`
4. Select the first row
5. Click the `Stop` button in the batch operation
6. An error message pops up
```javascript
it('successfully stop', () => {
cy.tableSearchText(name)
.clickConfirmActionInMoreSub('Stop', 'Instance Status')
.wait(10000)
.tableSearchText(name)
.checkColumnValue(6, 'Shutoff')
.selectFirst()
.clickHeaderButtonByTitle('Stop')
.checkDisableAction(2000);
});
```
![select-first](images/e2e/table/select-first.png)
- `selectAll`
- Check all the entries in the table, in order to do the follow-up batch operations
- Usually used to clear data
- `waitStatusActiveByRefresh`
- Click the refresh button above the table every 5 seconds until the resource status becomes available
- After a resource is created or changed, it often takes a certain amount of time to become available before subsequent operations can be performed
- Take the creation of the stack `test/e2e/integration/pages/heat/stack.spec.js` as an example
```javascript
it('successfully create', () => {
const volumeJson = {
name: volumeName,
};
cy.clickHeaderButton(1, 2000)
.formAttachFile('content', contentFile)
.formAttachFile('params', paramFile)
.clickStepActionNextButton()
.wait(2000)
.formInput('name', name)
.formJsonInput('volume_name_spec', volumeJson)
.clickStepActionNextButton()
.waitFormLoading()
.wait(5000)
.tableSearchSelectText('Name', name)
.waitStatusActiveByRefresh();
});
```
![wait-1](images/e2e/table/wait-1.png)
![wait-2](images/e2e/table/wait-2.png)
## Operation of the button
Mainly contains
- The main button operation (general is creation operation) and batch operation located at the top of the form
- Line operations on each line of the form
### Operation of the buttons above the form
The buttons above the table generally include: refresh, create, batch operation button, configure table list items, download
- `clickHeaderButton`
- Click the button above the table,
- Parameter `buttonIndex`, the subscript of the button above the table
- Parameter `waitTime`, the waiting time after clicking, the default is 2 seconds
- Generally, the subscript of the created button is 1
- Take the creat key pair `test/e2e/integration/pages/compute/keypair.spec.js` as an example
```javascript
it('successfully create', () => {
cy.clickHeaderButton(1)
.formInput('name', name)
.clickModalActionSubmitButton()
.wait(5000);
});
```
![header-btn-index](images/e2e/table/header-btn-index.png)
- `clickHeaderButtonByTitle`
- Click the button above the table by name, generally used for batch operation button clicks
- Parameter `title`, the text on the button above the table
- Parameter `waitTime`, the waiting time after clicking, the default is 2 seconds
- Take the shut off operation of the instance in the close state `test/e2e/integration/pages/compute/instance.spec.js` as an example
- Click the close button at the top of the form
```javascript
it('successfully stop', () => {
cy.tableSearchText(name)
.clickConfirmActionInMoreSub('Stop', 'Instance Status')
.wait(10000)
.tableSearchText(name)
.checkColumnValue(6, 'Shutoff')
.selectFirst()
.clickHeaderButtonByTitle('Stop')
.checkDisableAction(2000);
});
```
![header-btn-title](images/e2e/table/header-btn-title.png)
- `clickHeaderConfirmButtonByTitle`
- The function will complete
1. Click the button at the top of the table by name, the page will pop up a prompt to confirm the operation
2. Click the `Confirm` button
- Parameter `title`, the text on the button above the table
- Parameter `waitTime`, the waiting time after clicking, the default is 2 seconds
- Take the release of floating IP `test/e2e/integration/pages/network/floatingip.spec.js` as an example
- Select all floating IPs in the stopped state and release them in batches
```javascript
it('successfully delete', () => {
cy.tableSearchSelect('Status', 'Down')
.selectAll()
.clickHeaderConfirmButtonByTitle('Release');
});
```
![header-confirm-title](images/e2e/table/header-confirm-title.png)
### Row operations on the first row of the form
- `clickFirstActionButton`
- Click the first button in the operation column of the first row of the form, which is generally used for pop-up operation buttons
Single-page operation button click
- Take edit user `test/e2e/integration/pages/identity/user.spec.js` as an example
```javascript
it('successfully edit', () => {
cy.tableSearchText(name)
.clickFirstActionButton()
.formInput('name', newname)
.clickModalActionSubmitButton();
});
```
![click-first](images/e2e/table/click-first.png)
- `clickActionButtonByTitle`
- Click the operation in the first row according to the title
- Take edit and starting instance `test/e2e/integration/pages/configuration/system.spec.js` as an example
- When instance starts, click the `Disable` button
- When instance is stopped, click the `Enable` button
```javascript
it('successfully disable compute services', () => {
cy.clickTab(computeServicesTab)
.tableSearchText('nova-compute')
.clickActionButtonByTitle('Disable')
.formText('disabled_reason', reason)
.clickModalActionSubmitButton();
});
it('successfully enable compute services', () => {
cy.clickTab(computeServicesTab)
.tableSearchSelect('Service Status', 'Disabled')
.clickActionButtonByTitle('Enable')
.clickConfirmActionSubmitButton();
});
```
![action-by-title](images/e2e/table/action-by-title.png)
![action-by-title-2](images/e2e/table/action-by-title-2.png)
- `clickActionInMore`
- Click the operation in `More` in the first row according to the title
- Take the create instance button `test/e2e/integration/pages/compute/image.spec.js` as an example
```javascript
it('successfully create instance with cancel', () => {
cy.tableSearchText(name)
.clickActionInMore('Create Instance')
.wait(2000)
.clickStepActionCancelButton();
});
```
![action-in-more](images/e2e/table/action-in-more.png)
- `clickActionInMoreSub`
- Click the operation under the submenu of the first row of operations according to the title
- Parameter `title`, the title of the button
- Parameter `subMenu`, the title of the submenu
- Take the instance and click on the `Attach Interface` `test/e2e/integration/pages/compute/image.spec.js` under `Associated Resources` as an example
```javascript
it('successfully attach interface', () => {
cy.tableSearchText(name)
.clickActionInMoreSub('Attach Interface', 'Related Resources')
.wait(5000)
.formTableSelect('network')
.clickModalActionSubmitButton();
});
```
![action-in-sub](images/e2e/table/action-in-sub.png)
- `checkActionDisabledInFirstRow`
- Verify that the specified operation of the resource with the specified name is not available
1. Search for resources based on specified names
2. Verify that the specified operation does not exist in the operation column `More` in the first row of the search result
- Parameter `title`, the name of the operation
- Parameter `name`, the name of the resource
- After the resource is in certain states, some operations need to be disabled, the first operation in the row operation list, if it is not operable, it is in the `disabled` state, and the operations in `more`, if not available , Dont show
- Take the router `test/e2e/integration/pages/network/router.spec.js` as an example
1. Open the public network gateway when creating the router
2. Verify that the router cannot be deleted, that is, there is no `Delete` button
```javascript
it('successfully disable delete', () => {
cy.checkActionDisabledInFirstRow('Delete', name);
});
```
![disable-more-action](images/e2e/table/disable-more-action.png)
- `clickFirstActionDisabled`
- Verify that the first operation in the first row of the table is unavailable
- After the resource is in certain states, some operations need to be disabled, the first operation in the row operation list, if it is not operable, it is in the `disabled` state, and the operations in `more`, if not available , Dont show
- Take instance group `test/e2e/integration/pages/compute/server-group.spec.js` as an example
1. Create a instance under the instance group
2. Verify that the instance group containing instance cannot be deleted
3. After deleting instance, the instance group is successfully deleted
```javascript
it('successfully delete', () => {
cy.clickFirstActionDisabled();
cy.forceDeleteInstance(instanceName);
cy.wait(5000);
cy.visitPage(listUrl)
.tableSearchText(name)
.clickConfirmActionInFirst()
.checkEmptyTable();
});
```
![disable-first](images/e2e/table/disable-first.png)
- `clickConfirmActionInFirst`
- Complete the operation corresponding to the first operation button in the first row of the table
1. Click the first operation button in the first row of the table. This operation is a confirmation operation
2. Click the `Confirm` button, and wait for the request to complete, close the prompt message that the request is successful
- Parameter `waitTime`, the waiting time after closing the operation successful prompt
- Take instance group `test/e2e/integration/pages/compute/server-group.spec.js` as an example
1. Create a instance under the instance group
2. Verify that the instance group containing instance cannot be deleted
3. After deleting the instance, the instance group is successfully deleted
```javascript
it('successfully delete', () => {
cy.clickFirstActionDisabled();
cy.forceDeleteInstance(instanceName);
cy.wait(5000);
cy.visitPage(listUrl)
.tableSearchText(name)
.clickConfirmActionInFirst()
.checkEmptyTable();
});
```
![first-confirm](images/e2e/table/first-confirm.png)
![first-confirm-2](images/e2e/table/first-confirm-2.png)
- `clickConfirmActionButton`
- Complete the corresponding operation in the operation buttons listed in the first row of the table
1. Click the specified operation in the first row of the table. This operation is a confirmation operation
2. Click the `Confirm` button, and wait for the request to complete, close the prompt message that the request is successful
- Parameter `title`, specify the name of the operation
- Parameter `waitTime`, the waiting time after closing the operation prompt successfully
- Take delet VPN IPsec policy `test/e2e/integration/pages/compute/server-group.spec.js` as an example
```javascript
it('successfully delete ipsec policy', () => {
cy.clickTab('IPsec Policy')
.tableSearchText(ipsecPolicy)
.clickConfirmActionButton('Delete');
});
```
![confirm-action](images/e2e/table/confirm-action.png)
- `clickConfirmActionInMore`
- Complete the corresponding operation in `More` in the first row of the table
1. Click the specified operation in `More` in the first row of the table. This operation is a confirmation operation
2. Click the `Confirm` button, and wait for the request to complete, close the prompt message that the request is successful
- Parameter `title`, specify the name of the operation
- Parameter `waitTime`, the waiting time after closing the operation prompt successfully
- Take deleting the router `test/e2e/integration/pages/network/router.spec.js` as an example
1. Search
2. Complete the operation of `Close public gateway` in `More`
2. Complete the `Delete` operation in `More`
```javascript
it('successfully close external gateway and delete', () => {
cy.tableSearchText(newname)
.clickConfirmActionInMore('Close External Gateway')
.clickConfirmActionInMore('Delete')
.tableSearchText(newname)
.checkEmptyTable();
});
```
![confirm-more-1](images/e2e/table/confirm-more-1.png)
![confirm-more-2](images/e2e/table/confirm-more-2.png)
- `clickConfirmActionInMoreSub`
- Complete the corresponding operation under the specified submenu in `More` in the first row of the table
1. Click the specified operation under the specified submenu in `More` in the first row of the table. This operation is a confirmation operation
2. Click the `Confirm` button, and wait for the request to complete, close the prompt message that the request is successful
- Parameter `title`, specify the name of the operation
- The parameter `subMenu`, specifies the name of the submenu
- Parameter `waitTime`, the waiting time after closing the operation prompt successfully
- Take lock the instance `test/e2e/integration/pages/compute/instance.spec.js` as an example
```javascript
it('successfully lock', () => {
cy.tableSearchText(name)
.clickConfirmActionInMoreSub('Lock', 'Instance Status')
.wait(10000);
cy.tableSearchText(name)
.selectFirst()
.clickHeaderButtonByTitle('Start')
.checkDisableAction(2000)
.clickHeaderButtonByTitle('Stop')
.checkDisableAction(2000)
.clickHeaderButtonByTitle('Reboot')
.checkDisableAction(2000);
});
```
![confirm-in-sub](images/e2e/table/confirm-in-sub.png)
For the various operations of the table operation, the functions introduced above are mainly used. For the specific writing of the functions, please view `test/e2e/support/table-commands.js`

View File

@ -0,0 +1,96 @@
English | [简体中文](/docs/zh/test/3-3-E2E-detail-operation.md)
Because of the consistency of the front-end framework, we often find that there is a strong regularity when we write related use cases for detailed operations, select elements and perform operations, so we have written corresponding Cypress functions for most detailed operations. It greatly reduces the difficulty of writing test cases. The following will give a detailed description of the main table operation functions.
- `checkDetailName`
- Verify that the header of the detail page contains the specified resource name
- Parameter `name`, resource name
- Take viewing key detail `test/e2e/integration/pages/compute/keypair.spec.js` as an example
```javascript
it('successfully detail', () => {
cy.tableSearchText(name)
.checkTableFirstRow(name)
.goToDetail()
.checkDetailName(name);
cy.goBackToList(listUrl);
});
```
![name](images/e2e/detail/name.png)
- `goBackToList`
- Click the `Back` button on the detail page to enter the list page and wait for the list to load
- Parameter `url`, list url
- If set, it will verify whether the returned list route meets expectations
- Take viewing key detail `test/e2e/integration/pages/compute/keypair.spec.js` as an example
1. Search
2. Verify that the first row of the form contains the specified name
3. Enter the detail page
4. Verify the name of the detail page
5. Return to the list page
```javascript
it('successfully detail', () => {
cy.tableSearchText(name)
.checkTableFirstRow(name)
.goToDetail()
.checkDetailName(name);
cy.goBackToList(listUrl);
});
```
![list](images/e2e/detail/list.png)
- `goBackToList`
- Click the `Back` button on the detail page to enter the list page and wait for the list to load
- Parameter `url`, list url
- If set, it will verify whether the returned list route meets expectations
- Take viewing key detail `test/e2e/integration/pages/compute/keypair.spec.js` as an example
1. Search
2. Verify that the first row of the form contains the specified name
3. Enter the detail page
4. Verify the name of the detail page
5. Return to the list page
```javascript
it('successfully detail', () => {
cy.tableSearchText(name)
.checkTableFirstRow(name)
.goToDetail()
.checkDetailName(name);
cy.goBackToList(listUrl);
});
```
![list](images/e2e/detail/list.png)
- `clickDetailTab`
- Click the designated Tab tab at the bottom of the details page and wait for the relevant resource list to load
- Parameter `label`, the specified Tab label
- Parameter `urlTab`, the tab attribute in the route
- If set, it will verify whether the tab attribute in the route is as expected after switching the label
- Parameter `waitTime`, the waiting time after switching labels
- Take viewing network details `test/e2e/integration/pages/network/network.spec.js` as an example
1. Search
2. Verify that the first row of the form contains the specified name
3. Enter the details page
4. Verify the name of the details page
5. Click the subnet Tab and wait for the list to load
6. Click the port Tab, and wait for the list to load
5. Return to the list page
```javascript
it('successfully detail', () => {
cy.tableSearchText(name)
.checkTableFirstRow(name)
.goToDetail()
.checkDetailName(name);
cy.clickDetailTab('Subnets', 'subnets').clickDetailTab('Ports', 'ports');
cy.goBackToList(listUrl);
});
```
![tab](images/e2e/detail/tab.png)
For the details page, the functions introduced above are mainly used. For the specific writing of the functions, please see`test/e2e/support/detail-commands.js`

View File

@ -0,0 +1,276 @@
English | [简体中文]](/docs/zh/test/3-4-E2E-resource-operation.md)
In the E2E process, when creating a resource, it is often necessary to create the associated resource first, and after deleting the resource, the related resource also needs to be deleted. Therefore, the operation of the related resource is encapsulated based on the principle of complete creation/deletion.
- `createInstance`
- Create instance and wait for the instance to become `running`
- Parameter `name`, the name of the instance
- Parameter `networkName`, the network name selected when the instance was created
- Take the floating IP associated instance `test/e2e/integration/pages/network/floatingip.spec.js` as an example
- In order to successfully associate with the instance, the router connected to the subnet where the instance's interfae is located must have a public network gateway turned on
1. Create a network `networkName` with subnet
2. Create a router `routerName` with the public network gateway turned on and connected to the network `networkName` subnet
3. Create a instance `instanceName` with a interfae on the network `networkName`
```javascript
it('successfully prepair resource', () => {
cy.createNetwork({ name: networkName });
cy.createRouter({ name: routerName, network: networkName });
cy.createInstance({ name: instanceName, networkName });
});
```
- `createNetwork`
- Create a network with a subnet
- Parameter `name`, the name of the network
- Parameter `networkName`, the network name selected when the instance was created
- Take the router connected to the subnet as an example `test/e2e/integration/pages/network/router.spec.js` as an example
- Created a network named `networkName` in preparation for connecting to subnets
```javascript
it('successfully prepair resource', () => {
cy.createNetwork({ name: networkName });
});
```
- `createNetworkPolicy`
- Create network QoS policy
- Parameter `name`, the name of the strategy
- Take virtual adapter modification QoS as an example `test/e2e/integration/pages/network/virtual-adapter.spec.js` as an example
- Created a policy named `policyName` in preparation for modifying QoS
```javascript
it('successfully prepair resource by admin', () => {
cy.loginAdmin().wait(5000).createNetworkPolicy({ name: policyName });
});
```
- `createRouter`
- Create a router with a public network gateway turned on
- Parameter `name`, the name of the router
- Parameter `network`
- If set, the router will connect to the subnet of the `network` network
- Take the floating IP associated instance `test/e2e/integration/pages/network/floatingip.spec.js` as an example
- In order to successfully associate with the instance, the router connected to the subnet where the instance's interfae is located must have a public network gateway turned on
1. Create a network `networkName` with subnets
2. Create a router `routerName` with the public network gateway turned on and connected to the network `networkName` subnet
3. Create a instance `instanceName` with a interfae on the network `networkName`
```javascript
it('successfully prepair resource', () => {
cy.createNetwork({ name: networkName });
cy.createRouter({ name: routerName, network: networkName });
cy.createInstance({ name: instanceName, networkName });
});
```
- `deleteRouter`
- Deleting the router will disconnect the router's subnet, turn off the router's public network gateway, and finally successfully delete the router
- Parameter `network`
- If set, you need to disconnect the router's subnet first
- Parameter `name`, the name of the router
- Take the floating IP to delete the associated resource `test/e2e/integration/pages/network/floatingip.spec.js` as an example
- In order to successfully associate with the instance, the router connected to the subnet where the instance's interfae is located must have a public network gateway turned on
```javascript
it('successfully delete related resources', () => {
cy.forceDeleteInstance(instanceName);
cy.deleteRouter(routerName, networkName);
cy.deleteAll('network', networkName);
cy.loginAdmin().wait(5000);
cy.deleteAll('networkQosPolicy', policyName);
});
```
- `forceDeleteInstance`
- Force delete instance instead of soft delete
- Parameter `name`, the name of the instance
- Take deleting the instance group `test/e2e/integration/pages/compute/server-group.spec.js` as an example
1. Delete the instance under the instance group first
2. Then successfully delete the instance group
```javascript
it('successfully delete', () => {
cy.clickFirstActionDisabled();
cy.forceDeleteInstance(instanceName);
cy.wait(5000);
cy.visitPage(listUrl)
.tableSearchText(name)
.clickConfirmActionInFirst()
.checkEmptyTable();
});
```
- `createVolume`
- Create volume
- Parameter `name`, the name of the volume
- Take volume backup `test/e2e/integration/pages/storage/backup.spec.js` as an example
- To create a volume backup, you need to prepare the volume first
```javascript
it('successfully prepair resource', () => {
cy.createVolume(volumeName);
cy.createNetwork({ name: networkName });
cy.createInstance({ name: instanceName, networkName });
});
```
- `createSecurityGrouop`
- Create a security group
- Parameter `name`, the name of the security group
- Take the virtual adapter card `test/e2e/integration/pages/network/virtual-adapter.spec.js` as an example
-To test management security group, you need to prepare the security group first
```javascript
it('successfully prepair resource', () => {
cy.createFip();
cy.createSecurityGrouop({ name: securityGroupName });
cy.createNetwork({ name: networkName });
cy.createRouter({ name: routerName, network: networkName });
cy.createInstance({ name: instanceName, networkName });
});
```
- `createFip`
- Create floating ip
- Take instance `test/e2e/integration/pages/compute/instance.spec.js`as an example
- Test associate floating IP, you need to prepare reachable floating IP
```javascript
it('successfully prepair resource', () => {
cy.createNetwork({ name: networkName });
cy.createRouter({ name: routerName, network: networkName });
cy.createFip();
cy.createVolume(volumeName);
});
```
- `createUserGroup`
- Create user group
- Parameter `name`, the name of user group
- Take project `test/e2e/integration/pages/identity/project.spec.js`as an example
- To test management user group, you need to prepare the user group
```javascript
it('successfully prepair resource', () => {
cy.createUser({ name: username });
cy.createUserGroup({ name: userGroupName });
});
```
- `createUser`
- Create user
- Parameter `name`, user name
- Take project `test/e2e/integration/pages/identity/project.spec.js`as an example
- To test management user, you need to prepare user
```javascript
it('successfully prepair resource', () => {
cy.createUser({ name: username });
cy.createUserGroup({ name: userGroupName });
});
```
- `createProject`
- Create project
- Parameter`name`, the name of project
- Take user`test/e2e/integration/pages/identity/user.spec.js`as an example
- To test creater user, need to prepare project
- To test management project permission need to prepare project
```javascript
it('successfully prepair resource', () => {
cy.createProject({ name: projectName });
cy.createProject({ name: projectName2 });
cy.createUserGroup({ name: userGroupName });
});
```
- `createIronicImage`
- Create image for ironic
- Parameter `name`, the name of the image
- Take ironic `test/e2e/integration/pages/compute/ironic.spec.js` as an example
- Create a ironic, image need to be able to create a ironic
```javascript
it('successfully prepair resource', () => {
cy.createNetwork({ name: networkName });
cy.createRouter({ name: routerName, network: networkName });
cy.createFip();
cy.createIronicImage({ name: imageName });
});
```
- `deleteInstance`
- Delete instance
- Parameter `name`, name of instance
- Parameter `deleteRecycleBin`, Default `true`, Indicates that you need to enter the recycle bin to delete again
- Take delete instance `test/e2e/integration/pages/compute/instance.spec.js` as an example
```javascript
it('successfully delete', () => {
cy.deleteInstance(newname);
});
```
- `deleteAllAvailableVolume`
-Delete all availablevolume
-Take instance `test/e2e/integration/pages/compute/instance.spec.js` as an example
```javascript
it('successfully delete related resources', () => {
cy.deleteAll('fip');
cy.deleteRouter(routerName, networkName);
cy.deleteAll('network', networkName);
cy.deleteAll('volume', volumeName);
cy.deleteAllAvailableVolume();
});
```
- `deleteAll`
- Delete qualified resources
- Parameter `resourceName`, resource name
```javacript
export default {
// compute
instance: instanceListUrl,
image: imageListUrl,
// storage
volume: volumeListUrl,
volumeSnapshot: volumeSnapshotListUrl,
backup: backupListUrl,
volumeType: volumeTypeListUrl,
// network
network: networkListUrl,
router: routerListUrl,
networkQosPolicy: policyListUrl,
fip: fipListUrl,
virtualAdapter: virtualAdapterListUrl,
// security
securityGroup: securityGroupListUrl,
// identity
project: projectListUrl,
user: userListUrl,
userGroup: userGroupListUrl,
};
```
- Parameter `name`
- If set, delete the resource with the specified name
- If not set, all resources under the resource list will be deleted
- Parameter `tab`
- If set, it means that the resource is located under the tab `tab`, you need to switch to the specified tab first
- Take the volume type `test/e2e/integration/pages/storage/volume-type.spec.js` as an example
- Delete the QoS prepared when managing QoS
```javascript
it('successfully delete related resources', () => {
cy.deleteAll('volumeType', qosName, 'QoS');
});
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -76,7 +76,7 @@
yarn run test:e2e
```
![控制台](/docs/zh/test/images/e2e/console.png)
![控制台](images/e2e/console.png)
## GUI 运行 E2E
@ -86,15 +86,15 @@ yarn run test:e2e:open
Cypress 提供了 GUI
![gui](/docs/zh/test/images/e2e/gui-list.png)
![gui](images/e2e/gui-list.png)
![work](/docs/zh/test/images/e2e/gui-work.png)
![work](images/e2e/gui-work.png)
## E2E 测试结果
测试运行结束后,访问`test/e2e/report/merge-report.html`即可查看
![结果](/docs/zh/test/images/e2e/result.png)
![结果](images/e2e/result.png)
## E2E 代码覆盖率测试结果
@ -139,4 +139,4 @@ yarn run test:unit
直接在命令行控制台中即可查看运行结果
![单元测试结果](/docs/zh/test/images/unit/result.png)
![单元测试结果](images/unit/result.png)

View File

@ -9,24 +9,24 @@
- `closeNotice`
- 关闭操作后右上角的操作成功的提示信息
![notice](/docs/zh/test/images/e2e/form/notice.png)
![notice](images/e2e/form/notice.png)
- `waitFormLoading`
- 等待表单请求完成
- 表单填写并验证通过后,点击确认按钮,会向服务端发起相应请求,这时表单项的确认按钮会处于`Loading`的状态
- 使用该函数,而不是`cy.wait(seconds)`,能更有效的保证同步请求已经处理完全,从而保证后续用例的先决条件
![wait-form-loading](/docs/zh/test/images/e2e/form/wait-form-loading.png)
![wait-form-loading](images/e2e/form/wait-form-loading.png)
- `clickFormActionSubmitButton`
- 点击确认型表单的确认按钮,并等待请求完成
![click-form-submit](/docs/zh/test/images/e2e/form/click-form-submit.png)
![click-form-submit](images/e2e/form/click-form-submit.png)
- `clickModalActionSubmitButton`
- 点击弹窗型表单的确认按钮,并等待请求完成
![click-modal-submit](/docs/zh/test/images/e2e/form/click-modal-submit.png)
![click-modal-submit](images/e2e/form/click-modal-submit.png)
- `clickModalActionCancelButton`
- 点击弹窗型表单的取消按钮
@ -34,7 +34,7 @@
- 点击确认型表单的确认按钮,等待请求完成,并关闭请求成功的提示信息
- 参数`waitTime`,关闭提示信息后的等待时间
![click-confirm-submit](/docs/zh/test/images/e2e/form/click-confirm-submit.png)
![click-confirm-submit](images/e2e/form/click-confirm-submit.png)
- `checkDisableAction`
- 某些数据不符合要求时,使用批量操作,会弹出报错,该函数验证该数据的确不合操作要求,并关闭报错提示
@ -57,7 +57,7 @@
});
```
![disable-action](/docs/zh/test/images/e2e/form/disable-action.png)
![disable-action](images/e2e/form/disable-action.png)
- `clickStepActionNextButton`
- 点击分步表单的下一步/确认按钮
@ -98,7 +98,7 @@
});
```
![click-step-next](/docs/zh/test/images/e2e/form/click-step-next.png)
![click-step-next](images/e2e/form/click-step-next.png)
- `clickStepActionCancelButton`
- 点击分步表单的取消按钮
@ -118,7 +118,7 @@
通过页面查看元素的结构、样式等,发现,所有的表单项,都具有`id`,而且对应于开发时编写的表单配置`formItem`的`name`属性,也可直接通过查看页面内元素的`id`获取`name`,如下图所示,`form-item-col-`之后的内容便是`name`
![form-name](/docs/zh/test/images/e2e/form/form-name.png)
![form-name](images/e2e/form/form-name.png)
- `formInput`
- 带有`input`输入框的表单项输入内容
@ -136,7 +136,7 @@
});
```
![input](/docs/zh/test/images/e2e/form/input.png)
![input](images/e2e/form/input.png)
- `formJsonInput`
- 带有`textarea`输入框的表单项输入`json`格式内容
@ -164,7 +164,7 @@
});
```
![textarea-json](/docs/zh/test/images/e2e/form/textarea-json.png)
![textarea-json](images/e2e/form/textarea-json.png)
- `formCheckboxClick`
- 点击表单项中的`checkbox`
@ -184,7 +184,7 @@
});
```
![checkbox](/docs/zh/test/images/e2e/form/checkbox.png)
![checkbox](images/e2e/form/checkbox.png)
- `formTableSelectAll`
- 对表格选择类型的表单项做全选操作
@ -201,7 +201,7 @@
});
```
![select-all](/docs/zh/test/images/e2e/form/select-all.png)
![select-all](images/e2e/form/select-all.png)
- `formTableNotSelectAll`
- 对表格选择类型的表单项做取消全选操作
@ -217,7 +217,7 @@
});
```
![unselect-all](/docs/zh/test/images/e2e/form/unselect-all.png)
![unselect-all](images/e2e/form/unselect-all.png)
- `formTableSelect`
- 对表格选择类型的表单项做选择操作
@ -235,7 +235,7 @@
});
```
![select-table](/docs/zh/test/images/e2e/form/select-table.png)
![select-table](images/e2e/form/select-table.png)
- `formTableSelectBySearch`
- 对表格选择类型的表单项,先做搜索操作,然后选择条目中的第一条
@ -266,7 +266,7 @@
});
```
![select-table-search](/docs/zh/test/images/e2e/form/select-table-search.png)
![select-table-search](images/e2e/form/select-table-search.png)
- `formTableSelectBySearchOption`
- 对表格选择类型的表单项,先做搜索操作,然后选择条目中的第一条
@ -296,7 +296,7 @@
});
```
![select-table-option](/docs/zh/test/images/e2e/form/select-table-option.png)
![select-table-option](images/e2e/form/select-table-option.png)
- `formSelect`
- 对选择器类型的表单项的操作
@ -313,7 +313,7 @@
});
```
![select](/docs/zh/test/images/e2e/form/select.png)
![select](images/e2e/form/select.png)
- 以网络 QoS 策略创建带宽限制规则时设置方向为“入方向”`test/e2e/integration/pages/network/qos-policy.spec.js`为例
@ -326,7 +326,7 @@
});
```
![select-value](/docs/zh/test/images/e2e/form/select-value.png)
![select-value](images/e2e/form/select-value.png)
- `formRadioChoose`
- 对单选类型的表单项的操作
@ -346,7 +346,7 @@
});
```
![radio](/docs/zh/test/images/e2e/form/radio.png)
![radio](images/e2e/form/radio.png)
- `formAttachFile`
- 对上传文件的表单项的操作
@ -366,7 +366,7 @@
});
```
![attach-file](/docs/zh/test/images/e2e/form/attach-file.png)
![attach-file](images/e2e/form/attach-file.png)
- 以创建镜像选择文件为例`test/e2e/integration/pages/compute/image.spec.js`为例
@ -392,7 +392,7 @@
});
```
![attach-file-image](/docs/zh/test/images/e2e/form/attach-file-image.png)
![attach-file-image](images/e2e/form/attach-file-image.png)
- `formAddSelectAdd`
- 对可增加条目的表单项的操作
@ -411,7 +411,7 @@
});
```
![add-select](/docs/zh/test/images/e2e/form/add-select.png)
![add-select](images/e2e/form/add-select.png)
- `formSwitch`
- 对开关型的表单项的点击操作
@ -429,7 +429,7 @@
});
```
![switch](/docs/zh/test/images/e2e/form/switch.png)
![switch](images/e2e/form/switch.png)
- `formButtonClick`
- 对表单项中的按钮的点击操作
@ -448,9 +448,9 @@
});
```
![more](/docs/zh/test/images/e2e/form/more.png)
![more](images/e2e/form/more.png)
![more-open](/docs/zh/test/images/e2e/form/more-open.png)
![more-open](images/e2e/form/more-open.png)
- `formTransfer`
- 对穿梭框类型的表单操作
@ -472,7 +472,7 @@
});
```
![transfer-left](/docs/zh/test/images/e2e/form/transfer-left.png)
![transfer-left](images/e2e/form/transfer-left.png)
- `formTransferRight`
- 对右侧的穿梭框基于搜索展示指定待选条目
@ -494,7 +494,7 @@
});
```
![transfer-right](/docs/zh/test/images/e2e/form/transfer-right.png)
![transfer-right](images/e2e/form/transfer-right.png)
- `formTabClick`
- 点击带有 Tab 的表单项中的 Tab
@ -514,7 +514,7 @@
});
```
![tab](/docs/zh/test/images/e2e/form/tab.png)
![tab](images/e2e/form/tab.png)
- `formInputKeyValue`
- 对`KeyValue`组件的表单项进行输入操作,一般是配合`formAddSelectAdd`使用,对添加的新的`KeyValue`组件的条目,输入内容
@ -535,7 +535,7 @@
});
```
![key-value](/docs/zh/test/images/e2e/form/key-value.png)
![key-value](images/e2e/form/key-value.png)
- `formTransferLeftCheck`
- 对左侧的穿梭框的操作
@ -557,7 +557,7 @@
});
```
![transfer-left-click](/docs/zh/test/images/e2e/form/transfer-left-click.png)
![transfer-left-click](images/e2e/form/transfer-left-click.png)
- `formTransferRightCheck`
- 对右侧的穿梭框的操作
@ -586,6 +586,6 @@
});
```
![transfer-right-check](/docs/zh/test/images/e2e/form/transfer-right-check.png)
![transfer-right-check](images/e2e/form/transfer-right-check.png)
对资源操作的各种操作,主要用到了上方介绍的函数,函数的具体编写,请查看`test/e2e/support/form-commands.js`

View File

@ -10,7 +10,7 @@
- 等待列表加载完成
- 列表在加载过程中,会有`loading`状态展示,等待该状态结束
![wait-table-loading](/docs/zh/test/images/e2e/table/wait-table-loading.png)
![wait-table-loading](images/e2e/table/wait-table-loading.png)
- `checkTableFirstRow`
- 验证表格第一行是否包含指定内容,一般用于创建后验证创建资源是否存在
@ -28,7 +28,7 @@
});
```
![check-first-row](/docs/zh/test/images/e2e/table/check-first-row.png)
![check-first-row](images/e2e/table/check-first-row.png)
- `tableSearchText`
- 在表格上方的搜索栏中输入内容,并等待搜索完成
@ -50,7 +50,7 @@
});
```
![search](/docs/zh/test/images/e2e/table/search.png)
![search](images/e2e/table/search.png)
- `tableSimpleSearchText`
- 在表格上方的搜索栏中输入内容,并等待搜索完成
@ -65,7 +65,7 @@
});
```
![simple-search](/docs/zh/test/images/e2e/table/simple-search.png)
![simple-search](images/e2e/table/simple-search.png)
- `tableSearchSelect`
- 使用表格上方的搜索栏中的选择项进行搜索,并等待搜索完成
@ -92,11 +92,11 @@
});
```
![search-select-1](/docs/zh/test/images/e2e/table/search-select-1.png)
![search-select-1](images/e2e/table/search-select-1.png)
![search-select-2](/docs/zh/test/images/e2e/table/search-select-2.png)
![search-select-2](images/e2e/table/search-select-2.png)
![search-select-3](/docs/zh/test/images/e2e/table/search-select-3.png)
![search-select-3](images/e2e/table/search-select-3.png)
- `tableSearchSelectText`
- 使用表格上方的搜索栏进行搜索,并等待搜索完成
@ -132,11 +132,11 @@
});
```
![search-text-1](/docs/zh/test/images/e2e/table/search-text-1.png)
![search-text-1](images/e2e/table/search-text-1.png)
![search-text-2](/docs/zh/test/images/e2e/table/search-text-2.png)
![search-text-2](images/e2e/table/search-text-2.png)
![search-text-3](/docs/zh/test/images/e2e/table/search-text-3.png)
![search-text-3](images/e2e/table/search-text-3.png)
- `checkEmptyTable`
- 验证表格为空表格
@ -175,9 +175,9 @@
});
```
![detail-1](/docs/zh/test/images/e2e/table/detail-1.png)
![detail-1](images/e2e/table/detail-1.png)
![detail-2](/docs/zh/test/images/e2e/table/detail-2.png)
![detail-2](images/e2e/table/detail-2.png)
- `checkColumnValue`
- 验证第一行指定列的内容是否符合预期
@ -202,7 +202,7 @@
});
```
![check-value](/docs/zh/test/images/e2e/table/check-value.png)
![check-value](images/e2e/table/check-value.png)
- `selectFirst`
- 选中表格中第一行,以便做后续的批量操作
@ -227,7 +227,7 @@
});
```
![select-first](/docs/zh/test/images/e2e/table/select-first.png)
![select-first](images/e2e/table/select-first.png)
- `selectAll`
- 选中表格中所有条目,以便做后续的批量操作
@ -258,14 +258,14 @@
});
```
![wait-1](/docs/zh/test/images/e2e/table/wait-1.png)
![wait-1](images/e2e/table/wait-1.png)
![wait-2](/docs/zh/test/images/e2e/table/wait-2.png)
![wait-2](images/e2e/table/wait-2.png)
## 对按钮的操作
主要包含
- 位于表单上的主按钮操作(一般创建操作)、批量操作
- 位于表单上的主按钮操作(一般创建操作)、批量操作
- 位于表单每一行的行操作
### 表单上方按钮的操作
@ -286,7 +286,7 @@
});
```
![header-btn-index](/docs/zh/test/images/e2e/table/header-btn-index.png)
![header-btn-index](images/e2e/table/header-btn-index.png)
- `clickHeaderButtonByTitle`
- 通过名称点击表格上方的按钮,一般用于批量操作按钮的点击
@ -308,7 +308,7 @@
});
```
![header-btn-title](/docs/zh/test/images/e2e/table/header-btn-title.png)
![header-btn-title](images/e2e/table/header-btn-title.png)
- `clickHeaderConfirmButtonByTitle`
- 该函数会完成
@ -327,8 +327,7 @@
});
```
![header-confirm-title](/docs/zh/test/images/e2e/table/header-confirm-title.png)
![header-confirm-title](images/e2e/table/header-confirm-title.png)
### 表单第一行的行操作
- `clickFirstActionButton`
@ -345,7 +344,7 @@
});
```
![click-first](/docs/zh/test/images/e2e/table/click-first.png)
![click-first](images/e2e/table/click-first.png)
- `clickActionButtonByTitle`
- 根据标题点击第一行中的操作
@ -370,9 +369,9 @@
});
```
![action-by-title](/docs/zh/test/images/e2e/table/action-by-title.png)
![action-by-title](images/e2e/table/action-by-title.png)
![action-by-title-2](/docs/zh/test/images/e2e/table/action-by-title-2.png)
![action-by-title-2](images/e2e/table/action-by-title-2.png)
- `clickActionInMore`
- 根据标题点击第一行中`更多`中的操作
@ -387,7 +386,7 @@
});
```
![action-in-more](/docs/zh/test/images/e2e/table/action-in-more.png)
![action-in-more](images/e2e/table/action-in-more.png)
- `clickActionInMoreSub`
- 根据标题点击第一行操作的子菜单下的操作
@ -405,7 +404,7 @@
});
```
![action-in-sub](/docs/zh/test/images/e2e/table/action-in-sub.png)
![action-in-sub](images/e2e/table/action-in-sub.png)
- `checkActionDisabledInFirstRow`
- 验证指定名称的资源的指定操作不可用
@ -424,14 +423,14 @@
});
```
![disable-more-action](/docs/zh/test/images/e2e/table/disable-more-action.png)
![disable-more-action](images/e2e/table/disable-more-action.png)
- `clickFirstActionDisabled`
- 验证表格中第一行的操作中的第一个操作不可用
- 资源处于某些状态后,某些操作是需要被禁用的,行操作列表中的第一个操作,如果不可操作,则处于`禁用`状态,而`更多`中的操作,如果不可用,则不展示
- 以云主机组`test/e2e/integration/pages/compute/server-group.spec.js`为例
1. 在云主机组下创建云主机
2. 验证含有云主机的云主机不可删除
2. 验证含有云主机的云主机不可删除
3. 删除云主机后,云主机组删除成功
```javascript
@ -446,7 +445,7 @@
});
```
![disable-first](/docs/zh/test/images/e2e/table/disable-first.png)
![disable-first](images/e2e/table/disable-first.png)
- `clickConfirmActionInFirst`
- 完成表格中第一行的第一个操作按钮对应的操作
@ -455,7 +454,7 @@
- 参数`waitTime`,关闭操作成功提示后的等待时间
- 以云主机组`test/e2e/integration/pages/compute/server-group.spec.js`为例
1. 在云主机组下创建云主机
2. 验证含有云主机的云主机不可删除
2. 验证含有云主机的云主机不可删除
3. 删除云主机后,云主机组删除成功
```javascript
@ -470,9 +469,9 @@
});
```
![first-confirm](/docs/zh/test/images/e2e/table/first-confirm.png)
![first-confirm](images/e2e/table/first-confirm.png)
![first-confirm-2](/docs/zh/test/images/e2e/table/first-confirm-2.png)
![first-confirm-2](images/e2e/table/first-confirm-2.png)
- `clickConfirmActionButton`
- 完成表格中第一行的列出的操作按钮中对应的操作
@ -490,7 +489,7 @@
});
```
![confirm-action](/docs/zh/test/images/e2e/table/confirm-action.png)
![confirm-action](images/e2e/table/confirm-action.png)
- `clickConfirmActionInMore`
- 完成表格中第一行的`更多`中对应的操作
@ -513,9 +512,9 @@
});
```
![confirm-more-1](/docs/zh/test/images/e2e/table/confirm-more-1.png)
![confirm-more-1](images/e2e/table/confirm-more-1.png)
![confirm-more-2](/docs/zh/test/images/e2e/table/confirm-more-2.png)
![confirm-more-2](images/e2e/table/confirm-more-2.png)
- `clickConfirmActionInMoreSub`
- 完成表格中第一行的`更多`中指定子菜单下对应的操作
@ -542,7 +541,6 @@
});
```
![confirm-in-sub](/docs/zh/test/images/e2e/table/confirm-in-sub.png)
![confirm-in-sub](images/e2e/table/confirm-in-sub.png)
对表格操作的各种操作,主要用到了上方介绍的函数,函数的具体编写,请查看`test/e2e/support/table-commands.js`

View File

@ -17,7 +17,7 @@
});
```
![name](/docs/zh/test/images/e2e/detail/name.png)
![name](images/e2e/detail/name.png)
- `goBackToList`
- 点击详情页的`返回`按钮,进入列表页,并等待列表加载完成
@ -40,7 +40,7 @@
});
```
![list](/docs/zh/test/images/e2e/detail/list.png)
![list](images/e2e/detail/list.png)
- `goBackToList`
- 点击详情页的`返回`按钮,进入列表页,并等待列表加载完成
@ -63,7 +63,7 @@
});
```
![list](/docs/zh/test/images/e2e/detail/list.png)
![list](images/e2e/detail/list.png)
- `clickDetailTab`
- 点击详情页下方的指定Tab标签并等待相关资源列表加载完成
@ -91,6 +91,6 @@
});
```
![tab](/docs/zh/test/images/e2e/detail/tab.png)
![tab](images/e2e/detail/tab.png)
对详情页主要用到了上方介绍的函数,函数的具体编写,请查看`test/e2e/support/detail-commands.js`