summaryrefslogtreecommitdiffstats
path: root/devtools/shared/tests/unit/test_css-properties-db.js
blob: 108650a3ed4981be2c7cae1443fcaf5642b7a52b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

/**
 * Test that the devtool's client-side CSS properties database is in sync with the values
 * on the platform (in Nightly only). If they are not, then `mach devtools-css-db` needs
 * to be run to make everything up to date. Nightly, aurora, beta, and release may have
 * different CSS properties and values. These are based on preferences and compiler flags.
 *
 * This test broke uplifts as the database needed to be regenerated every uplift. The
 * combination of compiler flags and preferences means that it's too difficult to
 * statically determine which properties are enabled between Firefox releases.
 *
 * Because of these difficulties, the database only needs to be up to date with Nightly.
 * It is a fallback that is only used if the remote debugging protocol doesn't support
 * providing a CSS database, so it's ok if the provided properties don't exactly match
 * the inspected target in this particular case.
 */

"use strict";

const DOMUtils = Components.classes["@mozilla.org/inspector/dom-utils;1"]
                           .getService(Components.interfaces.inIDOMUtils);

const {PSEUDO_ELEMENTS, CSS_PROPERTIES} = require("devtools/shared/css/generated/properties-db");
const {generateCssProperties} = require("devtools/server/actors/css-properties");

function run_test() {
  const propertiesErrorMessage = "If this assertion fails, then the client side CSS " +
                                 "properties list in devtools is out of sync with the " +
                                 "CSS properties on the platform. To fix this " +
                                 "assertion run `mach devtools-css-db` to re-generate " +
                                 "the client side properties.";

  // Check that the platform and client match for pseudo elements.
  deepEqual(PSEUDO_ELEMENTS, DOMUtils.getCSSPseudoElementNames(), `The pseudo elements ` +
            `match on the client and platform. ${propertiesErrorMessage}`);

  /**
   * Check that the platform and client match for the details on their CSS properties.
   * Enumerate each property to aid in debugging.
   */
  const platformProperties = generateCssProperties();

  for (let propertyName in CSS_PROPERTIES) {
    const platformProperty = platformProperties[propertyName];
    const clientProperty = CSS_PROPERTIES[propertyName];
    const deepEqual = isJsonDeepEqual(platformProperty, clientProperty);

    if (deepEqual) {
      ok(true, `The static database and platform match for "${propertyName}".`);
    } else {
      const prefMessage = `The static database and platform do not match ` +
                          `for "${propertyName}".`;
      if (getPreference(propertyName) === false) {
        ok(true, `${prefMessage} However, there is a preference for disabling this ` +
                 `property on the current build.`);
      } else {
        ok(false, `${prefMessage} ${propertiesErrorMessage}`);
      }
    }
  }

  /**
   * Check that the list of properties on the platform and client are the same. If
   * they are not, check that there may be preferences that are disabling them on the
   * target platform.
   */
  const mismatches = getKeyMismatches(platformProperties, CSS_PROPERTIES)
    // Filter out OS-specific properties.
    .filter(name => name && name.indexOf("-moz-osx-") === -1);

  if (mismatches.length === 0) {
    ok(true, "No client and platform CSS property database mismatches were found.");
  }

  mismatches.forEach(propertyName => {
    ok(false, `The static database and platform do not agree on the property ` +
              `"${propertyName}" ${propertiesErrorMessage}`);
  });
}

/**
 * Check JSON-serializable objects for deep equality.
 */
function isJsonDeepEqual(a, b) {
  // Handle primitives.
  if (a === b) {
    return true;
  }

  // Handle arrays.
  if (Array.isArray(a) && Array.isArray(b)) {
    if (a.length !== b.length) {
      return false;
    }
    for (let i = 0; i < a.length; i++) {
      if (!isJsonDeepEqual(a[i], b[i])) {
        return false;
      }
    }
    return true;
  }

  // Handle objects
  if (typeof a === "object" && typeof b === "object") {
    for (let key in a) {
      if (!isJsonDeepEqual(a[key], b[key])) {
        return false;
      }
    }

    return Object.keys(a).length === Object.keys(b).length;
  }

  // Not something handled by these cases, therefore not equal.
  return false;
}

/**
 * Take the keys of two objects, and return the ones that don't match.
 *
 * @param {Object} a
 * @param {Object} b
 * @return {Array} keys
 */
function getKeyMismatches(a, b) {
  const aNames = Object.keys(a);
  const bNames = Object.keys(b);
  const aMismatches = aNames.filter(key => !bNames.includes(key));
  const bMismatches = bNames.filter(key => {
    return !aNames.includes(key) && !aMismatches.includes(key);
  });

  return aMismatches.concat(bMismatches);
}