summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/test/browser_inspector_pseudoclass-lock.js
blob: df924aab8c27d98af015b7d1c7a1b64540b6e0a6 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */
/* globals getHighlighterTestFrontWithoutToolbox */
"use strict";

// Test that locking the pseudoclass displays correctly in the ruleview

const PSEUDO = ":hover";
const TEST_URL =
  "data:text/html;charset=UTF-8," +
  "<head>" +
  "  <style>div {color:red;} div:hover {color:blue;}</style>" +
  "</head>" +
  "<body>" +
  '  <div id="parent-div">' +
  '    <div id="div-1">test div</div>' +
  '    <div id="div-2">test div2</div>' +
  "  </div>" +
  "</body>";

add_task(async function () {
  info("Creating the test tab and opening the rule-view");
  let { tab, toolbox, inspector, highlighterTestFront } =
    await openInspectorForURL(TEST_URL);

  info("Selecting the ruleview sidebar");
  inspector.sidebar.select("ruleview");

  const view = inspector.getPanel("ruleview").view;

  info("Selecting the test node");
  await selectNode("#div-1", inspector);

  await togglePseudoClass(inspector);
  await assertPseudoAddedToNode(
    inspector,
    highlighterTestFront,
    view,
    "#div-1"
  );

  await togglePseudoClass(inspector);
  await assertPseudoRemovedFromNode(highlighterTestFront, "#div-1");
  await assertPseudoRemovedFromView(
    inspector,
    highlighterTestFront,
    view,
    "#div-1"
  );

  await togglePseudoClass(inspector);
  await testNavigate(inspector);

  info("Toggle pseudo on the parent and ensure everything is toggled off");
  await selectNode("#parent-div", inspector);
  await togglePseudoClass(inspector);
  await assertPseudoRemovedFromNode(highlighterTestFront, "#div-1");
  await assertPseudoRemovedFromView(
    inspector,
    highlighterTestFront,
    view,
    "#div-1"
  );

  await togglePseudoClass(inspector);
  info("Assert pseudo is dismissed when toggling it on a sibling node");
  await selectNode("#div-2", inspector);
  await togglePseudoClass(inspector);
  await assertPseudoAddedToNode(
    inspector,
    highlighterTestFront,
    view,
    "#div-2"
  );
  const hasLock = await hasPseudoClassLock("#div-1", PSEUDO);
  ok(
    !hasLock,
    "pseudo-class lock has been removed for the previous locked node"
  );

  info("Destroying the toolbox");
  await toolbox.destroy();

  // As the toolbox get destroyed, we need to fetch a new test-actor
  highlighterTestFront = await getHighlighterTestFrontWithoutToolbox(tab);

  await assertPseudoRemovedFromNode(highlighterTestFront, "#div-1");
  await assertPseudoRemovedFromNode(highlighterTestFront, "#div-2");
});

async function togglePseudoClass(inspector) {
  info("Toggle the pseudoclass, wait for it to be applied");

  // Give the inspector panels a chance to update when the pseudoclass changes
  const onPseudo = inspector.selection.once("pseudoclass");
  const onRefresh = inspector.once("rule-view-refreshed");

  // Walker uses SDK-events so calling walker.once does not return a promise.
  const onMutations = once(inspector.walker, "mutations");

  await inspector.togglePseudoClass(PSEUDO);

  await onPseudo;
  await onRefresh;
  await onMutations;
}

async function testNavigate(inspector) {
  await selectNode("#parent-div", inspector);

  info("Make sure the pseudoclass is still on after navigating to a parent");

  ok(
    await hasPseudoClassLock("#div-1", PSEUDO),
    "pseudo-class lock is still applied after inspecting ancestor"
  );

  await selectNode("#div-2", inspector);

  info(
    "Make sure the pseudoclass is still set after navigating to a " +
      "non-hierarchy node"
  );
  ok(
    await hasPseudoClassLock("#div-1", PSEUDO),
    "pseudo-class lock is still on after inspecting sibling node"
  );

  await selectNode("#div-1", inspector);
}

async function assertPseudoAddedToNode(
  inspector,
  highlighterTestFront,
  ruleview,
  selector
) {
  info(
    "Make sure the pseudoclass lock is applied to " +
      selector +
      " and its ancestors"
  );

  let hasLock = await hasPseudoClassLock(selector, PSEUDO);
  ok(hasLock, "pseudo-class lock has been applied");
  hasLock = await hasPseudoClassLock("#parent-div", PSEUDO);
  ok(hasLock, "pseudo-class lock has been applied");
  hasLock = await hasPseudoClassLock("body", PSEUDO);
  ok(hasLock, "pseudo-class lock has been applied");

  info("Check that the ruleview contains the pseudo-class rule");
  const rules = ruleview.element.querySelectorAll(".ruleview-rule");
  is(
    rules.length,
    3,
    "rule view is showing 3 rules for pseudo-class locked div"
  );
  is(
    rules[1]._ruleEditor.rule.selectorText,
    "div:hover",
    "rule view is showing " + PSEUDO + " rule"
  );

  info("Show the highlighter on " + selector);
  const nodeFront = await getNodeFront(selector, inspector);
  await inspector.highlighters.showHighlighterTypeForNode(
    inspector.highlighters.TYPES.BOXMODEL,
    nodeFront
  );

  info("Check that the infobar selector contains the pseudo-class");
  const value = await highlighterTestFront.getHighlighterNodeTextContent(
    "box-model-infobar-pseudo-classes"
  );
  is(value, PSEUDO, "pseudo-class in infobar selector");
  await inspector.highlighters.hideHighlighterType(
    inspector.highlighters.TYPES.BOXMODEL
  );
}

async function assertPseudoRemovedFromNode(highlighterTestFront, selector) {
  info(
    "Make sure the pseudoclass lock is removed from #div-1 and its " +
      "ancestors"
  );

  let hasLock = await hasPseudoClassLock(selector, PSEUDO);
  ok(!hasLock, "pseudo-class lock has been removed");
  hasLock = await hasPseudoClassLock("#parent-div", PSEUDO);
  ok(!hasLock, "pseudo-class lock has been removed");
  hasLock = await hasPseudoClassLock("body", PSEUDO);
  ok(!hasLock, "pseudo-class lock has been removed");
}

async function assertPseudoRemovedFromView(
  inspector,
  highlighterTestFront,
  ruleview,
  selector
) {
  info("Check that the ruleview no longer contains the pseudo-class rule");
  const rules = ruleview.element.querySelectorAll(".ruleview-rule");
  is(rules.length, 2, "rule view is showing 2 rules after removing lock");

  const nodeFront = await getNodeFront(selector, inspector);
  await inspector.highlighters.showHighlighterTypeForNode(
    inspector.highlighters.TYPES.BOXMODEL,
    nodeFront
  );

  const value = await highlighterTestFront.getHighlighterNodeTextContent(
    "box-model-infobar-pseudo-classes"
  );
  is(value, "", "pseudo-class removed from infobar selector");
  await inspector.highlighters.hideHighlighterType(
    inspector.highlighters.TYPES.BOXMODEL
  );
}

/**
 * Check that an element currently has a pseudo-class lock.
 * @param {String} selector The node selector to get the pseudo-class from
 * @param {String} pseudo The pseudoclass to check for
 * @return {Promise<Boolean>}
 */
function hasPseudoClassLock(selector, pseudoClass) {
  return SpecialPowers.spawn(
    gBrowser.selectedBrowser,
    [selector, pseudoClass],
    (_selector, _pseudoClass) => {
      const element = content.document.querySelector(_selector);
      return InspectorUtils.hasPseudoClassLock(element, _pseudoClass);
    }
  );
}