前端自动化测试框架Cypress之基础知识

一、Cypress目录及环境搭建

(一)、安装Cypress

  • 在线安装使用npm
    npm install cypress --save-dev
  • 离线安装
    第一步,官网上下载cpress.zip压缩包 ☟点击下载
    第二步,配置系统环境变量
    CYPRESS_INSTALL_BINARY 下载并安装的Cypress二进制文件的目标位置
    第三步,执行安装命令
    CYPRESS_INSTALL_BINARY=2.0.1 npm install [email protected]
    ☞官网api

(二)、目录结构

在这里插入图片描述

  • support文件夹中存,指定集合
/**
 - 编写人:
 - 日期:
 - 目的:登录
 - 参数说明:
 */
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()
})
  • specs目录中存放测试案例
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]')
  })
})

二、运行案例测试

  • 配置指令
    "test:e2e-gui": "vue-cli-service test:e2e --mode development"
  • 页面操作
    在这里插入图片描述
    点击需要测试文件如下
    在这里插入图片描述

三、Cypress闭包环境变量

1. describe

describe(’’, () => {
// 各种钩子函数
before(() => {
// 在全部案例执行之前执行一次
})
after(() => {
// 在全部案例执行完成之后执行一次
})
beforeEach(() => {
// 在每一条案例之前执行
})
afterEach(() => {
// 在每一条案例执行完成之后执行
})
it(‘测试表单验证案例’, () => {})
// 只执行该案例
it.only(‘测试表单验证案例’, () => {})
// 忽略该案例
it.skip(‘测试表单验证案例’, () => {})
})

2. 钩子函数里环境变量

  1. 可以访问cy对象
    传入selector选择器,本质是由jquery选择器实现,故用法一致
    const $cyElement = cy.get('.demo-ruleForm > .el-form-item:first-child input')
    
  2. 类似jquery可以链式调用
    样式选择器连接如是
cy.get('.demo-ruleForm > .el-form-item:first-child input')
     .should('have.value', '')
     .focus()
     .blur()
  1. js基本变量语法
    js基本语法api都支持,但稍有不同
 const arr = [];
 arr.forEach 可以访问
 [].forEach 不可以访问
  1. expect asset断言
assert.isOk('everything', 'everything is ok')
expect('Jane').to.not.equal('Jane')
  1. Cypress对象
    Cypress提供了cy的一切api,另外多了.$()方法用于返回jquery对象
    便于操作dom

3. should里环境变量

可以访问Cypress对象
js基本变量语法

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.$()返回jQuery对象,可以访问jquery 的api
  • Cypress.dom 返回dom的api
  • Cpress.cy返回cy实例,可以类似钩子函数里断言

4. 案例

代码如下:

// 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
    })
  })
})

四、获取dom元素

1.get

用法一、选择器定位

cy.get(selector)

用法二、以别名定位

cy.get(alias)

匹配多个元素时,返回多个对象

2.find

cy.get(selector).find(selector1)

定位方法,用来在 DOM 树中搜索已被定位到的元素的后代,例如get选中的后代元素

// 错误写法
cy.find(selector)

会报错,需要一个父类选中元素
在这里插入图片描述

3.contains

两种用法,如下:

.contains(content)
.contains(selector, content)

支持cy.contains,及cy.get().contains
重点:只会返回第一个匹配到的元素

4.first

类似jquery的first方法

5.eq

类似jquery的eq方法,eq(index) index从0开始获取第几个元素子元素

五、获取/设置dom元素属性 !!!

1. cy.$$(selector,context) ☆☆☆

cy.$$('input') // 返回input元素的jquery对象
cy.$$('input').value() // 可用用jquery的api
cy.$$('input').text() // 例子,等等

cy对象挂载在window下,故环境变量this指向window时可用访问,一般顶级作用域指向这个window,可用通过箭头函数将内部作用域指向window,访问cy

2. Cypress.$(selector) ☆☆☆

Cypress.$('input') // 返回input元素的jquery对象
Cypress.$('input').value() // 可用用jquery的api
Cypress.$('input').text() // 例子,等等

Cypress对象挂载在window下,故环境变量this指向window时可用访问,一般顶级作用域指向这个window,可用通过箭头函数将内部作用域指向window,访问Cypresss

3.should回调函数 ☆☆☆

  • 形参$e为jquery对象
  • Cpress.$ 返回jquery对象

利用jquery的api可以获取元素的dom属性

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.cy对象的type方法

对input输入框的输入

cy.get('input').type('text')
cy.get('input').type('2222')

六、鼠标事件

1.单击事件click

// 点击事件
cy.get('#btn').click()

2.悬浮事件hover

版本不支持该事件,有代替方案如下:

cy.get('#btn')
  .trigger('mouserover')
  .wait(3000)
  .rightclick()
  .wait(3000)
  .should('have.css', 'color', 'rgb(255, 255, 255)')

3.双加事件dblclick

// 双击事件
cy.get('#btn').dblclick()

4.右击事件rightclick

// 右击事件
cy.get('#btn').rightclick()

5.聚焦事件focus

// 聚焦事件
cy.get('input').focus()

6.失焦事件blur

// 失焦事件
cy.get('input').blur()

总结案例

// 案例三、测试鼠标一些事件
  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()
  })

七、断言should、expect

每条案例都需要加断言,及验证点,否则是一条不完整的案例

(一)、should断言

1. dom断言

  1. Length
// retry until we find 3 matching <li.selected>
cy.get('li.selected').should('have.length', 3)
  1. Class
// retry until this input does not have class disabled
cy.get('form').find('input').should('not.have.class', 'disabled')
  1. Value
// retry until this textarea has the correct value
cy.get('textarea').should('have.value', 'foo bar baz')
  1. Text Content
// retry until this span does not contain 'click me'
cy.get('a').parent('span.help').should('not.contain', 'click me')
  1. Visibility
// retry until this button is visible
cy.get('button').should('be.visible')
  1. Existence
// retry until loading spinner no longer exists
cy.get('#loading').should('not.exist')
  1. State
// retry until our radio is checked
cy.get(':radio').should('be.checked')
  1. 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. 回调函数

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-/)
  })

(二)、expect断言

1. 断言入参不是dom对象时

Chainer 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’)

八、项目常见报错解决方案

后续持续更新。。。

猜你喜欢

转载自blog.csdn.net/qq_29510269/article/details/107447705