Cypress: Testing color property always yields `rgb()` value, even when stored as hex

Created on 21 Jul 2018  路  10Comments  路  Source: cypress-io/cypress

Firstly, I 鉂わ笍 Cypress. Thank you so much for all of y'alls work.

Current behavior:

I have a quick test to ensure that some branding is working within a component:

cy.get('[data-testid="StepsCard"]')
  .find('h2')
  .should('have.css', 'color').and('equal', '#663399');

This is what the property looks like in the Cypress Test Runner's browser's dev tools:
screen shot 2018-07-20 at 11 48 19 am

The test fails with the following error:
screen shot 2018-07-20 at 11 51 58 am

I've also seen others complain about this behavior: https://gitter.im/cypress-io/cypress?at=5b4da9d88fe2780689bc20e7

Desired behavior:

Test passes when running yarn cypress:open, since the <h2> element within the StepsCard component does indeed have a color of #663399.

Steps to reproduce:

I'll reproduce if absolutely necessary. I'm curious to know if perhaps this may be unavoidable. I understand y'all are very busy - feel free to close this issue if it isn't up to the necessary standard 馃憤

Versions

  • macOS High Sierra v0.13.6
  • Chrome v67.0.3396.99
  • Cypress v3.0.1
  • React v16.4.1
existing workaround pkdriver ready for work unexpected behavior

Most helpful comment

Cool. I figured it had something to do with that old jQuery issue...

I - personally - would love to see that accepted as a core feature.

Curious to see how others feel.

All 10 comments

This assertion method comes from chai-jquery, which makes assertions off of the computed values of css styles. Unfortunately, this returns in the rgb format - and I agree, it is annoying.

As a workaround you could include some sort of hex -> rgb converter for your assertions, otherwise we will have to include one in our library and overwrite this assertion.

Cool. I figured it had something to do with that old jQuery issue...

I - personally - would love to see that accepted as a core feature.

Curious to see how others feel.

+1

Not a big deal, but it would be nice to have this someday!

I've just noticed this issue but as @j-arens mentioned above, it's not a big deal, nice to have ;)

+1

Yes, its NBD, but killing dev kruft is always welcome.

Additionally, these are compared as a string, so "rgb(255, 255, 255)" <> "rgb(255,255,255)". When I'm comparing colors, I care about the resolved color only, not the string it's encoded as.

Is there any new development in this issue?

I currently use this method to compare color values. (With the color library)

import Color from 'color'

const expectBackgroundColor = Color('#000').string() // => got "rgb(0, 0, 0)"
cy.get('div').should($div => {
  const style = window.getComputedStyle($div[0])
  expect(style.backgroundColor).to.equal(expectBackgroundColor)
})

Now with css-variables this could certainly come in handy. I'm currently doing a comparison like:
expect('div').to.have.css('color', 'var(--success-color)');
which fails because the value is actually some rgb value

Perhaps try the following: https://gist.github.com/NicholasBoll/e584991b36986a85acf0e95101752bc0

The gist has the following JS to add to your cypress/support/commands.js file:

const compareColor = (color, property) => (targetElement) => {
    const tempElement = document.createElement('div');
    tempElement.style.color = color;
    tempElement.style.display = 'none'; // make sure it doesn't actually render
    document.body.appendChild(tempElement); // append so that `getComputedStyle` actually works

    const tempColor = getComputedStyle(tempElement).color;
    const targetColor = getComputedStyle(targetElement[0])[property];

    document.body.removeChild(tempElement); // remove it because we're done with it

    expect(tempColor).to.equal(targetColor);
};

Cypress.Commands.overwrite('should', (originalFn, subject, expectation, ...args) => {
    const customMatchers = {
        'have.backgroundColor': compareColor(args[0], 'backgroundColor'),
        'have.color': compareColor(args[0], 'color'),
    };

    // See if the expectation is a string and if it is a member of Jest's expect
    if (typeof expectation === 'string' && customMatchers[expectation]) {
        return originalFn(subject, customMatchers[expectation]);
    }
    return originalFn(subject, expectation, ...args);
});

You'll then be able to do things like:

cy.get('button').should('have.color', 'black')
cy.get('button').should('have.color', '#000000')
cy.get('button').should('have.color', 'rgba(0, 0, 0)')

cy.get('button').should('have.backgroundColor', '#cccccc')

It works by using getComputedStyle on both the subject element and creates a temp element to get the computed color and compares. The assertion output could be better, but perhaps that's an assertion plugin?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

HugoGiraudel picture HugoGiraudel  路  97Comments

kamituel picture kamituel  路  66Comments

jukefr picture jukefr  路  168Comments

t-zander picture t-zander  路  125Comments

Hipska picture Hipska  路  83Comments