The Story:
In several places in our test codebase we assert different CSS values to be equal to expected values. Usually, this is a color
, background-color
, font
related style properties, or cursor
. This question is about dealing with colors.
Here is an example working test that currently passes:
describe("AngularJS home page", function () {
beforeEach(function () {
browser.get("/");
});
it("should show a blue Download button", function () {
var downloadButton = element(by.partialLinkText("Download"));
expect(downloadButton.getCssValue("background-color")).toEqual("rgba(0, 116, 204, 1)");
});
});
It checks that the Download button on the AngularJS website has 0, 116, 204, 1
RGBA value.
Now, if the color would change, the test would fail as, for example:
Expected 'rgba(0, 116, 204, 1)' to equal 'rgba(255, 116, 204, 1)'.
The Problems:
As you can see, first of all, the expectation itself is not quite readable. Unless we put a ment near it, it is not obvious what color are we expecting to see.
Also, the error message is not informative. It is unclear what an actual color is and what color are we expecting to see.
The Question:
Is it possible to improve the test itself and the error message to be more readable and informative and operate color names instead of color RGB/RGBA values?
Desired expectation:
expect(downloadButton).toHaveBackgroundColor("midnight blue");
Desired error messages:
Expect 'blue' to equal 'black'
Expect 'dark grey' to equal 'light sea green'
Currently, I'm thinking about making a custom jasmine matcher that would convert the RGB/RGBA
value to a custom Color
object that would keep the original value as well as determine the closest color. color
npm package looks very promising.
Would appreciate any hints.
The Story:
In several places in our test codebase we assert different CSS values to be equal to expected values. Usually, this is a color
, background-color
, font
related style properties, or cursor
. This question is about dealing with colors.
Here is an example working test that currently passes:
describe("AngularJS home page", function () {
beforeEach(function () {
browser.get("https://angularjs/");
});
it("should show a blue Download button", function () {
var downloadButton = element(by.partialLinkText("Download"));
expect(downloadButton.getCssValue("background-color")).toEqual("rgba(0, 116, 204, 1)");
});
});
It checks that the Download button on the AngularJS website has 0, 116, 204, 1
RGBA value.
Now, if the color would change, the test would fail as, for example:
Expected 'rgba(0, 116, 204, 1)' to equal 'rgba(255, 116, 204, 1)'.
The Problems:
As you can see, first of all, the expectation itself is not quite readable. Unless we put a ment near it, it is not obvious what color are we expecting to see.
Also, the error message is not informative. It is unclear what an actual color is and what color are we expecting to see.
The Question:
Is it possible to improve the test itself and the error message to be more readable and informative and operate color names instead of color RGB/RGBA values?
Desired expectation:
expect(downloadButton).toHaveBackgroundColor("midnight blue");
Desired error messages:
Expect 'blue' to equal 'black'
Expect 'dark grey' to equal 'light sea green'
Currently, I'm thinking about making a custom jasmine matcher that would convert the RGB/RGBA
value to a custom Color
object that would keep the original value as well as determine the closest color. color
npm package looks very promising.
Would appreciate any hints.
Share Improve this question edited Dec 29, 2015 at 1:20 alecxe asked Dec 27, 2015 at 6:01 alecxealecxe 474k127 gold badges1.1k silver badges1.2k bronze badges 8- Are all the puted values guaranteed to correspond to named colors? – BoltClock Commented Dec 27, 2015 at 6:10
- @BoltClock good question. I would stick to some base mapping between rgb->color name, and if a color name not found, we can just show the actual original rgb(a) value..I understand, it is probably not going to be bullet-proof, but I hope practical. – alecxe Commented Dec 27, 2015 at 6:11
-
4
Most of the websites have their own set of colors, usually there is not a lot of them, but it depends on a design. I would think of creating a simple JS object as a map for colors and color names, specific to your website, and not rely on another lib:
{ 'red': 'rgba(255, 0, 0, 1)', 'blue': 'rgba(0, 0, 255, 1)' }
and match against them. – Michael Radionov Commented Dec 27, 2015 at 9:47 - I would opt for color roles, not colors per se.. although that's not 1:1. – user2864740 Commented Dec 31, 2015 at 3:45
-
2
@alecxe The tests I've written target classes, but even in the case of Michael's suggestion it could be
{ 'warning': 'rgb(255, 0, 0, 1)' }
. That's still lower than I'd prefer to deal with though and human 'visual' testing catches the layout/rendering flaws - that can manifest in so many ridiculous ways across different devices - much better than Selenium can. – user2864740 Commented Dec 31, 2015 at 4:46
2 Answers
Reset to default 8 +50Protractor uses Jasmine as its testing framework by default and it provides a mechanism for adding custom expectations.
So, you could do something like this:
In your protractor config file:
var customMatchers = {
toHaveBackgroundColor: function(util, customEqualityTesters) {
pare: function(actual, expected) {
result.pass = util.equals(extractColor(actual), convertToRGB(expected), customEqualityTesters);
result.message = 'Expected ' + actual + ' to be color ' + expected';
}
}
}
jasmine.addMatchers(customMatchers);
function convertToRGB(color) {
// convert a named color to rgb
}
function extractColor(domElement) {
// extract background color from dom element
}
And to use it:
expect(downloadButton).toHaveBackgroundColor("midnight blue");
I haven't tried this out, but this is the basic idea of what you need.
I got a working answer based on @Andrew and @Manasov remendations.
So the custom expectation would be like this:
var nameColor = require('name-that-color/lib/ntc');
var rgbHex = require('rgb-hex');
toHaveColor: function() {
return {
pare: function (elem, color) {
var result = {};
result.pass = elem.getCssValue("color").then(function(cssColor) {
var hexColor = rgbHex(cssColor);
var colorName = nameColor.name('#' + hexColor.substring(0, 6).toUpperCase());
result.message = "Expect '" + colorName[1] + "' to equal '" + color + "'";
return colorName[1] === color;
});
return result;
}
}
}
We need to first install the necessary packages:
npm install name-that-color
npm install rgb-hex
We first need to convert the rgb
color into hex. Also we have to remove the alpha from the color for name-that-color
to actually match it against a color name, it can be removed from the hex
conversion.
Now we can just simple call it like:
expect(downloadButton).toHaveColor("midnight blue");