cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.8k stars 3.17k forks source link

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

Open kylemh opened 6 years ago

kylemh commented 6 years ago

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

jennifer-shehane commented 6 years ago

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.

kylemh commented 6 years ago

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.

j-arens commented 6 years ago

+1

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

ziyailkemerogul commented 5 years ago

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

Roralee commented 5 years ago

+1

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

calvinballing commented 5 years ago

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.

mutoe commented 5 years ago

Is there any new development in this issue?

mutoe commented 5 years ago

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)
})
rienheuver commented 5 years ago

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

NicholasBoll commented 4 years ago

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?

ahnpnl commented 3 years ago

I hope this feature will be supported soon

YakinRojinegro commented 2 years ago

Any progress in this one? The solution of @NicholasBoll is not working anymore in some versions due to the change of rgb to rgba in cypress these are the same color (white). image

Tooluloope commented 2 years ago

Any Luck on this.

drecali commented 2 years ago

@YakinRojinegro @Tooluloope This answer on Stack Overflow works for me. Basically the chai-colors plugin can compare colors expressed in any standard CSS color model. I use it to compare HEX to RGBA. Hope that helps!

alaaahmedmu commented 11 months ago

any progress on this issue?

vsambor commented 10 months ago

This is very annoying :(

katzohub commented 5 months ago

@jennifer-shehane thanks for the idea 💯 my function here (convert hex to rgb) is in place file commands.ts

      export const hexToRgb = (hex: string) => {
      let r = 0;
      let g = 0;
      let b = 0;

      // 3 digits
      if (hex.length === 4) {
        r = parseInt(`${hex[1]}${hex[1]}`, 16);
        g = parseInt(`${hex[2]}${hex[2]}`, 16);
        b = parseInt(`${hex[3]}${hex[3]}`, 16);

    // 6 digits

      } else if (hex.length === 7) {
        r = parseInt(hex.slice(1, 3), 16);
        g = parseInt(hex.slice(3, 5), 16);
        b = parseInt(hex.slice(5, 7), 16);
      }
      // return rgb value , alert on space
      return `rgb(${r}, ${g}, ${b})`;
    };

and next step

import {
  hexToRgb,
} from '../../support/commands';

 it('correct colors for elements', () => {
    cy.get(byTestId('admin-roll-up-menu')).click();
    cy.get(byTestId('link-to-companies')).click();

    testLoadPage('select-company-btn-3', '/accountant/overview');
    cy.wait('@authSwitchCompany').should(({ request }) => {
      expect(request.body.companyId, 'companyId').to.eq(3);
    });
    defualControllerColorsLight();
    cy.get(byTestId('overview-graph')).should(
      'have.css',
      'background-color',
      hexToRgb('#ffffff'),
    );
    cy.get(byTestId('graph-title')).should(
      'have.css',
      'color',
      hexToRgb('#292929'),
    );
  });

and result

cy_result_git