Cypress

Cypress用法简介

介绍了Cypress的基本用法(Cypress一个基于js的自动化框架),注意:与jQuery一起食用更佳

本文参考资料

悠悠cypress博客cypress actioncypress assertcypress connectcypress cookies

Cypress一个简单的范本

cy
  // 找到一个id为 'some-link'元素
  .get('#some-link')
  .then(($myElement) => {
    // ...模拟任意操作对象的一段代码
    // 获取它的 href 属性
    const href = $myElement.prop('href')

    // 替换'hash'字符和它之后的一切
    return href.replace(/(#.*)/, '')
  })
  .then((href) => {
    // href 是现在的新操作对象
    // 现在我们可以干我们想干的
  })
cy.get('.does-not-exist').should(($element) => { expect($element.find('input')).to.not.exist })
cy.get('tbody tr:first').should(($tr) => {
  expect($tr).to.have.class('active')
  expect($tr).to.have.attr('href', '/users')
})

Cypress 定位

DOM树定位

  • .prev()上一个同级DOM元素 .next() 下一个同级DOM元素

  • .first() 同级别第一个DOM元素 .last() 同级别最后一个DOM元素

  • .children(selector)通过父元素定位子元素 .closest(selector)获取最近的祖先DOM元素

  • .eq(number)特定索引 .filter(selector)特定选择器

  • .nextAll()所有下一个同级元素 .nextUntil(selector)获取所有下一个同级元素直到指定元素出现

    • cy.get('parent-selector').contains('current-selector').nextAll().should('have.length', 3);
      cy.get('current-selector').nextUntil('selector').should('have.length', 3)
      
  • .not(selector)从找到的元素列表里删除selector的元素

  • parent() parents() parentsUntil()

  • .siblings() 所有同级别元素

链式定位获取的值

cy.get('.connectors-each-ul>li')
    .each(($el, index, $list) => {
    console.log($el, index, $list);
});

Cypress Action

  • .blur()` - 移开DOM元素上的焦点.

  • .focus() - 聚焦DOM元素.

  • .clear() - 清除输入或文本区域的值.

  • .check() - 选中复选框或者单选框.

  • .uncheck() - 取消选中复选框.

  • .select() - 选择一个含有 <option>属性的<select>元素.

  • .dblclick() - 双击DOM元素.

  • .type - 输入文本值

    • {lefearrow}{rightarrow}{uparrow}{downarrow}
    • {del}{selectall}{backspace}{alt}{ctrl}{cmd}{shift}
  • .scrollIntoView会移动到所get的元素地方(注意,水平与左右均会移动)

    • cy.get(selector).scrollIntoView().should('be.visible')
  • .scrollTo() -> .scrollTo(200, 200); .scrollTo('75%', '25%');.scrollTo('center', {easing: 'linear'}); .scrollTo('center', {duration: 2000});

  • 多重选择(标准)

    • cy.get('.action-select-multiple')
        .select(['fr-apples', 'fr-oranges', 'fr-bananas'])
        .invoke('val')
        .should('deep.equal', ['fr-apples', 'fr-oranges', 'fr-bananas'])
      // assert the selected values include oranges
      cy.get('.action-select-multiple')
        .invoke('val').should('include', 'fr-oranges')
      
  • .trigger(event)强制触发事件

  • .focused()对上一步的焦点元素进行执行

  • .screenshot(filename)截图

常用动作的参数配置

  • {force:true} Ignore error checking prior to type// like whether the input is visible or disabled

  • {delay:100}delay time 0.1sec

  • .click('left') 也可通过坐标点击 .click(100,80)对于ele的相对位置的x:100px y:80px

    • // You can click on 9 specific positions of an element://  
      ---------------------------------- 
      |// | topLeft        top       topRight |// |                                  |// |                                   |// |                                 |// | left          center        right |// |                                 |// |                                   |// |                                 |// | bottomLeft   bottom   bottomRight |// |
      ----------------------------------- 
      // clicking in the center of the element is the default
      

Cypress常用API

发送接口

Cypress.Commands.add('login', (userType, options = {}) => {
        const accountTypes = {   // 设置账号类型
            admin:{
                account:'admin',
                password:'123456'
            }
        }
        cy.request({
            url:'http://yourhost/login',
            method:'POST',
            form:true,
            body:accountTypes[userType]      // 使用 admin 账号登录
        })
    })

强制触发事件

// Main button pressed (usually the left button)
cy.get('.target').trigger('mousedown', { button: 0 })
// Auxiliary button pressed (usually the middle button)
cy.get('.target').trigger('mousedown', { button: 1 })
//Secondary button pressed (usually the right button)
cy.get('.target').trigger('mousedown', { button: 2 })

获取属性,强制改变属性

.its('length').should('be.gt', 2); .invoke('show').should('be.visible')

Cookies

  • 获取cookies cy.getCookie('')
  • 设置cookies cy.setCookie
  • 清除cookies cy.clearCookies();
  • 保留cookies Cypress.Cookies.preserveOnce(cookie_Key) 一般在beforeEach里使用
  • cookies白名单(每次均保留的cookies) 可以在before里使用
    • Cypress.Cookies.defaults({whitelist: ['session_id', 'remember_token']})

route路由设置

cy.server();
cy.fixture('example.json').as('comment');
// when application makes an Ajax request matching "GET comments/*"
// Cypress will intercept it and reply with object
// from the "comment" alias
cy.route('GET', 'comments/*', '@comment').as('getComment');
cy.wait('@getComment').then(($it) => {
    // expect($it).to.have.property('name');
    // expect($it).include('Using fixtures to represent data');
    var rep = $it.responseBody
    cy.log(JSON.stringify(rep));
    cy.log('--------------------------------')
    // .should('have.property', 'name')
    // .and('include', 'Using fixtures to represent data');
});

fixture(固件)

读取json文件

使用cy.fixture('xx.json').as('xx.json')导入json文件,可直接以对象形式访问,默认文件路径在fixtures文件夹下

cy.fixture('login.json').as('login')
cy.log("读取login.json文件账号:"+this.login.username)
cy.log("读取login.json文件密码:"+this.login.password)

读取/写入文件

cy.readFile('cypress.json')

cy.request('https://jsonplaceholder.cypress.io/users')
    .then((response) => {
    cy.writeFile('cypress/fixtures/users.json', response.body);
});

localstorage Setting

localStorage.getItem('key');localStorage.setItem('key');localStorage.removeItem('key');

cy.clearLocalStorage()

location当前页面的全局对象

cy.visit('http://localhost:8000/app/index.html?q=dan#/users/123/edit')
cy.location().should((loc) => {
  expect(loc.hash).to.eq('#/users/123/edit')
  expect(loc.host).to.eq('localhost:8000')
  expect(loc.hostname).to.eq('localhost')
  expect(loc.href).to.eq('http://localhost:8000/app/index.html?q=dan#/users/123/edit')
  expect(loc.origin).to.eq('http://localhost:8000')
  expect(loc.pathname).to.eq('/app/index.html')
  expect(loc.port).to.eq('8000')
  expect(loc.protocol).to.eq('http:')
  expect(loc.search).to.eq('?q=dan')
  expect(loc.toString()).to.eq('http://localhost:8000/app/index.html?q=brian#/users/123/edit')
})

cmd执行

var l = [];
l.push(
    "python",
    getScriptPath("login_request.py"),
);
var command = l.join(" ");
cy.exec(command).then(result => {
    var a = result.stdout;
    var orig = JSON.parse(a);
    const token = orig.items.token;
    const org = orig.items.organizations;
    cy.log(token);
    cy.log(a);
    cy.wrap(localStorage.setItem("token", token));});

Cypress用法范式

数据驱动(使用基于ES6的forEach)

describe('if your app uses jQuery', function () {
  ['mouseover', 'mouseout', 'mouseenter', 'mouseleave'].forEach((event) => {
    it('triggers event: ' + event, function () {
      // if your app uses jQuery, then we can trigger a jQuery
      // event that causes the event callback to fire
      cy
        .get('#with-jquery').invoke('trigger', event)
        .get('#messages').should('contain', 'the event ' + event + 'was fired')
    })
  })
})

断言

序列(列表断言)

cy.get('.todo-list li')     // command
  .should('have.length', 2) // assertion
  .and(($li) => {
    // 2 more assertions
    expect($li.get(0).textContent, 'first item').to.equal('todo a')
    expect($li.get(1).textContent, 'second item').to.equal('todo B')
  })

should断言

属性断言

.should('have.attr', 'style', 'color:red'); .should('have.class', 'success')

值断言

.should('have.value', ' clear the text'); .should('contains', 'text')

其他状态断言

.should('not.be.visible'); .should('be.visible')

.should('be.checked'); .should('not.be.checked')

cy.get('.assertions-link')
    .should('have.class', 'active')
    .and('have.attr', 'href')
    .and('include', 'cypress.io');

expect断言

expect(true).to.be.true;
const o = {foo: 'bar'};
expect(o).to.equal(o);
expect(o).to.deep.equal({foo: 'bar'});
// matching text using regular expression
expect('FooBar').to.match(/bar$/i);
// property assert
expect(cookies[0]).to.have.property('name', 'token');
// 使用jQuery进行断言
cy.get('.assertions-p')
    .find('p')
    .should(($p) => {
    // https://on.cypress.io/$
    // return an array of texts from all of the p's
    // @ts-ignore TS6133 unused variable
    const texts = $p.map((i, el) => Cypress.$(el).text());
    // jquery map returns jquery object
    // and .get() convert this to simple array
    const paragraphs = texts.get();
    // array should have length of 3
    expect(paragraphs, 'has 3 paragraphs').to.have.length(3);
    // use second argument to expect(...) to provide clear
    // message with each assertion
    expect(paragraphs, 'has expected text in each paragraph').to.deep.eq([
        'Some text from first p',
        'More text from second p',
        'And even more text from third p',
    ]);
});

条件判断

// body已经完全显示,没有任何还在对状态进行的修改
cy.get('body').then(($body) => {
    // 同步查询body中的文字
    // 并根据它是否包含指定字符串来做一些事,注意,这里是JQuery的使用语法,cy原生不支持条件判断
    if ($body.text().includes('some string')) {
      // 找到了
      cy.get(...).should(...)
    } else {
      // 没找到
      cy.get(...).should(...)
    }
  })
// 不会报错的jQuery原生的长度匹配与正则文本匹配
cy.get('.docs-header')
    .find('div')
    .should(($div) => {
    if ($div.length !== 1) {
        // you can throw your own errors
        throw new Error('Did not find 1 element');
    }
    const className = $div[0].className;
    if (!className.match(/heading-/)) {
        throw new Error(`Could not find class "heading-" in ${className}`);
    }
});

配置文件

// set config
//具体运行参数可以在 package.json 下配置:
"scripts": {
   "cypress:run": "cypress run --browser chrome"
 }
//解决chrome 下的跨域问题:在 cypress.json 中添加:
"chromeWebSecurity": false
//生成Junit-allure报表在 cypress.json 中添加依赖:
"reporter": "junit",
"reporterOptions": {
  "mochaFile": "results/my-test-output[hash].xml",   // 通过hash 标签区分不同文件的用例结果
  "toConsole": true
}
posted @ 2020-12-08 09:19  WheelCode  阅读(433)  评论(0)    收藏  举报