1. Multiple Assertions
cy .get('[data-cy=task]') .then( item => { expect(item[0]).to.contain.text('bread') expect(item[1]).to.contain.text('milk') })
- 用 then()就不会retry, 即使页面发生变化, expect assertion也不会retry.
cy .get('[data-cy=task]') .should( item => { if (item.length !== 3) { throw new Error('Not enough elements!') } expect(item[0]).to.contain.text('bread') expect(item[1]).to.contain.text('milk') })
- 用should(), 如果页面上元素发生变化, assert前面的一个命令就会retry。
- 可以加一些logic决定要不要做assertion。
2. Invisible element - changing the DOM
当Dom里面有一些invisible的element, 我们需要用.click(force:true) 来click到。更好的办法是让这个element显示出来。
cy .get('[data-cy=star]') // invisible element, only display when mouse over the 'board-item'. .invoke('show') .should('be.visible') .click()
同时我们也可以通过trigger()的办法来测试元素什么时候display。当鼠标靠近时display, 鼠标离开时disappear.
cy .get('[data-cy="board-item"]') .trigger('mouseover') cy .get('[data-cy=star]') .should('be.visible') cy .get('[data-cy="board-item"]') .trigger('mouseout') cy .get('[data-cy=star]') .should('not.be.visible')
- Cypress checks actionability of elements
- .invoke() function can change attributes of DOM elements.
- Trigger different type of events. Event listeners can be triggererd by .trigger() command.
3. Cookies
保存token在cookies里面,这样执行测试时候不用每个case都需要login一次。
方法一: 保存cookies 里面的token在support file>index.js里面,所有的tests都会share这个token。
Cypress.Cookies.defaults({ preserve: 'trello_token' })
方法二: 只是单个文件share这个token, 则可以放在 berore each里面:
beforeEach(() => { Cypress.Cookies.preserveOnce('trello_token') cy .visit('/') }) it('test #1', () => { cy .setCookie('trello_token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImZpbGlwQGV4YW1wbGUuY29tIiwiaWF0IjoxNjE1OTg5MTkyLCJleHAiOjE2MTU5OTI3OTIsInN1YiI6IjIifQ.c3HqS_RRCJp4IPYvwbUkxWPwBx4VXJa_0ArzKq7qx_M') cy .reload() }); it('test #2', () => { });
- Cypress deletes cookies and other storage in between tests
- Cypress.Cookies API enables you to change cookies rules.
4. Intercepting Network Requests
- use .intercept() to match any http request our app makes.
- intercepted http requests can be waited for.
- Intercepted http requests can be tested.
it('Intercept requests', () => { cy .intercept({ method: 'POST', url: '/api/boards' }).as('createBoard') cy .visit('/') cy .get('[data-cy=create-board]') .click() cy .get('[data-cy=new-board-input]') .type('launching a rocket{enter}') cy .wait('@createBoard') .then( (board) => { expect(board.response.statusCode).to.eq(201) expect(board.request.body.name).to.eq('launching a rocket') }) });
5. Stubbing Responses
stubbing response, 举例 如果get response stubbing empty.
cy .intercept({ method: 'GET', url: '/api/boards' }, { body: [] }).as('boardList')
can use fixture to load a json file as request reponse body:
cy .intercept({ method: 'GET', url: '/api/boards' }, { fixture: 'threeBoards' }).as('boardList')
stubbing network error:
cy .intercept({ method: 'POST', url: '/api/boards' }, { forceNetworkError: true }).as('boardList') cy.visit('/') cy.get('[data-cy-create-board]') .click() cy.get('[data-cy=new-board-input]') .type('new board{enter}') cy.get('#errorMessge') .should('be.visible')
- Second argument modifies intercepted request
- We can dynamically change just a part of response data.
it('Stubbing response', () => { cy .intercept({ method: 'GET', url: '/api/boards' }, (req) => { req.reply( (res) => { res.body[0].starred = true return res }) }).as('boardList') cy .visit('/') });
6. Creating a custom command
- Create .d.ts definmitions file to get autocomplete of custom command.
- JSDoc adds documentation to custom comands.
create a custom comman in the test file or under the support folder > commands.js.(notes: can add the command in a index to load type definitions that come tish cypress module.E.g. command.d.ts or index.d.ts check in cypress documents. )
Cypress.Commands.add('addBoard', (input) => { cy .get('[data-cy="create-board"]') .click(); cy .get('[data-cy=new-board-input]') .type(input + '{enter}'); }) it('Custom commands', () => { cy .visit('/'); cy .addBoard('groceries'); });
More powerful custom command using prevSubject: true or prevSubject: 'optional' command to call a child command only.
- custom commands can be parent, child or dual.
- https://testautomationu.applitools.com/advanced-cypress-tutorial/chapter9.html
Cypress.Commands.add('take', {prevSubject: 'optional'}, (subject, input) => { if (subject) { cy .wrap(subject) .find(`[data-cy=${input}]`) } else { cy .get(`[data-cy=${input}]`) } }) it('Custom commands', () => { cy .visit('/board/77787127477'); cy .take('list') .eq(0) .take('task') });
7. Install Plugins
8. Running a Task
We can run a task in the background , wait for it to finish, and then continue on with our test.