Cypress
Cypress用法简介
介绍了Cypress的基本用法(Cypress一个基于js的自动化框架),注意:与jQuery一起食用更佳
本文参考资料
悠悠cypress博客;cypress action;cypress assert; cypress connect; cypress 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
}

浙公网安备 33010602011771号