summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/rules/test/browser_rules_completion-new-property_multiline.js
blob: ec939eafc844f3063c3066201c45a4d56ed95b66 (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
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
 http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

// Test the behaviour of the CSS autocomplete for CSS value displayed on
// multiple lines. Expected behavior is:
// - UP/DOWN should navigate in the input and not increment/decrement numbers
// - typing a new value should still trigger the autocomplete
// - UP/DOWN when the autocomplete popup is displayed should cycle through
//   suggestions

const LONG_CSS_VALUE =
  "transparent linear-gradient(0deg, blue 0%, white 5%, red 10%, blue 15%, " +
  "white 20%, red 25%, blue 30%, white 35%, red 40%, blue 45%, white 50%, " +
  "red 55%, blue 60%, white 65%, red 70%, blue 75%, white 80%, red 85%, " +
  "blue 90%, white 95% ) repeat scroll 0% 0%";

const EXPECTED_CSS_VALUE = LONG_CSS_VALUE.replace("95%", "95%, red");

const TEST_URI =
  `<style>
    .title {
      background: ${LONG_CSS_VALUE};
    }
  </style>
  <h1 class=title>Header</h1>`;

add_task(function* () {
  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
  let { inspector, view} = yield openRuleView();

  info("Selecting the test node");
  yield selectNode("h1", inspector);

  info("Focusing the property editable field");
  let rule = getRuleViewRuleEditor(view, 1).rule;
  let prop = rule.textProps[0];

  // Calculate offsets to click in the middle of the first box quad.
  let rect = prop.editor.valueSpan.getBoundingClientRect();
  let firstQuad = prop.editor.valueSpan.getBoxQuads()[0];
  // For a multiline value, the first quad left edge is not aligned with the
  // bounding rect left edge. The offsets expected by focusEditableField are
  // relative to the bouding rectangle, so we need to translate the x-offset.
  let x = firstQuad.bounds.left - rect.left + firstQuad.bounds.width / 2;
  // The first quad top edge is aligned with the bounding top edge, no
  // translation needed here.
  let y = firstQuad.bounds.height / 2;

  info("Focusing the css property editable value");
  let editor = yield focusEditableField(view, prop.editor.valueSpan, x, y);

  info("Moving the caret next to a number");
  let pos = editor.input.value.indexOf("0deg") + 1;
  editor.input.setSelectionRange(pos, pos);
  is(editor.input.value[editor.input.selectionStart - 1], "0",
    "Input caret is after a 0");

  info("Check that UP/DOWN navigates in the input, even when next to a number");
  EventUtils.synthesizeKey("VK_DOWN", {}, view.styleWindow);
  ok(editor.input.selectionStart !== pos, "Input caret moved");
  is(editor.input.value, LONG_CSS_VALUE, "Input value was not decremented.");

  info("Move the caret to the end of the gradient definition.");
  pos = editor.input.value.indexOf("95%") + 3;
  editor.input.setSelectionRange(pos, pos);

  info("Sending \", re\" to the editable field.");
  for (let key of ", re") {
    yield synthesizeKeyForAutocomplete(key, editor, view.styleWindow);
  }

  info("Check the autocomplete can still be displayed.");
  ok(editor.popup && editor.popup.isOpen, "Autocomplete popup is displayed.");
  is(editor.popup.selectedIndex, 0,
    "Autocomplete has an item selected by default");

  let item = editor.popup.getItemAtIndex(editor.popup.selectedIndex);
  is(item.label, "rebeccapurple",
    "Check autocomplete displays expected value.");

  info("Check autocomplete suggestions can be cycled using UP/DOWN arrows.");

  yield synthesizeKeyForAutocomplete("VK_DOWN", editor, view.styleWindow);
  ok(editor.popup.selectedIndex, 1, "Using DOWN cycles autocomplete values.");
  yield synthesizeKeyForAutocomplete("VK_DOWN", editor, view.styleWindow);
  ok(editor.popup.selectedIndex, 2, "Using DOWN cycles autocomplete values.");
  yield synthesizeKeyForAutocomplete("VK_UP", editor, view.styleWindow);
  is(editor.popup.selectedIndex, 1, "Using UP cycles autocomplete values.");
  item = editor.popup.getItemAtIndex(editor.popup.selectedIndex);
  is(item.label, "red", "Check autocomplete displays expected value.");

  info("Select the background-color suggestion with a mouse click.");
  let onRuleviewChanged = view.once("ruleview-changed");
  let onSuggest = editor.once("after-suggest");

  let node = editor.popup._list.childNodes[editor.popup.selectedIndex];
  EventUtils.synthesizeMouseAtCenter(node, {}, editor.popup._window);

  view.throttle.flush();
  yield onSuggest;
  yield onRuleviewChanged;

  is(editor.input.value, EXPECTED_CSS_VALUE,
    "Input value correctly autocompleted");

  info("Press ESCAPE to leave the input.");
  onRuleviewChanged = view.once("ruleview-changed");
  EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow);
  yield onRuleviewChanged;
});

/**
 * Send the provided key to the currently focused input of the provided window.
 * Wait for the editor to emit "after-suggest" to make sure the autocompletion
 * process is finished.
 *
 * @param {String} key
 *        The key to send to the input.
 * @param {InplaceEditor} editor
 *        The inplace editor which owns the focused input.
 * @param {Window} win
 *        Window in which the key event will be dispatched.
 */
function* synthesizeKeyForAutocomplete(key, editor, win) {
  let onSuggest = editor.once("after-suggest");
  EventUtils.synthesizeKey(key, {}, win);
  yield onSuggest;
}