Testing API Endpoints with Cypress

Adam Drake
3 min readOct 11, 2023

--

Photo by https://www.pexels.com/@heiner-56542/

I have been working recently on quite a large project with many API endpoints. I have been working on the Frontend whilst another developer has been working on the backend.

The Frontend stack is:

  • React
  • Typescript
  • React-query (using hooks to wrap around the services created by OpenAPI)
  • OpenAPI (to generate API services which can be used in the Frontend application)

The Backend stack is:

  • Python
  • FastApi

Auto Generating API Services on the Frontend

Part of the flow is when the Backend makes some changes and pushes them the Frontend would pull these changes and then run a script. The script is:

"generate-client": "openapi --input http://localhost:3000/api/v2/openapi.json --output src/services/api --client axios",

This would use OpenApi to generate services and models in the Frontend codebase from the openapi.json file provided by the backend api. This is a super helpful script and easily allows our Frontend to keep up to date with the backend and also provides all the types we need to interact with these services.

Due to the sheer amount of changes quite a few things have been breaking when backend changes are being pushed.

When things break

However, as we have been going through this flow, due to the sheer amount of changes quite a few things have been breaking when backend changes are being pushed. This causes api endpoints like the Reseeding functionality to stop working or a specific GET request suddenly doesn’t work.

Due to the amount of endpoints we have in this application we needed a quick way to test the basic functionality of the endpoints whenever there were backend changes introduced. This would very quickly allow us to determine if the latest changes introduced anything that broke something.

Cypress to the rescue

This is where Cypress came in super handy. I was looking into their very extremely useful Real World Application repo and getting some ideas about how to do this.

They have a specific folder — api which they use just to test api endpoints. This was exactly what I needed so I decided to implement it. My primary focus was being able to access the apis and do basic GET requests. I didn’t want to spend too long on these tests at this time.

Getting through authentication

The endpoints we use require an authenticated user to access them. This comes in the form of a token in the request header. How to do this in Cypress? I experimented a few different ways and finally settled on this way:

Cypress.Commands.add('loginByRequest', () => {
cy.request({
method: 'POST',
url: 'http://localhost:3000/api/v2/login',
body: {
username: adminUser.username,
password: adminUser.password,
},
form: true,
}).then((resp) => {
const token = resp.body.token;
cy.wrap(token).as('jwt');
});
});

This is a command I added to the commands.ts file and it allowed me access to the api. The little ‘trick’ here is the line cy.wrap(token).as('jwt'); This allows the token to then be accessed in your tests so they can be used when you access the api endpoints. Something like:

describe('Users API', () => {
beforeEach(() => {
cy.loginByRequest();
});

context('GET /user', function () {
it('gets a list of users', function () {
cy.get('@jwt').then((token) => {
cy.request({
method: 'GET',
url: 'http://localhost:3000/api/v2/users',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
}).then((response) => {
expect(response.status).to.eq(200);
expect(response.body.total_records).to.be.greaterThan(1);
});
});
});
});
});

The cy.get('@jwt') allows you access to retrieve this token and then use it in the header of the GET request. Pretty neat!

Conclusion

This was a very quick way to introduce some tests into the codebase that could provide very quick and useful feedback when changes are done on the backend. When working on a large codebase it can sometimes become too much for a single developer to keep every piece of logic and connection in their head. By introducing basic tests like this you are giving yourself and the team a safety net to prevent you from accidentally pushing something broken to the production environment.

About me

I am a Frontend Developer working mainly with React and Typescript in my day to day professional life. I love exploring new tools and libraries and love the Javascript Ecosystem.

I like to write blog posts that share exciting new tools I’ve discovered, how-to articles and also the occasional opinion post.

I live in Prague in the Czech Republic with my family.

Check out the original blog post on my blog here.

--

--

Adam Drake

I'm a Frontend Developer and I write about all things Frontend Related - Think lightly of yourself and deeply of the world. Based in Prague, CZ