Bug 1288165 - browser_parsable_css.js should fail if entries in the whitelist of the test are unused. r?gijs draft
authorJared Wein <jwein@mozilla.com>
Wed, 20 Jul 2016 18:10:44 -0700
changeset 390294 8d019be1390327bce765c679adc9f4e1d5692852
parent 390076 afbd03d4a5a1fef519c3f36bea67a5dfcd690707
child 525979 146132140c9a0ab13f005b54e1de3b6d7017e0b9
push id23648
push userjwein@mozilla.com
push dateThu, 21 Jul 2016 01:14:24 +0000
reviewersgijs
bugs1288165
milestone50.0a1
Bug 1288165 - browser_parsable_css.js should fail if entries in the whitelist of the test are unused. r?gijs MozReview-Commit-ID: EHwD6clWNnf
browser/base/content/test/general/browser_parsable_css.js
--- a/browser/base/content/test/general/browser_parsable_css.js
+++ b/browser/base/content/test/general/browser_parsable_css.js
@@ -4,64 +4,74 @@
 /* This list allows pre-existing or 'unfixable' CSS issues to remain, while we
  * detect newly occurring issues in shipping CSS. It is a list of objects
  * specifying conditions under which an error should be ignored.
  *
  * Every property of the objects in it needs to consist of a regular expression
  * matching the offending error. If an object has multiple regex criteria, they
  * ALL need to match an error in order for that error not to cause a test
  * failure. */
-const kWhitelist = [
+let whitelist = [
   // CodeMirror is imported as-is, see bug 1004423.
-  {sourceName: /codemirror\.css$/i},
+  {sourceName: /codemirror\.css$/i,
+   isFromDevTools: true},
   // PDFjs is futureproofing its pseudoselectors, and those rules are dropped.
   {sourceName: /web\/viewer\.css$/i,
-   errorMessage: /Unknown pseudo-class.*(fullscreen|selection)/i},
+   errorMessage: /Unknown pseudo-class.*(fullscreen|selection)/i,
+   isFromDevTools: false},
   // Tracked in bug 1004428.
-  {sourceName: /aboutaccounts\/(main|normalize)\.css$/i},
+  {sourceName: /aboutaccounts\/(main|normalize)\.css$/i,
+    isFromDevTools: false},
   // TokBox SDK assets, see bug 1032469.
-  {sourceName: /loop\/.*sdk-content\/.*\.css$/i},
+  {sourceName: /loop\/.*sdk-content\/.*\.css$/i,
+    isFromDevTools: false},
   // Loop standalone client CSS uses placeholder cross browser pseudo-element
   {sourceName: /loop\/.*\.css$/i,
-   errorMessage: /Unknown pseudo-class.*placeholder/i},
+   errorMessage: /Unknown pseudo-class.*placeholder/i,
+   isFromDevTools: false},
   {sourceName: /loop\/.*shared\/css\/common.css$/i,
-   errorMessage: /Unknown property .user-select./i},
+   errorMessage: /Unknown property .user-select./i,
+   isFromDevTools: false},
   // Highlighter CSS uses a UA-only pseudo-class, see bug 985597.
   {sourceName: /highlighters\.css$/i,
-   errorMessage: /Unknown pseudo-class.*moz-native-anonymous/i},
+   errorMessage: /Unknown pseudo-class.*moz-native-anonymous/i,
+   isFromDevTools: true},
   // Responsive Design Mode CSS uses a UA-only pseudo-class, see Bug 1241714.
   {sourceName: /responsive-ua\.css$/i,
-   errorMessage: /Unknown pseudo-class.*moz-dropdown-list/i},
+   errorMessage: /Unknown pseudo-class.*moz-dropdown-list/i,
+   isFromDevTools: true},
 ];
 
 var moduleLocation = gTestPath.replace(/\/[^\/]*$/i, "/parsingTestHelpers.jsm");
 var {generateURIsFromDirTree} = Cu.import(moduleLocation, {});
 
 // Add suffix to stylesheets' URI so that we always load them here and
 // have them parsed. Add a random number so that even if we run this
 // test multiple times, it would be unlikely to affect each other.
 const kPathSuffix = "?always-parse-css-" + Math.random();
 
 /**
  * Check if an error should be ignored due to matching one of the whitelist
- * objects defined in kWhitelist
+ * objects defined in whitelist
  *
  * @param aErrorObject the error to check
  * @return true if the error should be ignored, false otherwise.
  */
 function ignoredError(aErrorObject) {
-  for (let whitelistItem of kWhitelist) {
+  for (let whitelistItem of whitelist) {
     let matches = true;
-    for (let prop in whitelistItem) {
-      if (!whitelistItem[prop].test(aErrorObject[prop] || "")) {
+    for (let prop of ["sourceName", "errorMessage"]) {
+      if (whitelistItem.hasOwnProperty(prop) &&
+          !whitelistItem[prop].test(aErrorObject[prop] || "")) {
         matches = false;
         break;
       }
     }
     if (matches) {
+      whitelistItem.used = true;
       return true;
     }
   }
   return false;
 }
 
 function once(target, name) {
   return new Promise((resolve, reject) => {
@@ -145,17 +155,17 @@ function convertToChromeUri(fileUri) {
 
 function messageIsCSSError(msg) {
   // Only care about CSS errors generated by our iframe:
   if ((msg instanceof Ci.nsIScriptError) &&
       msg.category.includes("CSS") &&
       msg.sourceName.endsWith(kPathSuffix)) {
     let sourceName = msg.sourceName.slice(0, -kPathSuffix.length);
     let msgInfo = { sourceName, errorMessage: msg.errorMessage };
-    // Check if this error is whitelisted in kWhitelist
+    // Check if this error is whitelisted in whitelist
     if (!ignoredError(msgInfo)) {
       ok(false, `Got error message for ${sourceName}: ${msg.errorMessage}`);
       return true;
     }
     info(`Ignored error for ${sourceName} because of filter.`);
   }
   return false;
 }
@@ -229,16 +239,25 @@ add_task(function* checkAllTheCSS() {
   yield Promise.all(allPromises);
 
   let messages = Services.console.getMessageArray();
   // Count errors (the test output will list actual issues for us, as well
   // as the ok(false) in messageIsCSSError.
   let errors = messages.filter(messageIsCSSError);
   is(errors.length, 0, "All the styles (" + allPromises.length + ") loaded without errors.");
 
+  // Confirm that all whitelist rules have been used.
+  for (let item of whitelist) {
+    if (!item.used && isDevtools == item.isFromDevTools) {
+      ok(false, "Unused whitelist item. " +
+                (item.sourceName ? " sourceName: " + item.sourceName : "") +
+                (item.errorMessage ? " errorMessage: " + item.errorMessage : ""));
+    }
+  }
+
   // Clean up to avoid leaks:
   iframe.remove();
   doc.head.innerHTML = '';
   doc = null;
   iframe = null;
   windowless.close();
   windowless = null;
 });