2025December

Testing in Umami codebase - Part 1.3

Inspired by BulletProof React, I applied its codebase architecture concepts to the Umami codebase.

This article focuses only on the testing strategies used in Umami codebase.

Prerequisites

  1. Testing in Umami codebase — Part 1.0

  2. Testing in Umami codebase — Part 1.1

  3. Testing in Umami codebase — Part 1.2

In part 1.1, we reviewed the website.cy.ts. It has the test cases for adding, editing and deleting a website. In this part 1.2, we reviewed the login.cy.ts test cases. In this part 1.3, we review the api-website.cy.ts

I found the following test cases defined in api-website.cy.ts

  1. Creates a website for user.

  2. Creates a website for team.

  3. Creates a website with a fixed ID.

  4. Returns all tracked websites.

  5. Gets a website by ID.

  6. Updates a website.

  7. Updates a website with only shareId.

  8. Resets a website by removing all data related to the website.

  9. Deletes a website.

I would be more interested to learn about fixtures because I saw it some of the test cases and also review the pattern used to make API requests within a test case.

Let’s choose a test case: #1, this demonstrates how a fixture is used.

What is a fixture in Cypress?

Fixture loads a fixed set of data located in a file. 

Syntax

cy.fixture(filePath)
cy.fixture(filePath, encoding)
cy.fixture(filePath, options)
cy.fixture(filePath, encoding, options)

Usage

cy.fixture('users').as('usersJson') // load data from users.json
cy.fixture('logo.png').then((logo) => {
  // load data from logo.png
})

Check out docs related to Fixtures.

Creates a website for user

You will find the following code at L30 in api-website.cy.ts.

it('Creates a website for user.', () => {
  cy.fixture('websites').then(data => {
    const websiteCreate = data.websiteCreate;
    cy.request({
      method: 'POST',
      url: '/api/websites',
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
      body: websiteCreate,
    }).then(response => {
      websiteId = response.body.id;
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('name', 'Cypress Website');
      expect(response.body).to.have.property('domain', 'cypress.com');
    });
  });
});

I see the cy.fixture, this loads the websites json from the fixtures/websites.json

{
  "websiteCreate": {
    "name": "Cypress Website",
    "domain": "cypress.com"
  },
  "websiteUpdate": {
    "name": "Cypress Website Updated",
    "domain": "cypressupdated.com"
  }
}

cy.request API is used to send a POST request to the backend. This fixture data is used as the payload.

About me:

Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.

Email: ramu.narasinga@gmail.com

I spent 200+ hours analyzing Supabase, shadcn/ui, LobeChat. Found the patterns that separate AI slop from production code. Stop refactoring AI slop. Start with proven patterns. Check out production-grade projects at thinkthroo.com

References:

  1. https://github.com/umami-software/umami/blob/master/cypress/e2e/api-website.cy.ts

  2. https://docs.cypress.io/api/commands/fixture

  3. https://github.com/umami-software/umami/blob/master/cypress/fixtures/websites.json

We use cookies
We use cookies to ensure you get the best experience on our website. For more information on how we use cookies, please see our cookie policy.

By clicking "Accept", you agree to our use of cookies.

Learn more