DEV Community

Ramu Narasinga
Ramu Narasinga

Posted on • Originally published at thinkthroo.com

Testing in Umami codebase - Part 1.1

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.

Prerequisite

  1. Testing in Umami codebase — Part 1.0

Approach

The approach we take is simple:

  1. Check the test script in package.json

  2. Understand the Cypress configuration

  3. Reviews tests in the cypress folder.

In this part 1.1, we review the website.cy.ts.

Test script in package.json

At L47, you will find the below script in package.json:

    "test": "jest",
    "cypress-open": "cypress open cypress run",
    "cypress-run": "cypress run cypress run",
Enter fullscreen mode Exit fullscreen mode

Looks like they also have use jest.

Cypress config

In the umami/cypress.config.ts, you will find the below code:

import { defineConfig } from 'cypress';

export default defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
  },
  // default username / password on init
  env: {
    umami_user: 'admin',
    umami_password: 'umami',
    umami_user_id: '41e2b680-648e-4b09-bcd7-3e2b10c06264',
  },
});
Enter fullscreen mode Exit fullscreen mode

Learn more about the Cypress Configuration File.

website.cy.ts

In this file, I found 3 test cases:

  1. Add a website

  2. Edit a website

  3. Delete a website

Add a website


 

it('Add a website', () => {
    // add website
    cy.visit('/settings/websites');
    cy.getDataTest('button-website-add').click();
    cy.contains(/Add website/i).should('be.visible');
    cy.getDataTest('input-name').find('input').as('inputUsername').click();
    cy.getDataTest('input-name').find('input').type('Add test', { delay: 0 });
    cy.getDataTest('input-domain').find('input').click();
    cy.getDataTest('input-domain').find('input').type('addtest.com', { delay: 0 });
    cy.getDataTest('button-submit').click();
    cy.get('td[label="Name"]').should('contain.text', 'Add test');
    cy.get('td[label="Domain"]').should('contain.text', 'addtest.com');

    // clean-up data
    cy.getDataTest('link-button-edit').first().click();
    cy.contains(/Details/i).should('be.visible');
    cy.getDataTest('text-field-websiteId')
      .find('input')
      .then($input => {
        const websiteId = $input[0].value;
        cy.deleteWebsite(websiteId);
      });
    cy.visit('/settings/websites');
    cy.contains(/Add test/i).should('not.exist');
  });
Enter fullscreen mode Exit fullscreen mode

Picked this code from Add a website test case.

Edit a website

it('Edit a website', () => {
    // prep data
    cy.addWebsite('Update test', 'updatetest.com');
    cy.visit('/settings/websites');

    // edit website
    cy.getDataTest('link-button-edit').first().click();
    cy.contains(/Details/i).should('be.visible');
    cy.getDataTest('input-name').find('input').click();
    cy.getDataTest('input-name').find('input').clear();
    cy.getDataTest('input-name').find('input').type('Updated website', { delay: 0 });
    cy.getDataTest('input-domain').find('input').click();
    cy.getDataTest('input-domain').find('input').clear();
    cy.getDataTest('input-domain').find('input').type('updatedwebsite.com', { delay: 0 });
    cy.getDataTest('button-submit').click({ force: true });
    cy.getDataTest('input-name').find('input').should('have.value', 'Updated website');
    cy.getDataTest('input-domain').find('input').should('have.value', 'updatedwebsite.com');

    // verify tracking script
    cy.get('div')
      .contains(/Tracking code/i)
      .click();
    cy.get('textarea').should('contain.text', Cypress.config().baseUrl + '/script.js');

    // clean-up data
    cy.get('div')
      .contains(/Details/i)
      .click();
    cy.contains(/Details/i).should('be.visible');
    cy.getDataTest('text-field-websiteId')
      .find('input')
      .then($input => {
        const websiteId = $input[0].value;
        cy.deleteWebsite(websiteId);
      });
    cy.visit('/settings/websites');
    cy.contains(/Add test/i).should('not.exist');
  });
Enter fullscreen mode Exit fullscreen mode

Picked this code from Edit a website test case.

Delete a website

it('Delete a website', () => {
  // prep data
  cy.addWebsite('Delete test', 'deletetest.com');
  cy.visit('/settings/websites');

  // delete website
  cy.getDataTest('link-button-edit').first().click();
  cy.contains(/Data/i).should('be.visible');
  cy.get('div').contains(/Data/i).click();
  cy.contains(/All website data will be deleted./i).should('be.visible');
  cy.getDataTest('button-delete').click();
  cy.contains(/Type DELETE in the box below to confirm./i).should('be.visible');
  cy.get('input[name="confirm"').type('DELETE');
  cy.get('button[type="submit"]').click();
  cy.contains(/Delete test/i).should('not.exist');
});
Enter fullscreen mode Exit fullscreen mode

Picked this code from Delete a website test case.

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/package.json

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

  3. https://github.com/umami-software/umami/blob/master/cypress.config.ts

Top comments (0)