---
title: "How to Test an Application that Changes a CSS Variable"
url: "https://www.cypress.io/blog/how-to-test-an-application-that-changes-css-variable"
description: "Let's take an application that has an <input type=\"color\"> element. When the user picks a new color, the application changes a CSS variable which controls the…"
---

# How to Test an Application that Changes a CSS Variable

March 17, 2020

By Gleb Bahmutov

## The App

Let's take an application that has an `<input type="color">` element. When the user picks a new color, the application changes a CSS variable which controls the background color. In action, it looks like this:

The application in action

The HTML markup below has only the input color element.

```html
<head>
  <link rel="stylesheet" type="text/css" href="app.css" />
</head>
<body>
  This is the body of the document
  <div>Change color using this color input
    <input type="color">
  </div>
  <script src="app.js"></script>
</body>
```

The `app.css` file uses [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties?ref=cypress-io.ghost.io) to control the background color

```css
:root {
  --main-color: #fff;
  --background-color: #000;
}
body {
  color: var(--main-color);
  background-color: var(--background-color);
  font-size: xx-large;
}
```

Finally, the application code `app.js` reacts to the `change` event and sets the new CSS variable value

```js
document.querySelector('input[type=color]')
  .addEventListener('change', (e) => {
    console.log('setting new background color to: %s', e.target.value)
    document.documentElement.style.setProperty(
      '--background-color', e.target.value)
})
```

**Tip:** find the application and test code in repository [cypress-example-recipes](https://github.com/cypress-io/cypress-example-recipes?ref=cypress-io.ghost.io) under "Testing the DOM" recipes.

## Tests

In our first test, we will ignore _how_ the application implements the background color. Instead we will confirm that the change works.

```js
it('starts with black background', () => {
  cy.visit('index.html')
  cy.get('body').should('have.css', 'background-color', 'rgb(0, 0, 0)')
})
```

First test confirms the application has black background after load

**Tip:**  instead of using RGB values to make the assertion, you can specify the expected value in different formats using [chai-colors](https://github.com/hurrymaplelad/chai-colors?ref=cypress-io.ghost.io) NPM module, see our recipe [Adding Chai Assertions](https://github.com/cypress-io/cypress-example-recipes?ref=cypress-io.ghost.io#fundamentals).

The above test is too short in my opinion. We want to go through the entire user action: visit the page, change the color using the input element, and observe the result. A more realistic test would be:

```js
it('changes background color', () => {
  cy.visit('index.html')
  cy.get('body').should('have.css', 'background-color', 'rgb(0, 0, 0)')

  // select the new color value in the <input type="color">
  // element and trigger "change" event
  cy.get('input[type=color]')
    .invoke('val', '#ff0000')
    .trigger('change')

  // check the background color has been changed
  cy.get('body')
    .should('have.css', 'background-color', 'rgb(255, 0, 0)')
})
```

The test uses the [.invoke](http://on.cypress.io/invoke?ref=cypress-io.ghost.io) command to set the value of the color input element, then calls the [.trigger](http://on.cypress.io/trigger?ref=cypress-io.ghost.io) command to generate the "change" to the event. The application does the rest.

The test changes the background color

To better see how the `.trigger` command caused the application to change the color, hover over the command - Cypress shows before and after snapshots that include all styles.

Hover over trigger command to see how the app has changed in response

## Spying on browser API

In the next test, let's confirm the implementation details. Our application calls the browser API method `document.documentElement.style.setProperty` to change the CSS variable. Because Cypress tests run directly in the same browser's window as the application, we can [spy and stub](https://on.cypress.io/stubs-spies-and-clocks?ref=cypress-io.ghost.io) DOM method calls directly.

```js
it('can spy on native methods', () => {
  cy.visit('index.html')
  cy.get('body').should('have.css', 'background-color', 'rgb(0, 0, 0)')

  // create a spy and save it under an alias
  cy.document().its('documentElement.style')
    .then((style) => cy.spy(style, 'setProperty').as('setColor'))

  cy.get('input[type=color]')
    .invoke('val', '#ff0000')
    .trigger('change')

  cy.get('body').should('have.css', 'background-color', 'rgb(255, 0, 0)')
  // find spy by its alias and confirm it was called as expected
  cy.get('@setColor')
    .should('have.been.calledWith', '--background-color', '#ff0000')
})
```

The test passes, and Cypress Command Log shows the table with the spy, its alias, and how many times it was called. It also shows when it was called among the other Cypress commands.

"setColor" spy was called once right after triggering color change (green arrows)

**Tip:** if you do not care about values of some arguments in an assertion like

```js
cy.get('@setColor')
  .should('have.been.calledWith', '--background-color', '#ff0000')
```

you can use Sinon.js placeholders. For example, skip the `--background-color` value and match any string using:

```js
cy.get('@setColor')
  .should('have.been.calledWith', Cypress.sinon.match.string, '#ff0000')
```

## See also

Read these blog posts that show more examples accessing the browser and DOM APIs directly from Cypress tests

-   [Testing the Browser Notification API](https://www.cypress.io/blog/2020/01/24/testing-the-browser-notification-api/?ref=cypress-io.ghost.io)
-   [Testing the first built-in browser module, KV Storage, using Cypress](https://www.cypress.io/blog/2019/07/02/testing-the-first-built-in-browser-module/?ref=cypress-io.ghost.io)
-   [Stub navigator API in end-to-end tests](https://glebbahmutov.com/blog/stub-navigator-api/?ref=cypress-io.ghost.io)