API-first setup pattern in Cypress - Build an Automation Script
describe('API-first setup pattern test', () => { it('creates a user via API and verifies UI shows it', () => { // Step 1: Create user via API cy.request({ method: 'POST', url: '/api/users', body: { name: 'Alice', email: 'alice@example.com' }, headers: { 'Content-Type': 'application/json' } }).then((response) => { expect(response.status).to.equal(201); expect(response.body).to.have.property('id'); }); // Step 2: Visit the users page cy.visit('/users'); // Step 3: Verify the user appears in the list cy.get('[data-test=user-list]').should('be.visible'); cy.get('[data-test=user-list]').contains('Alice').should('exist'); cy.get('[data-test=user-list]').contains('alice@example.com').should('exist'); }); });
This test uses Cypress to automate the manual test case.
First, it sends a POST request to the API to create a user named Alice. We check the response status is 201 to confirm success and that the response body contains an id, meaning the user was created.
Next, the test visits the /users page in the browser to check the UI.
Finally, it looks for the user list element using a data-test attribute, which is a best practice for stable selectors. It asserts that the list contains the name 'Alice' and the email 'alice@example.com'.
This approach uses the API to set up test data quickly and reliably, then verifies the UI shows the expected result, following the API-first setup pattern.
Now add data-driven testing with 3 different users created via API and verify each appears in the UI
Practice
API-first setup pattern in Cypress tests?Solution
Step 1: Understand API-first setup purpose
API-first setup means using backend API calls to prepare data before UI tests.Step 2: Identify the benefit
This approach makes tests faster and more reliable by avoiding UI data entry steps.Final Answer:
It prepares test data quickly by calling backend APIs before UI tests run. -> Option AQuick Check:
API-first setup = faster, reliable test data setup [OK]
- Thinking API-first replaces UI tests
- Assuming API calls slow down tests
- Believing API-first only works on frontend
Solution
Step 1: Recall Cypress API call syntax
Cypress usescy.request()to make HTTP requests.Step 2: Match correct method and parameters
cy.request('POST', url, body)is the correct syntax.Final Answer:
cy.request('POST', '/users', {name: 'John'}) -> Option DQuick Check:
Use cy.request() for API calls in Cypress [OK]
- Using cy.api() which is not a Cypress command
- Using cy.call() or cy.fetch() which don't exist in Cypress
- Mixing up method names or parameters
cy.request('POST', '/api/users', {name: 'Alice'}).then((response) => {
expect(response.status).to.eq(201)
cy.visit('/users/' + response.body.id)
})What will happen if the API returns status 400 instead of 201?
Solution
Step 1: Analyze the assertion on response status
The test expectsresponse.statusto equal 201.Step 2: Understand behavior if status is 400
If status is 400, the assertionexpect(response.status).to.eq(201)fails and test stops with failure.Final Answer:
The test will fail at the assertion checking response.status. -> Option CQuick Check:
Assertion fails if response.status != 201 [OK]
- Assuming test continues after failed assertion
- Thinking Cypress throws syntax error on bad status
- Believing test ignores failed API responses
cy.request('POST', '/api/items', {name: 'Book'})
.then((res) => {
expect(res.status).to.eq(200)
cy.wrap(res.body.id).as('itemId')
})
cy.get('@itemId').then((id) => {
cy.visit(`/items/${id}`)
})But the test fails with "Cannot read property 'then' of undefined". What is the likely cause?
Solution
Step 1: Understand Cypress command chaining and timing
Cypress commands run asynchronously and in order, but alias usage requires the alias to be set before use.Step 2: Identify timing issue with alias usage
cy.get('@itemId')is called immediately, before the alias is set inside thethencallback, causing undefined error.Final Answer:
Thecy.get('@itemId')runs before the alias is set. -> Option AQuick Check:
Alias must be set before cy.get() uses it [OK]
- Assuming API error causes this specific error
- Thinking cy.request is misspelled
- Believing cy.wrap cannot create aliases
const users = [
{name: 'Anna'},
{name: 'Ben'},
{name: 'Cara'}
]
// Which code snippet is correct?Solution
Step 1: Understand Cypress command queue and async behavior
Cypress commands likecy.requestare asynchronous and queued. To wait for all requests, usecy.wrap().each()with a.then()callback.Step 2: Analyze each option
The nativeforEachandfor-ofoptions placecy.visit()inside the loop, causing visits after each request instead of after all. Thecy.wrap(users).each(...) cy.visit()executes visit before requests due to queuing. Onlycy.wrap(users).each(...).then(() => cy.visit())waits for all requests before visiting.Final Answer:
cy.wrap(users).each(user => { cy.request('POST', '/api/users', user) }).then(() => { cy.visit('/users') }) -> Option BQuick Check:
Use cy.wrap().each() with then() to wait before next step [OK]
- Placing cy.visit() inside the forEach or for-of loop
- Using cy.wrap().each() without .then() afterward
- Not chaining .then() to wait for all iterations
Ready to prove it?
Pass the test and this pattern moves unknown
