Intermediate Workshop
@ceceliacreates
Delete/comment out line 204 in cypress/support/commands.ts
A test is considered to be flaky when it can pass and fail across multiple retry attempts without any code changes.
For example, a test is executed and fails, then the test is executed again, without any change to the code, but this time it passes.
✅ ? ❌
github.com/cypress-io/cypress-realworld-app
// Backend source code for "like" functionality
// creates an arbitrary delay on the server to simulate inconsistent response times
const delay = Math.random() * 5500;
setTimeout(() => {
res.sendStatus(200);
}, delay);
Test case: User A likes a transaction of User B; User B gets notification that User A liked transaction
✅ ? ❌
cy.contains(likesCountSelector, 0);
cy.getBySelLike("like-button").click();
// a successful "like" should disable the button and increment
// the number of likes
cy.getBySelLike("like-button").should("be.disabled");
cy.contains(likesCountSelector, 1);
Test case: User A likes a transaction of User B; User B gets notification that User A liked transaction
✅ ? ❌
Test case: User A likes a transaction of User B; User B gets notification that User A liked transaction
✅ ? ❌
Examples:
Examples:
Examples:
🧠 cy.intercept() can spy and stub all network requests
💡Wait for long network requests before proceeding
cy.intercept('GET', '/api/accounts/*').as('getAccount')
cy.visit('/accounts/123')
// Wait up to 30 seconds for request to complete
cy.wait('@getAccount', { timeout: 30000 })
cy.get(selector)
.should('have.text', accountName)
💡Stub inconsistent or unneeded network requests
// Intercept and stub the response as successful
cy.intercept({ method: 'POST', url: '/inconsistent' }, { success: true })
cy.intercept(url)
cy.intercept(method, url)
cy.intercept(routeMatcher)
// with routeMatcher
cy.intercept({
url: 'http://example.com/search*',
query: { q: 'expected terms' },
}).as('search')
auth, headers, hostname, https, method, middleware, path, pathname, port, query, times, url
Save the intercepted request to use throughout your test code
cy.intercept({
url: 'http://example.com/search*',
query: { q: 'expected terms' },
}).as('search')
After declaring an intercept, use its alias to wait for the request to occur in your test code
cy.intercept('GET', '/users').as('getUsers')
// test code
cy.wait('@getUsers')
// test code continues after request occurs
it('adds two items', () => {
cy.get('.new-todo')
.type('todo A{enter}')
.type('todo B{enter}')
cy.get('.todo-list li')
.should('have.length', 2)
})
cy.get('.todo-list li') // command
.should('have.length', 2) // assertion
✅ ❌
If the assertion that follows the cy.get() command fails, then the cy.get() command will requery the application's DOM again, and again until the cy.get() command timeout is reached.
If the assertion that follows the cy.get() command passes, then the command finishes successfully.
🧠 Only the last query command is retried
💡Use a single query command instead of chaining
-- cy.get() not retried
cy.get(selector).contains(text)
.should()
-- Entire query is retried
cy.contains(selector, text)
.should()
💡Alternate commands and assertions
-- Test will retry the cy.get() until assertion passes
cy.get(selector)
.should('have.length', 3)
-- Now we know we have the correct element before proceeding
.parent()
.should('contain', text)
Will retry an individual test a specified number of times before failing
// cypress.json
{
"retries": 1
}
// configure by mode
{
"retries": {
// Configure retry attempts for `cypress run`
"runMode": 2,
// Configure retry attempts for `cypress open`
"openMode": 0
}
}
Coming Soon: Test Burn-In
GitHub & Slack Flake Alerts
Parallelization recommendations in Cypress Dashboard
Intermediate Workshop
@ceceliacreates