How can I get a custom css variable from any element (cypress)

999 Views Asked by At

enter image description here

I want to create some tests checking the styles of elements. We use these custom CSS vars. Is there any way to get these in cypress instead of checking for e.g. RGB(0,0,0)?

Thx in advance!

3

There are 3 best solutions below

3
agoff On

If you use cy.should() alongside have.css, you can specify which CSS property to check, and the value.

Using a simple example from your image, it would look something like this:

cy.get('foo')
  .should('have.css', 'min-width', '211px');

If there are more complex checks going on, you can always run the .should() as a callback.

cy.get('foo').should(($el) => {
  const minHeight = +($el.css('min-height').split('px')[0]);
  expect(minHeight).to.eql(40);
});

I found myself checking a lot of CSS values on elements, and opted to have a custom command that allowed me to pass in an expected object and check for all of those values.

Cypress.Commands.add('validateCss', { prevSubject: 'element' }, (subject, expected: { [key: string]: any }) => {
  Object.entries(expected).forEach(([key, value]) => {
    cy.wrap(subject).should('have.css', key, value);
  });
});

const expected = { 'min-width': '211px', 'min-height': '40px' };
cy.get('foo').validateCss(expected);
0
Animesh On

Interacting with browser element or Dynamic CSS can be achieved in may ways ,

most use-full is cy.get() with the help of .should()

you can find here ( However i know you already checked this :) )

https://docs.cypress.io/api/commands/get#Get-vs-Find

for Example

cy.get('#comparison')
  .get('div')
  // finds the div.test-title outside the #comparison
  // and the div.feature inside
  .should('have.class', 'test-title')
  .and('have.class', 'feature')
2
Fody On

It is possible to evaluate a css variable fairly simply using getComputedStyle()

Cypress.Commands.add('cssVar', (cssVarName) => {
  return cy.document().then(doc => {
    return window.getComputedStyle(doc.body).getPropertyValue(cssVarName).trim()
  })
})

cy.cssVar('--mycolor')
  .should('eq', 'yellow')

where, for example

<html>
<head>
  <style>
    body { 
      --mycolor: yellow;
    }
    p {
      background-color: var(--mycolor);
    }
  </style>
</head>

But asserting that <p> has --mycolor requires a dummy element to evaluate yellow to rgb(255, 255, 0).

Cypress.Commands.add('hasCssVar', {prevSubject:true}, (subject, styleName, cssVarName) => {
  cy.document().then(doc => {
    const dummy = doc.createElement('span')
    dummy.style.setProperty(styleName, `var(${cssVarName})`)
    doc.body.appendChild(dummy)

    const evaluatedStyle = window.getComputedStyle(dummy).getPropertyValue(styleName).trim()
    dummy.remove()

    cy.wrap(subject)
      .then($el => window.getComputedStyle($el[0]).getPropertyValue(styleName).trim())
      .should('eq', evaluatedStyle)
  })
})

it('compares element property to CSS variable', () => {

  cy.cssVar('--mycolor').should('eq', 'yellow')

  cy.get('p').hasCssVar('background-color', '--mycolor') // passes

  cy.get('button').click()                               // change the css var color

  cy.cssVar('--mycolor').should('eq', 'red')  

  cy.get('p').hasCssVar('background-color', '--mycolor') // passes
})

The complication is not really because of the CSS var, but because we are dealing with color names that are automatically translated by the browser CSS engine.


Full test page

<html>
<head>
  <style>
    body { 
      --mycolor: yellow;
    }
    p {
      background-color: var(--mycolor);
    }
  </style>
</head>
<body>

  <p>Some text, change the background from yellow to red.</p>
  <button onclick="changeColor()">Change color</button>

  <script>
    function changeColor() { 
      document.body.style.setProperty('--mycolor', 'red')
    };
  </script>
</body>
</html>

Test log

enter image description here