CSS specificity testing
The method I settled with is to use getComputedStyle to get the style with "highest priority". In the css I add a "tag" to the content property. In jasmine I then check if the desired tag is the computedStyle. (I will extend this in scss so that the content property is set by a mixin if test mode is used and not set in production.) This only makes a unit test for the class of highest priority, but not for the second highest etc.
Below is a tests to illustrate the example (only the first and last should pass).
// specs codedescribe("CSS", function() { it("Div element of class test should be handled by .test", () => { const testdiv = document.getElementById("testdiv") m = window.getComputedStyle(testdiv).getPropertyValue("content"); expect(m).toEqual('".test"'); }); it("Div element of class test should be handled by div", () => { const testdiv = document.getElementById("testdiv") m = window.getComputedStyle(testdiv).getPropertyValue("content"); expect(m).toEqual('"div"'); }); it("Div element should be handled by .test", () => { const testdiv = document.getElementById("testdiv2") m = window.getComputedStyle(testdiv).getPropertyValue("content"); expect(m).toEqual('".test"'); }); it("Div element of class test should be handled by div", () => { const testdiv = document.getElementById("testdiv2") m = window.getComputedStyle(testdiv).getPropertyValue("content"); expect(m).toEqual('"div"'); });});// load jasmine htmlReporter(function() { var env = jasmine.getEnv(); env.addReporter(new jasmine.HtmlReporter()); env.execute();}());
.test { content: '.test';}div { content: 'div';}
<script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script><script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script><link href="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" rel="stylesheet"/><div class="test" id="testdiv">TestDiv</div><div id="testdiv2">TestDiv</div>
If I understand the question correctly, you're basically asking for a test (for your example) like this:
if -> Element.ComputedStyle.color = greenthen -> test passedelse -> test failed (you have CSS structure errors)
Obviously, the browser will interpret specificity correctly. So you're really testing if changes you made by adding/overriding CSS caused unintended visual consequences.
That seems pretty manual question to answer since you'll have to decide what each of those correct states is and then maintain the tests. If you go this route, I'd look at something like Backstop.js. Though CSS visual regression testing is REALLY complex so be careful how much you expect from it.
The Manual Way
Could you solve the problem somewhat manually by creating a SCSS variable that's usually transparent
? Then as you're adding/changing code add that variable and change the color to something like pink
that's really obvious? At this point, you should see where things override when you render the page.
If you're making a CSS framework, I'd test against your documentation since that should show you previous examples that would be overridden.
CSS Blocks
You may also want to look into the CSS Blocks API. It's not going to be a "test" exactly but the API provides scoping and compile errors that might help you catch some of those issues sooner than later.
Here's the pertinent part:
With CSS Blocks new resolution system, cascade conflicts will be caught for you before you even know they exist and you will never have to fight a specificity war ever again.
As you have mentioned you can achieve this with Selenium. In terms of methodology, if you're looking to maintain this long term then I would recommend following the Page Object Model. The official documentation on this is available here, and there are some other articles in various language here, here, and here.
Essentially what it boils down to is create classes or models for the pages (or page sections/components (as in a form that has multiple controls)), this class will then have properties/fields for each of the elements on the page that you want to interact with. The advantages of this approach are:
- A single place to change if you need to update a selector (maintainability)
- The underlaying code which can be ugly can be exposed through a nice interface that uses fluent syntax (readability)
How this looks (since you haven't specified a language I'll go with C#:
public class LoginPage{ // FindBy attributes should decorate each property to specify the selector public WebElement UsernameInput { get; set; } public WebElement PasswordInput { get; set; } public WebElement LoginButton { get; set; } public LoginPage() { ... } public LoginPage Load(this LoginPage page) { // code to navigate to the login page } public LoginPage EnterCredentials(this LoginPage page, string username, string password) { // code to fill out inputs } public HomePage Login(this LoginPage page) { // code to click login button } // Other methods}
How this looks when you use it:
HomePage homePage = new LoginPage() .Load() .EnterCredentials("user", "pass") .Login();// Now you can perform operations on the HomePage