summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/markup/test/helper_style_attr_test_runner.js
blob: 029651cf74b0be10b103f3c5cd1f6c824da58b37 (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
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint no-unused-vars: [2, {"vars": "local"}] */
/* import-globals-from head.js */
"use strict";

/**
 * Perform an style attribute edition and autocompletion test in the test
 * url, for #node14. Test data should be an
 * array of arrays structured as follows :
 *  [
 *    what key to press,
 *    expected input box value after keypress,
 *    expected input.selectionStart,
 *    expected input.selectionEnd,
 *    is popup expected to be open ?
 *  ]
 *
 * The test will start by adding a new attribute on the node, and then send each
 * key specified in the testData. The last item of this array should leave the
 * new attribute editor, either by committing or cancelling the edit.
 *
 * @param {InspectorPanel} inspector
 * @param {Array} testData
 *        Array of arrays representing the characters to type for the new
 *        attribute as well as the expected state at each step
 */
async function runStyleAttributeAutocompleteTests(inspector, testData) {
  info("Expand all markup nodes");
  await inspector.markup.expandAll();

  info("Select #node14");
  const container = await focusNode("#node14", inspector);

  info("Focus and open the new attribute inplace-editor");
  const attr = container.editor.newAttr;
  attr.focus();
  EventUtils.sendKey("return", inspector.panelWin);
  const editor = inplaceEditor(attr);

  for (let i = 0; i < testData.length; i++) {
    const data = testData[i];

    // Skip empty key.
    if (!data.length) {
      continue;
    }

    // Expect a markupmutation event at the last iteration since that's when the
    // attribute is actually created.
    const onMutation =
      i === testData.length - 1 ? inspector.once("markupmutation") : null;

    info(`Entering test data ${i}: ${data[0]}, expecting: [${data[1]}]`);
    await enterData(data, editor, inspector);

    info(`Test data ${i} entered. Checking state.`);
    await checkData(data, editor, inspector);

    await onMutation;
  }

  // Undoing the action will remove the new attribute, so make sure to wait for
  // the markupmutation event here again.
  const onMutation = inspector.once("markupmutation");
  while (inspector.markup.undo.canUndo()) {
    await undoChange(inspector);
  }
  await onMutation;
}

/**
 * Process a test data entry.
 * @param {Array} data
 *        test data - click or key - to enter
 * @param {InplaceEditor} editor
 * @param {InspectorPanel} inspector
 * @return {Promise} promise that will resolve when the test data has been
 *         applied
 */
function enterData(data, editor, inspector) {
  const key = data[0];

  if (/^click_[0-9]+$/.test(key)) {
    const suggestionIndex = parseInt(key.split("_")[1], 10);
    return clickOnSuggestion(suggestionIndex, editor);
  }

  return sendKey(key, editor, inspector);
}

function clickOnSuggestion(index, editor) {
  return new Promise(resolve => {
    info("Clicking on item " + index + " in the list");
    editor.once("after-suggest", () => executeSoon(resolve));
    editor.popup._list.childNodes[index].click();
  });
}

function sendKey(key, editor, inspector) {
  return new Promise(resolve => {
    if (/(down|left|right|back_space|return)/gi.test(key)) {
      info("Adding event listener for down|left|right|back_space|return keys");
      editor.input.addEventListener("keypress", function onKeypress() {
        if (editor.input) {
          editor.input.removeEventListener("keypress", onKeypress);
        }
        executeSoon(resolve);
      });
    } else {
      editor.once("after-suggest", () => executeSoon(resolve));
    }

    EventUtils.synthesizeKey(key, {}, inspector.panelWin);
  });
}

/**
 * Verify that the inplace editor is in the expected state for the provided
 * test data.
 */
async function checkData(data, editor, inspector) {
  const [, completion, selStart, selEnd, popupOpen] = data;

  if (selEnd != -1) {
    is(editor.input.value, completion, "Completed value is correct");
    is(
      editor.input.selectionStart,
      selStart,
      "Selection start position is correct"
    );
    is(editor.input.selectionEnd, selEnd, "Selection end position is correct");
    is(
      editor.popup.isOpen,
      popupOpen,
      "Popup is " + (popupOpen ? "open" : "closed")
    );
  } else {
    const nodeFront = await getNodeFront("#node14", inspector);
    const container = getContainerForNodeFront(nodeFront, inspector);
    const attr = container.editor.attrElements
      .get("style")
      .querySelector(".editable");
    is(
      attr.textContent,
      completion,
      "Correct value is persisted after pressing Enter"
    );
  }
}