As you may have noticed, we have recently upgraded the rich-text editor in Rally to use Google’s Closure editor. This is the same editor used in Gmail and Google Docs.
As we were testing the Closure editor within the Rally tool, we noticed that the toolbar icons are actually images coming from Google’s server. This isn’t really a problem, except that some of our customers are on-premise customers with no internet access. Therefore, if we didn’t fix this, all of these customers would have blank images for all of their toolbar icons. Not good.
The fix was easy, as you might have guessed (we simply hosted the icons in Rally). Perhaps more importantly though, we wanted to make sure that we’d never have to worry about this same problem in the future. So we wrote a test to make sure that none of the CSS that Rally uses fetches resources from a third-party server. I’ll walk you through the test. We made heavy use of the CSS Parser library in our test.
First, we got a list of the paths to all of our CSS files (method implementation not shown):
List<String> cssFiles = getCssFiles();
We then built up a HashMap (called selectorPropertiesMap) where the keys are all the CSS selectors that we use in our app, and the values are HashMaps. These “inner” HashMaps’ keys are the CSS properties (padding, margin, background, etc.) declared for a given CSS selector and the values are the CSS value for each property for the given selector.
The use of the “inner” HashMap is important because it means that for a given selector S, if CSS property P is declared with value V in CSS file F, but P is later overriden using the same selector S in a later file F1 with a new value V1, then this HashMap will also override the value of P with V1 just as a browser would do when it determines CSS specificity (when everything else is a tie, the last declared value wins).
HashMap<String, HashMap<String, String>> selectorPropertiesMap = newHashMap();
for (String cssFile : cssFiles) {
MockServletContext servletContext = new MockServletContext("file:" + System.getProperty("slm.dir", "."));
InputStream stream = servletContext.getResourceAsStream(cssFile);
InputSource source = new InputSource(new InputStreamReader(stream));
CSSOMParser parser = new CSSOMParser();
CSSStyleSheet stylesheet = parser.parseStyleSheet(source, null, null);
CSSRuleListImpl ruleList = (CSSRuleListImpl) stylesheet.getCssRules();
for (CSSRule rule : ruleList.getRules()) {
CSSStyleRuleImpl cssRule = (CSSStyleRuleImpl) rule;
List<Selector> selectorList = ((SelectorListImpl) cssRule.getSelectors()).getSelectors();
List<Property> properties = ((CSSStyleDeclarationImpl) cssRule.getStyle()).getProperties();
for (Selector selector : selectorList) {
for (Property property : properties) {
String propertyName = property.getName();
String propertyValue = property.getValue().toString();
HashMap<String, String> propertiesMap = selectorPropertiesMap.get(selector.toString());
if (propertiesMap == null) {
HashMap<String, String> newPropertiesMap = newHashMap();
newPropertiesMap.put(propertyName, propertyValue);
selectorPropertiesMap.put(selector.toString(), newPropertiesMap);
} else {
propertiesMap.put(propertyName, propertyValue);
}
}
}
}
Finally, we iterate over the value of every CSS property in our app and ensure that it is not pointing to a third-party resource:
for (HashMap<String, String> propertiesMap : selectorPropertiesMap.values()) {
for (String propertyValue : propertiesMap.values()) {
assertFalse(
propertyValue.matches(".*https?://.*"),
"The CSS rules may not contain static links. Violation found for " + propertyValue
);
}
}
So, there you have it. A fairly simple test that ensures that none of your CSS properties are pointing to third-party resources.

Or just do a pattern match on “.*https?://.*” and skip everything else. I suppose it is possible to get a false positive, but not likely. What does the CSS Parser Library buy you?
We needed to use the CSS Parser library so that the test would use the same logic that the browser uses to determine which CSS rules to apply to elements on the page.
.
Out of curiosity, I just did a quick pattern match search for “https?://” in all of the CSS files that we use. This search returned 260 occurrences in our code base. A large majority of these hits are in comments so we could conceivably figure out a way to ignore comments in CSS files when writing a test as you suggest. However, there are definitely a few places where we have http(s):// in CSS files that we use from third-party libraries such as Closure. Having a list of these “false positives” in a test (so that the test will pass) doesn’t feel right; if we add another third-party library in the future, we’d have to add all of the false positives from the new library to our test.
Truthfully, the other developer whom I wrote the test with and myself were really curious if we could write a test like the one we did so it was partially done out of curiosity too