Basic knowledge of front-end automated testing framework Cypress
1. Cypress directory and environment construction
(1) Install Cypress
- Online installation using npm
npm install cypress --save-dev
- Offline installation
Step 1: Download the cpress.zip compressed package from the official website☟Click to download
Step 2: Configure system environment variables
CYPRESS_INSTALL_BINARY 下载并安装的Cypress二进制文件的目标位置
Step 3: Execute the installation command☞Official
CYPRESS_INSTALL_BINARY=2.0.1 npm install [email protected]
website api
(2) Directory structure
- Save in support folder, specify collection
/**
- 编写人:
- 日期:
- 目的:登录
- 参数说明:
*/
Cypress.Commands.add("login", (userName, password) => {
cy.visit('/#/login-page')
cy.get("#app > div input").type(userName)
cy.get("#secpwd").type(password)
cy.get("#app > button").click()
})
- Store test cases in the specs directory
describe('My First Test', function() {
before(() => {
// 在全部案例执行之前执行一次
// 浏览器模式访问时,可按照自己的需要设置窗口大小,如 cy.viewport(1920,1100)
// 访问首页
cy.visit('http://localhost:2000/#/input-demo')
})
after(() => {
// 在全部案例执行完成之后执行一次
})
beforeEach(() => {
// 在每一条案例之前执行
})
afterEach(() => {
// 在每一条案例执行完成之后执行
})
it('Does not do much!', function() {
expect(true).to.equal(false)
})
it('Gets, types and asserts', function() {
cy.visit('https://example.cypress.io')
cy.contains('type').click()
// 应该存在一个包含'/commands/actions'的新URL
cy.url().should('include', '/commands/actions')
// 获取一个输入, 输入进去并且验证文本值已经更新了
cy.get('.action-email')
.type('[email protected]')
.should('have.value', '[email protected]')
})
})
2. Run the case test
- Configuration instructions
"test:e2e-gui": "vue-cli-service test:e2e --mode development"
- Page operation
click on the required test file as follows
3. Cypress closure environment variables
1. describe
describe('', () => { // Various hook functions before(() => { // Executed once before all cases are executed }) after(() => { // Executed after all cases are executed. Once }) beforeEach(() => { // Executed before each case }) afterEach(() => { // Executed after each case is executed }) it('Test form validation case', () => {}) // Only execute this case it.only('Test form validation case', () => {}) // Ignore this case it.skip('Test form validation case', () => { }) })
2. Environment variables in hook functions
- You can access the cy object
and pass in the selector, which is essentially implemented by the jquery selector, so the usage is consistent.const $cyElement = cy.get('.demo-ruleForm > .el-form-item:first-child input')
- Similar to jquery, you can chain call
the style selector connection like this
cy.get('.demo-ruleForm > .el-form-item:first-child input')
.should('have.value', '')
.focus()
.blur()
- js basic variable syntax
js basic syntax api supports both, but is slightly different
const arr = [];
arr.forEach 可以访问
[].forEach 不可以访问
- expect asset assertion
assert.isOk('everything', 'everything is ok')
expect('Jane').to.not.equal('Jane')
- Cypress object
Cypress provides all APIs of cy, in addition, there is an additional .$() method for returning jquery objects, which
is convenient for operating dom
3. Environment variables in should
Can access Cypress object
js basic variable syntax
const $cyElement = cy.get('.demo-ruleForm > .el-form-item:first-child input')
$cyElement.should($el => {
// 闭包环境里可以访问Cypress是个可以操作dom集合
// Cypress.dom 返回dom的api
// Cypress.$(dom) 返回jquery对象
const isDom = Cypress.dom.isDom($el)
const $jqEl = Cypress.$($el[0])
expect(isDom).to.be.true
})
- Cypress.$() returns a jQuery object and can access jquery’s api
- Cypress.dom returns the dom API
- Cpress.cy returns the cy instance, which can be asserted similarly to the hook function
4. Case
code show as below:
// https://docs.cypress.io/api/introduction/api.html
describe('自动化测试表单验证案例', () => {
before(() => {
// 在全部案例执行之前执行一次
// 浏览器模式访问时,可按照自己的需要设置窗口大小,如 cy.viewport(1920,1100)
// 访问首页
cy.visit('http://localhost:2000/#/input-demo')
})
after(() => {
// 在全部案例执行完成之后执行一次
})
beforeEach(() => {
// 在每一条案例之前执行
})
afterEach(() => {
// 在每一条案例执行完成之后执行
})
// 案例一、测试表单验证案例
it('测试表单验证案例', () => {
cy.get('.demo-ruleForm > .el-form-item:first-child input')
.should('have.value', '')
.focus()
.blur()
cy.get('.demo-ruleForm .el-form-item__error')
.should('contain', '请输入活动名称')
cy.get('.demo-ruleForm > .el-form-item:first-child input').type('测试数据')
.blur()
cy.get('.demo-ruleForm .el-form-item__error')
.should('not.be.visible')
cy.get('.demo-ruleForm > .el-form-item:first-child input').type('测试数据测试数据')
.blur()
cy.get('.demo-ruleForm .el-form-item__error')
.should('contain', '长度在 3 到 5 个字符')
})
// 案例二、测试一些闭包环境变量及api
it('测试表单验证案例', () => {
// This is fine, jQuery returns the element synchronously.
// const $jqElement = $('.demo-ruleForm > .el-form-item:first-child input')
// This will not work! Cypress does not return the element synchronously.
const $cyElement = cy.get('.demo-ruleForm > .el-form-item:first-child input')
// cy操作类型jquery传入selector选择器,但不可以直接操作dom
// 类似jquery可以链式调用
// js基本变量语法
// 但稍有不同
const arr = [];
// arr.forEach 可以访问
// [].forEach 不可以访问
$cyElement.should($el => {
// 闭包环境里可以访问Cypress是个可以操作dom集合
// Cypress.dom 返回dom的api
// Cypress.$(dom) 返回jquery对象
const isDom = Cypress.dom.isDom($el)
const $jqEl = Cypress.$($el[0])
expect(isDom).to.be.true
})
})
})
4. Get dom elements
1.get
Usage 1. Selector positioning
cy.get(selector)
Usage 2. Positioning by alias
cy.get(alias)
When matching multiple elements, multiple objects are returned
2.find
cy.get(selector).find(selector1)
Positioning method, used to search the descendants of the positioned element in the DOM tree, such as get the selected descendant element
// 错误写法
cy.find(selector)
An error will be reported and a parent class is required to select the element.
3.contains
Two usages are as follows:
.contains(content)
.contains(selector, content)
Support cy.contains, and cy.get().contains
重点:只会返回第一个匹配到的元素
4.first
Similar to jquery’s first method
5.eq
Similar to jquery's eq method, eq(index) index starts from 0 to get the first element and child element.
5. Get/set DOM element attributes! ! !
1. cy.$$(selector,context) ☆☆☆
cy.$$('input') // 返回input元素的jquery对象
cy.$$('input').value() // 可用用jquery的api
cy.$$('input').text() // 例子,等等
The cy object is mounted under the window, so it can be accessed when the environment variable this points to the window. Generally, the top-level scope points to this window. You can use the arrow function to point the internal scope to the window to access cy.
2. Cypress.$(selector) ☆☆☆
Cypress.$('input') // 返回input元素的jquery对象
Cypress.$('input').value() // 可用用jquery的api
Cypress.$('input').text() // 例子,等等
The Cypress object is mounted under the window, so it can be accessed when the environment variable this points to the window. Generally, the top-level scope points to this window. You can use the arrow function to point the internal scope to the window to access Cypresss.
3.should callback function☆☆☆
- The formal parameter $e is a jquery object
- Cpress.$ returns jquery object
Use jquery's api to get the dom attribute of the element
cy.get('.dom-demo')
.should($e => {
// $e jquery对象
// Cpress.$ 返回jquery对象
const text = $e.find('.item').first().text();
const text1 = Cypress.$($e[0]).find('.item').first().text();
console.log(text === text1) // true
})
4.Type method of cy object
Input to input box
cy.get('input').type('text')
cy.get('input').type('2222')
6. Mouse events
1. Click event click
// 点击事件
cy.get('#btn').click()
2.Hover event hover
The version does not support this event. There are alternatives as follows:
cy.get('#btn')
.trigger('mouserover')
.wait(3000)
.rightclick()
.wait(3000)
.should('have.css', 'color', 'rgb(255, 255, 255)')
3. Double addition event dblclick
// 双击事件
cy.get('#btn').dblclick()
4. Right click event rightclick
// 右击事件
cy.get('#btn').rightclick()
5. Focus event focus
// 聚焦事件
cy.get('input').focus()
6. Out-of-focus event blur
// 失焦事件
cy.get('input').blur()
Summary case
// 案例三、测试鼠标一些事件
it('测试鼠标一些事件', () => {
// 点击事件
cy.get('#btn')
.click()
// 双击事件
cy.get('#btn')
.dblclick()
// 右击事件
cy.get('#btn')
.rightclick()
// 悬浮事件
// cy.get('#btn').hover()
// 该事件本版本不支持
// 代替方案如下:
cy.get('#btn')
.trigger('mouserover')
.wait(3000)
.rightclick()
.wait(3000)
.should('have.css', 'color', 'rgb(255, 255, 255)')
// 聚焦事件
cy.get('#int')
.focus()
// 失焦事件
cy.get('#int')
.blur()
})
7. Assert should, expect
每条案例都需要加断言,及验证点,否则是一条不完整的案例
(1), should assertion
1. dom assertion
- Length
// retry until we find 3 matching <li.selected>
cy.get('li.selected').should('have.length', 3)
- Class
// retry until this input does not have class disabled
cy.get('form').find('input').should('not.have.class', 'disabled')
- Value
// retry until this textarea has the correct value
cy.get('textarea').should('have.value', 'foo bar baz')
- Text Content
// retry until this span does not contain 'click me'
cy.get('a').parent('span.help').should('not.contain', 'click me')
- Visibility
// retry until this button is visible
cy.get('button').should('be.visible')
- Existence
// retry until loading spinner no longer exists
cy.get('#loading').should('not.exist')
- State
// retry until our radio is checked
cy.get(':radio').should('be.checked')
- CSS
// retry until .completed has matching css
cy.get('.completed').should('have.css', 'text-decoration', 'line-through')
// retry until .accordion css have display: none
cy.get('#accordion').should('not.have.css', 'display', 'none')
2. Callback function
cy.get('div')
.should(($div) => {
expect($div).to.have.length(1)
const className = $div[0].className
// className will be a string like "main-abc123 heading-xyz987"
expect(className).to.match(/heading-/)
})
(2), expect affirmation
1. When asserting that the input parameter is not a DOM object
Chain | Example |
---|---|
not | expect(name).to.not.equal(‘Jane’) |
deep | expect(obj).to.deep.equal({ name: ‘Jane’ }) |
nested | expect({a: {b: [‘x’, ‘y’]}}).to.have.nested.property(‘a.b[1]’) expect({a: {b: [‘x’, ‘y’]}}).to.nested.include({‘a.b[1]’: ‘y’}) |
ordered | expect([1, 2]).to.have.ordered.members([1, 2]).but.not.have.ordered.members([2, 1]) |
any | expect(arr).to.have.any.keys(‘age’) |
all | expect(arr).to.have.all.keys(‘name’, ‘age’) |
a(type) Aliases: an | expect(‘test’).to.be.a(‘string’) |
include(value) Aliases: contain, includes, contains | expect([1,2,3]).to.include(2) |
ok | expect(undefined).to.not.be.ok |
true | expect(true).to.be.true |
false | expect(false).to.be.false |
null | expect(null).to.be.null |
undefined | expect(undefined).to.be.undefined |
exist | expect(myVar).to.exist |
empty | expect([]).to.be.empty |
arguments Aliases: Arguments | expect(arguments).to.be.arguments |
equal(value) Aliases: equals, eq | expect(42).to.equal(42) |
deep.equal(value) | expect({ name: ‘Jane’ }).to.deep.equal({ name: ‘Jane’ }) |
eql(value) Aliases: eqls | expect({ name: ‘Jane’ }).to.eql({ name: ‘Jane’ }) |
greaterThan(value) Aliases: gt, above | expect(10).to.be.greaterThan(5) |
least(value)Aliases: gte | expect(10).to.be.at.least(10) |
lessThan(value) Aliases: lt, below | expect(5).to.be.lessThan(10) |
most(value) Aliases: lte | expect(‘test’).to.have.length.of.at.most(4) |
within(start, finish) | expect(7).to.be.within(5,10) |
instanceOf(constructor) Aliases: instanceof | expect([1, 2, 3]).to.be.instanceOf(Array) |
property(name, [value]) | expect(obj).to.have.property(‘name’) |
deep.property(name, [value]) | expect(deepObj).to.have.deep.property(‘tests[1]’, ‘e2e’) |
ownProperty(name) Aliases: haveOwnProperty, own.property | expect(‘test’).to.have.ownProperty(‘length’) |
ownPropertyDescriptor(name) Aliases: haveOwnPropertyDescriptor | expect({a: 1}).to.have.ownPropertyDescriptor(‘a’) |
lengthOf(value) | expect(‘test’).to.have.lengthOf(3) |
match(RegExp) Aliases: matches | expect(‘testing’).to.match(/^test/) |
string(string) | expect(‘testing’).to.have.string(‘test’) |
keys(key1, [key2], […]) Aliases: key | expect({ pass: 1, fail: 2 }).to.have.keys(‘pass’, ‘fail’) |
throw(constructor) Aliases: throws, Throw | expect(fn).to.throw(Error) |
respondTo(method) Aliases: respondsTo | expect(obj).to.respondTo(‘getName’) |
itself | expect(Foo).itself.to.respondTo(‘bar’) |
satisfy(method) Aliases: satisfies | expect(1).to.satisfy((num) => { return num > 0 }) |
closeTo(expected, delta) Aliases: approximately | expect(1.5).to.be.closeTo(1, 0.5) |
members(set) | expect([1, 2, 3]).to.include.members([3, 2]) |
oneOf(values) | expect(2).to.be.oneOf([1,2,3]) |
change(function) Aliases: changes | expect(fn).to.change(obj, ‘val’) |
increase(function) Aliases: increases | expect(fn).to.increase(obj, ‘val’) |
decrease(function) Aliases: decreases | expect(fn).to.decrease(obj, ‘val’) |
2. 断言入参是dom对象时
Chainers | Assertion |
---|---|
attr(name, [value]) | expect($el).to.have.attr(‘foo’, ‘bar’) |
prop(name, [value]) | expect($el).to.have.prop(‘disabled’, false) |
css(name, [value]) | expect($el).to.have.css(‘background-color’, ‘rgb(0, 0, 0)’) |
data(name, [value]) | expect($el).to.have.data(‘foo’, ‘bar’) |
class(className) | expect($el).to.have.class(‘foo’) |
id(id) | expect($el).to.have.id(‘foo’) |
html(html) | expect($el).to.have.html(‘I love testing’) |
text(text) | expect($el).to.have.text(‘I love testing’) |
value(value) | expect($el).to.have.value(‘[email protected]’) |
visible | expect($el).to.be.visible |
hidden | expect($el).to.be.hidden |
selected | expect($option).not.to.be.selected |
checked | expect($input).not.to.be.checked |
focus[ed] | expect($input).not.to.be.focused expect($input).to.have.focus |
enabled | expect($input).to.be.enabled |
disabled | expect($input).to.be.disabled |
empty | expect($el).not.to.be.empty |
exist | expect($nonexistent).not.to.exist |
match(selector) | expect($emptyEl).to.match(’:empty’) |
contain(text) | expect($el).to.contain(‘text’) |
descendants(selector) | expect($el).to.have.descendants(‘div’) |
3.断言对象是 cy.stub() 或 cy.spy()时
Sinon.JS property/method | Assertion |
---|---|
called | expect(spy).to.be.called |
callCount | expect(spy).to.have.callCount(n) |
calledOnce | expect(spy).to.be.calledOnce |
calledTwice | expect(spy).to.be.calledTwice |
calledThrice | expect(spy).to.be.calledThrice |
calledBefore | expect(spy1).to.be.calledBefore(spy2) |
calledAfter | expect(spy1).to.be.calledAfter(spy2) |
calledWithNew | expect(spy).to.be.calledWithNew |
alwaysCalledWithNew | expect(spy).to.always.be.calledWithNew |
calledOn | expect(spy).to.be.calledOn(context) |
alwaysCalledOn | expect(spy).to.always.be.calledOn(context) |
calledWith | expect(spy).to.be.calledWith(…args) |
alwaysCalledWith | expect(spy).to.always.be.calledWith(…args) |
calledWithExactly | expect(spy).to.be.calledWithExactly(…args) |
alwaysCalledWithExactly | expect(spy).to.always.be.calledWithExactly(…args) |
calledWithMatch | expect(spy).to.be.calledWithMatch(…args) |
alwaysCalledWithMatch | expect(spy).to.always.be.calledWithMatch(…args) |
returned | expect(spy).to.have.returned(returnVal) |
alwaysReturned | expect(spy).to.have.always.returned(returnVal) |
threw | expect(spy).to.have.thrown(errorObjOrErrorTypeStringOrNothing) |
alwaysThrew | expect(spy).to.have.always.thrown(errorObjOrErrorTypeStringOrNothing) |
(三)、assert断言
Assertion | Example |
---|---|
.isOk(object, [message]) | assert.isOk(‘everything’, ‘everything is ok’) |
.isNotOk(object, [message]) | assert.isNotOk(false, ‘this will pass’) |
.equal(actual, expected, [message]) | assert.equal(3, 3, ‘vals equal’) |
.notEqual(actual, expected, [message]) | assert.notEqual(3, 4, ‘vals not equal’) |
.strictEqual(actual, expected, [message]) | assert.strictEqual(true, true, ‘bools strict eq’) |
.notStrictEqual(actual, expected, [message]) | assert.notStrictEqual(5, ‘5’, ‘not strict eq’) |
.deepEqual(actual, expected, [message]) | assert.deepEqual({ id: ‘1’ }, { id: ‘1’ }) |
.notDeepEqual(actual, expected, [message]) | assert.notDeepEqual({ id: ‘1’ }, { id: ‘2’ }) |
.isAbove(valueToCheck, valueToBeAbove, [message]) | assert.isAbove(6, 1, ‘6 greater than 1’) |
.isAtLeast(valueToCheck, valueToBeAtLeast, [message]) | assert.isAtLeast(5, 2, ‘5 gt or eq to 2’) |
.isBelow(valueToCheck, valueToBeBelow, [message]) | assert.isBelow(3, 6, ‘3 strict lt 6’) |
.isAtMost(valueToCheck, valueToBeAtMost, [message]) | assert.isAtMost(4, 4, ‘4 lt or eq to 4’) |
.isTrue(value, [message]) | assert.isTrue(true, ‘this val is true’) |
.isNotTrue(value, [message]) | assert.isNotTrue(‘tests are no fun’, ‘val not true’) |
.isFalse(value, [message]) | assert.isFalse(false, ‘val is false’) |
.isNotFalse(value, [message]) | assert.isNotFalse(‘tests are fun’, ‘val not false’) |
.isNull(value, [message]) | assert.isNull(err, ‘there was no error’) |
.isNotNull(value, [message]) | assert.isNotNull(‘hello’, ‘is not null’) |
.isNaN(value, [message]) | assert.isNaN(NaN, ‘NaN is NaN’) |
.isNotNaN(value, [message]) | assert.isNotNaN(5, ‘5 is not NaN’) |
.exists(value, [message]) | assert.exists(5, ‘5 is not null or undefined’) |
.notExists(value, [message]) | assert.notExists(null, ‘val is null or undefined’) |
.isUndefined(value, [message]) | assert.isUndefined(undefined, ‘val is undefined’) |
.isDefined(value, [message]) | assert.isDefined(‘hello’, ‘val has been defined’) |
.isFunction(value, [message]) | assert.isFunction(x => x * x, ‘val is func’) |
.isNotFunction(value, [message]) | assert.isNotFunction(5, ‘val not funct’) |
.isObject(value, [message]) | assert.isObject({num: 5}, ‘val is object’) |
.isNotObject(value, [message]) | assert.isNotObject(3, ‘val not object’) |
.isArray(value, [message]) | assert.isArray([‘unit’, ‘e2e’], ‘val is array’) |
.isNotArray(value, [message]) | assert.isNotArray(‘e2e’, ‘val not array’) |
.isString(value, [message]) | assert.isString(‘e2e’, ‘val is string’) |
.isNotString(value, [message]) | assert.isNotString(2, ‘val not string’) |
.isNumber(value, [message]) | assert.isNumber(2, ‘val is number’) |
.isNotNumber(value, [message]) | assert.isNotNumber(‘e2e’, ‘val not number’) |
.isFinite(value, [message]) | assert.isFinite(‘e2e’, ‘val is finite’) |
.isBoolean(value, [message]) | assert.isBoolean(true, ‘val is bool’) |
.isNotBoolean(value, [message]) | assert.isNotBoolean(‘true’, ‘val not bool’) |
.typeOf(value, name, [message]) | assert.typeOf(‘e2e’, ‘string’, ‘val is string’) |
.notTypeOf(value, name, [message]) | assert.notTypeOf(‘e2e’, ‘number’, ‘val not number’) |
8. Solutions to common project errors
Will continue to update. . .