Bug 1463674 - Add new test helpers for JsTerm; r=bgrins.
Since we are dealing with 2 versions of this component, we
introduce new helpers that abtracts how we get or assert
some values.
MozReview-Commit-ID: 1XNPcmwwsBj
--- a/devtools/client/sourceeditor/editor.js
+++ b/devtools/client/sourceeditor/editor.js
@@ -23,16 +23,17 @@ const VALID_KEYMAPS = new Set(["emacs",
// Maximum allowed margin (in number of lines) from top or bottom of the editor
// while shifting to a line which was initially out of view.
const MAX_VERTICAL_OFFSET = 3;
// Match @Scratchpad/N:LINE[:COLUMN] or (LINE[:COLUMN]) anywhere at an end of
// line in text selection.
const RE_SCRATCHPAD_ERROR = /(?:@Scratchpad\/\d+:|\()(\d+):?(\d+)?(?:\)|\n)/;
const RE_JUMP_TO_LINE = /^(\d+):?(\d+)?/;
+const AUTOCOMPLETE_MARK_CLASSNAME = "cm-auto-complete-shadow-text";
const Services = require("Services");
const EventEmitter = require("devtools/shared/event-emitter");
const { PrefObserver } = require("devtools/client/shared/prefs");
const { getClientCssProperties } = require("devtools/shared/fronts/css-properties");
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
const {LocalizationHelper} = require("devtools/shared/l10n");
@@ -1268,20 +1269,30 @@ Editor.prototype = {
if (this.config.autocomplete && Services.prefs.getBoolPref(AUTOCOMPLETE)) {
this.initializeAutoCompletion(this.config.autocompleteOpts);
} else {
this.destroyAutoCompletion();
}
},
+ getAutoCompletionText() {
+ const cm = editors.get(this);
+ const mark = cm.getAllMarks().find(m => m.className === AUTOCOMPLETE_MARK_CLASSNAME);
+ if (!mark) {
+ return "";
+ }
+
+ return mark.title || "";
+ },
+
setAutoCompletionText: function(text) {
const cursor = this.getCursor();
const cm = editors.get(this);
- const className = "cm-auto-complete-shadow-text";
+ const className = AUTOCOMPLETE_MARK_CLASSNAME;
cm.getAllMarks().forEach(mark => {
if (mark.className === className) {
mark.clear();
}
});
if (text) {
--- a/devtools/client/webconsole/test/mochitest/head.js
+++ b/devtools/client/webconsole/test/mochitest/head.js
@@ -346,33 +346,51 @@ function hasFocus(node) {
&& node.ownerDocument.hasFocus();
}
/**
* Set the value of the JsTerm and its caret position, and fire a completion request.
*
* @param {JsTerm} jsterm
* @param {String} value : The value to set the jsterm to.
- * @param {Integer} caretIndexOffset : A number that will be added to value.length
- * when setting the caret. A negative number will place the caret
- * in (end - offset) position. Default to 0 (caret set at the end)
+ * @param {Integer} caretPosition : The index where to place the cursor. A negative
+ * number will place the caret at (value.length - offset) position.
+ * Default to value.length (caret set at the end).
* @param {Integer} completionType : One of the following jsterm property
* - COMPLETE_FORWARD
* - COMPLETE_BACKWARD
* - COMPLETE_HINT_ONLY
* - COMPLETE_PAGEUP
* - COMPLETE_PAGEDOWN
* Will default to COMPLETE_HINT_ONLY.
* @returns {Promise} resolves when the jsterm is completed.
*/
-function jstermSetValueAndComplete(jsterm, value, caretIndexOffset = 0, completionType) {
- const {inputNode} = jsterm;
- inputNode.value = value;
- const index = value.length + caretIndexOffset;
- inputNode.setSelectionRange(index, index);
+function jstermSetValueAndComplete(
+ jsterm,
+ value,
+ caretPosition = value.length,
+ completionType
+) {
+ jsterm.setInputValue(value);
+
+ if (caretPosition < 0) {
+ caretPosition = value.length + caretPosition;
+ }
+
+ if (Number.isInteger(caretPosition)) {
+ if (jsterm.inputNode) {
+ const {inputNode} = jsterm;
+ inputNode.value = value;
+ inputNode.setSelectionRange(caretPosition, caretPosition);
+ }
+
+ if (jsterm.editor) {
+ jsterm.editor.setCursor(jsterm.editor.getPosition(caretPosition));
+ }
+ }
return jstermComplete(jsterm, completionType);
}
/**
* Fires a completion request on the jsterm with the specified completionType
*
* @param {JsTerm} jsterm
@@ -387,16 +405,130 @@ function jstermSetValueAndComplete(jster
*/
function jstermComplete(jsterm, completionType = jsterm.COMPLETE_HINT_ONLY) {
const updated = jsterm.once("autocomplete-updated");
jsterm.complete(completionType);
return updated;
}
/**
+ * Checks if the jsterm has the expected completion value.
+ *
+ * @param {JsTerm} jsterm
+ * @param {String} expectedValue
+ * @param {String} assertionInfo: Description of the assertion passed to `is`.
+ */
+function checkJsTermCompletionValue(jsterm, expectedValue, assertionInfo) {
+ const completionValue = getJsTermCompletionValue(jsterm);
+ if (completionValue === null) {
+ ok(false, "Couldn't retrieve the completion value");
+ }
+
+ info(`Expects "${expectedValue}", is "${completionValue}"`);
+
+ if (jsterm.completeNode) {
+ is(completionValue, expectedValue, assertionInfo);
+ } else {
+ // CodeMirror jsterm doesn't need to add prefix-spaces.
+ is(completionValue, expectedValue.trim(), assertionInfo);
+ }
+}
+
+/**
+ * Checks if the cursor on jsterm is at the expected position.
+ *
+ * @param {JsTerm} jsterm
+ * @param {Integer} expectedCursorIndex
+ * @param {String} assertionInfo: Description of the assertion passed to `is`.
+ */
+function checkJsTermCursor(jsterm, expectedCursorIndex, assertionInfo) {
+ if (jsterm.inputNode) {
+ const {selectionStart, selectionEnd} = jsterm.inputNode;
+ is(selectionStart, expectedCursorIndex, assertionInfo);
+ ok(selectionStart === selectionEnd);
+ } else {
+ is(jsterm.editor.getCursor().ch, expectedCursorIndex, assertionInfo);
+ }
+}
+
+/**
+ * Checks the jsterm value and the cursor position given an expected string containing
+ * a "|" to indicate the expected cursor position.
+ *
+ * @param {JsTerm} jsterm
+ * @param {String} expectedStringWithCursor:
+ * String with a "|" to indicate the expected cursor position.
+ * For example, this is how you assert an empty value with the focus "|",
+ * and this indicates the value should be "test" and the cursor at the
+ * end of the input: "test|".
+ * @param {String} assertionInfo: Description of the assertion passed to `is`.
+ */
+function checkJsTermValueAndCursor(jsterm, expectedStringWithCursor, assertionInfo) {
+ info(`Checking jsterm state: \n${expectedStringWithCursor}`);
+ if (!expectedStringWithCursor.includes("|")) {
+ ok(false,
+ `expectedStringWithCursor must contain a "|" char to indicate cursor position`);
+ }
+
+ const inputValue = expectedStringWithCursor.replace("|", "");
+ is(jsterm.getInputValue(), inputValue, "jsterm has expected value");
+ if (jsterm.inputNode) {
+ is(jsterm.inputNode.selectionStart, jsterm.inputNode.selectionEnd);
+ is(jsterm.inputNode.selectionStart, expectedStringWithCursor.indexOf("|"),
+ assertionInfo);
+ } else {
+ const lines = expectedStringWithCursor.split("\n");
+ const lineWithCursor = lines.findIndex(line => line.includes("|"));
+ const {ch, line} = jsterm.editor.getCursor();
+ is(line, lineWithCursor, assertionInfo + " - correct line");
+ is(ch, lines[lineWithCursor].indexOf("|"), assertionInfo + " - correct ch");
+ }
+}
+
+/**
+ * Returns the jsterm completion value, whether there's CodeMirror enabled or not.
+ *
+ * @param {JsTerm} jsterm
+ * @returns {String}
+ */
+function getJsTermCompletionValue(jsterm) {
+ if (jsterm.completeNode) {
+ return jsterm.completeNode.value;
+ }
+
+ if (jsterm.editor) {
+ return jsterm.editor.getAutoCompletionText();
+ }
+
+ return null;
+}
+
+/**
+ * Returns a boolean indicating if the jsterm is focused, whether there's CodeMirror
+ * enabled or not.
+ *
+ * @param {JsTerm} jsterm
+ * @returns {Boolean}
+ */
+function isJstermFocused(jsterm) {
+ const document = jsterm.outputNode.ownerDocument;
+ const documentIsFocused = document.hasFocus();
+
+ if (jsterm.inputNode) {
+ return document.activeElement == jsterm.inputNode && documentIsFocused;
+ }
+
+ if (jsterm.editor) {
+ return documentIsFocused && jsterm.editor.hasFocus();
+ }
+
+ return false;
+}
+
+/**
* Open the JavaScript debugger.
*
* @param object options
* Options for opening the debugger:
* - tab: the tab you want to open the debugger for.
* @return object
* A promise that is resolved once the debugger opens, or rejected if
* the open fails. The resolution callback is given one argument, an