/
githubmirror
/
brackets
Обзор
Документация
Войти
/
githubmirror
/
brackets
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/extensions/default/JavaScriptCodeHints/unittests.js
1 837 строк
78 KB
Subhash Jha
Language Server Protocol Support for Brackets (#14606)
02 апр 2019, 12:35
02 апр 2019, 12:35
df7aea4
Код
Авторство
О чём код?
/* * Copyright (c) 2013 - present Adobe Systems Incorporated. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ /*jslint regexp: true */ /*global describe, it, xit, expect, beforeEach, afterEach, waitsFor, runs, waitsForDone, waitsForFail, beforeFirst, afterLast */ define(function (require, exports, module) { "use strict"; var Commands = brackets.getModule("command/Commands"), CommandManager = brackets.getModule("command/CommandManager"), MainViewManager = brackets.getModule("view/MainViewManager"), DocumentManager = brackets.getModule("document/DocumentManager"), EditorManager = brackets.getModule("editor/EditorManager"), FileSystem = brackets.getModule("filesystem/FileSystem"), FileUtils = brackets.getModule("file/FileUtils"), PreferencesManager = brackets.getModule("preferences/PreferencesManager"), SpecRunnerUtils = brackets.getModule("spec/SpecRunnerUtils"), JSCodeHints = require("main"), Preferences = brackets.getModule("JSUtils/Preferences"), ScopeManager = brackets.getModule("JSUtils/ScopeManager"), HintUtils = brackets.getModule("JSUtils/HintUtils"), HintUtils2 = require("HintUtils2"), ParameterHintProvider = require("ParameterHintsProvider").JSParameterHintsProvider, phProvider = new ParameterHintProvider(); var extensionPath = FileUtils.getNativeModuleDirectoryPath(module), testPath = extensionPath + "/unittest-files/basic-test-files/file1.js", testHtmlPath = extensionPath + "/unittest-files/basic-test-files/index.html", testDoc = null, testEditor, preTestText; CommandManager.register("test-file-open", Commands.FILE_OPEN, function (fileInfo) { // Register a command for FILE_OPEN, which the jump to def code will call return DocumentManager.getDocumentForPath(fileInfo.fullPath).done(function (doc) { MainViewManager._edit(MainViewManager.ACTIVE_PANE, doc); }); }); describe("JavaScript Code Hinting", function () { // Helper function for testing cursor position function fixPos(pos) { if (!("sticky" in pos)) { pos.sticky = null; } return pos; } /* * Ask provider for hints at current cursor position; expect it to * return some * * @param {Object} provider - a CodeHintProvider object * @param {string} key - the charCode of a key press that triggers the * CodeHint provider * @return {boolean} - whether the provider has hints in the context of * the test editor */ function expectHints(provider, key) { if (key === undefined) { key = null; } expect(provider.hasHints(testEditor, key)).toBe(true); return provider.getHints(null); } /* * Ask provider for hints at current cursor position; expect it NOT to * return any * * @param {Object} provider - a CodeHintProvider object * @param {string} key - the charCode of a key press that triggers the * CodeHint provider */ function expectNoHints(provider, key) { if (key === undefined) { key = null; } expect(provider.hasHints(testEditor, key)).toBe(false); } /* * Return the index at which hint occurs in hintList * * @param {Array.<Object>} hintList - the list of hints * @param {string} hint - the hint to search for * @return {number} - the index into hintList at which the hint occurs, * or -1 if it does not */ function _indexOf(hintList, hint) { var index = -1, counter = 0; for (counter; counter < hintList.length; counter++) { if (hintList[counter].data("token").value === hint) { index = counter; break; } } return index; } /* * Wait for a hint response object to resolve, then apply a callback * to the result * * @param {Object + jQuery.Deferred} hintObj - a hint response object, * possibly deferred * @param {Function} callback - the callback to apply to the resolved * hint response object */ function _waitForHints(hintObj, callback) { var complete = false, hintList = null; if (hintObj.hasOwnProperty("hints")) { complete = true; hintList = hintObj.hints; } else { hintObj.done(function (obj) { complete = true; hintList = obj.hints; }); } waitsFor(function () { return complete; }, "Expected hints did not resolve", 3000); runs(function () { callback(hintList); }); } /* * Test if hints should be closed or not closed at a given position. * * @param {Object} provider - a CodeHintProvider object * @param {Object + jQuery.Deferred} hintObj - a hint response object, * possibly deferred * @param {line: number, ch: number} newPos - new position to move to * after hints are received. * @param {boolean} expectedValue - true if hints should close, * false otherwise. */ function expectCloseHints(provider, hintObj, newPos, expectedValue) { _waitForHints(hintObj, function (hintList) { testEditor.setCursorPos(newPos); expect(provider.shouldCloseHints(JSCodeHints.getSession())).toBe(expectedValue); }); } /* * Expect a given list of hints to be absent from a given hint * response object * * @param {Object + jQuery.Deferred} hintObj - a hint response object, * possibly deferred * @param {Array.<string>} absentHints - a list of hints that should not * be present in the hint response */ function hintsAbsent(hintObj, absentHints) { _waitForHints(hintObj, function (hintList) { expect(hintList).toBeTruthy(); absentHints.forEach(function (absentHint) { expect(_indexOf(hintList, absentHint)).toBe(-1); }); }); } /* * Expect a given list of hints to be present in a given hint * response object * * @param {Object + jQuery.Deferred} hintObj - a hint response object, * possibly deferred * @param {Array.<string>} expectedHints - a list of hints that should be * present in the hint response */ function hintsPresent(hintObj, expectedHints) { _waitForHints(hintObj, function (hintList) { expect(hintList).toBeTruthy(); expectedHints.forEach(function (expectedHint) { expect(_indexOf(hintList, expectedHint)).not.toBe(-1); }); }); } /* * Expect a given list of hints to be present in the given order in a * given hint response object * * @param {Object + jQuery.Deferred} hintObj - a hint response object, * possibly deferred * @param {Array.<string>} expectedHints - a list of hints that should be * present in the given order in the hint response */ function hintsPresentOrdered(hintObj, expectedHints) { var prevIndex = -1, currIndex; _waitForHints(hintObj, function (hintList) { expect(hintList).toBeTruthy(); expectedHints.forEach(function (expectedHint) { currIndex = _indexOf(hintList, expectedHint); expect(currIndex).toBeGreaterThan(prevIndex); prevIndex = currIndex; }); }); } /* * Expect a given list of hints to be present in a given hint * response object, and no more. * * @param {Object + jQuery.Deferred} hintObj - a hint response object, * possibly deferred * @param {Array.<string>} expectedHints - a list of hints that should be * present in the hint response, and no more. */ function hintsPresentExact(hintObj, expectedHints) { _waitForHints(hintObj, function (hintList) { expect(hintList).toBeTruthy(); expect(hintList.length).toBe(expectedHints.length); expectedHints.forEach(function (expectedHint, index) { expect(hintList[index].data("token").value).toBe(expectedHint); }); }); } /** * Find the index of a string in a list of hints. * @param {Array} hintList - the list of hints * @param {string} hintSelection - the string represenation of the hint * to find the index of * @return {number} the index of the hint corresponding to the hintSelection */ function findHint(hintList, hintSelection) { var i, l; for (i = 0, l = hintList.length; i < l; ++i) { var current = hintList[i].data("token"); if (hintSelection === current.value) { return i; } } return -1; } /* * Simulation of selection of a particular hint in a hint list. * Presumably results in side effects in the hint provider's * current editor context. * * @param {Object} provider - a CodeHint provider object * @param {Object} hintObj - a hint response object from that provider, * possibly deferred * @param {string} hintSelection - the hint to select */ function selectHint(provider, hintObj, hintSelection) { expectHints(provider); _waitForHints(hintObj, function (hintList) { expect(hintList).toBeTruthy(); var index = findHint(hintList, hintSelection); expect(hintList[index].data("token")).toBeTruthy(); expect(provider.insertHint(hintList[index])).toBe(false); }); } /** * Wait for the editor to change positions, such as after a jump to * definition has been triggered. Will timeout after 3 seconds * * @param {{line:number, ch:number}} oldLocation - the original line/col * @param {Function} callback - the callback to apply once the editor has changed position */ function _waitForJump(jumpPromise, callback) { var cursor = null, complete = false; jumpPromise.done(function () { complete = true; }); waitsFor(function () { var activeEditor = EditorManager.getActiveEditor(); cursor = activeEditor.getCursorPos(); return complete; }, "Expected jump did not occur", 3000); runs(function () { callback(cursor); }); } /** * Trigger a jump to definition, and verify that the editor jumped to * the expected location. The new location is the variable definition * or function definition of the variable or function at the current * cursor location. Jumping to the new location will cause a new editor * to be opened or open an existing editor. * * @param {{line:number, ch:number, file:string}} expectedLocation - the * line, column, and optionally the new file the editor should jump to. If the * editor is expected to stay in the same file, then file may be omitted. */ function editorJumped(expectedLocation) { var jumpPromise = JSCodeHints.handleJumpToDefinition(); _waitForJump(jumpPromise, function (newCursor) { expect(newCursor.line).toBe(expectedLocation.line); expect(newCursor.ch).toBe(expectedLocation.ch); if (expectedLocation.file) { var activeEditor = EditorManager.getActiveEditor(); expect(activeEditor.document.file.name).toBe(expectedLocation.file); } }); } /** * Verify there is no parameter hint at the current cursor. */ function expectNoParameterHint() { var requestStatus = undefined; runs(function () { var request = phProvider._getParameterHint(); request.fail(function (status) { requestStatus = status; }); waitsForFail(request, "ParameterHints"); }); runs(function () { expect(requestStatus).toBe(null); }); } /** * Verify the parameter hint is not visible. */ function expectParameterHintClosed() { expect(phProvider.isHintDisplayed()).toBe(false); } /** * Show a function hint based on the code at the cursor. Verify the * hint matches the passed in value. * * @param {Array<{name: string, type: string, isOptional: boolean}>} * expectedParams - array of records, where each element of the array * describes a function parameter. If null, then no hint is expected. * @param {number} expectedParameter - the parameter at cursor. */ function expectParameterHint(expectedParams, expectedParameter) { var requestHints = undefined, request = null; function expectHint(hint) { var params = hint.parameters, n = params.length, i; // compare params to expected params expect(params.length).toBe(expectedParams.length); expect(hint.currentIndex).toBe(expectedParameter); for (i = 0; i < n; i++) { expect(params[i].name).toBe(expectedParams[i].name); expect(params[i].type).toBe(expectedParams[i].type); if (params[i].isOptional) { expect(expectedParams[i].isOptional).toBeTruthy(); } else { expect(expectedParams[i].isOptional).toBeFalsy(); } } } runs(function () { request = phProvider._getParameterHint(); if (expectedParams === null) { request.fail(function (result) { requestHints = result; }); waitsForFail(request, "ParameterHints"); } else { request.done(function (result) { requestHints = result; }); waitsForDone(request, "ParameterHints"); } }); if (expectedParams === null) { expect(requestHints).toBe(null); } else { expectHint(requestHints); } } function setupTest(path, primePump) { // FIXME: primePump argument ignored even though used below DocumentManager.getDocumentForPath(path).done(function (doc) { testDoc = doc; }); waitsFor(function () { return testDoc !== null; }, "Unable to open test document", 10000); // create Editor instance (containing a CodeMirror instance) runs(function () { testEditor = SpecRunnerUtils.createMockEditorForDocument(testDoc); preTestText = testDoc.getText(); waitsForDone(ScopeManager._readyPromise()); waitsForDone(ScopeManager._maybeReset(JSCodeHints.getSession(), testDoc, true)); }); } function tearDownTest() { // Restore the pre-test version of the text here because the hinter // will update the contents of the previous document in tern. testDoc.setText(preTestText); // The following call ensures that the document is reloaded // from disk before each test MainViewManager._closeAll(MainViewManager.ALL_PANES); SpecRunnerUtils.destroyMockEditor(testDoc); testEditor = null; testDoc = null; } describe("JavaScript Code Hinting Basic", function () { beforeFirst(function () { brackets._configureJSCodeHints({ noReset: true }); }); afterLast(function () { brackets._configureJSCodeHints({ noReset: false }); }); beforeEach(function () { setupTest(testPath, false); }); afterEach(function () { tearDownTest(); }); it("should not list hints in string literal", function () { testEditor.setCursorPos({ line: 20, ch: 22 }); expectNoHints(JSCodeHints.jsHintProvider); }); it("should list declared variable and function names in outer scope", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["A2", "A3", "funB", "A1"]); }); it("should filter hints by query", function () { testEditor.setCursorPos({ line: 5, ch: 10 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["A1", "A2", "A3"]); hintsAbsent(hintObj, ["funB"]); }); it("should list keywords", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["break", "case", "catch"]); }); xit("should list explicitly defined globals from JSLint annotations", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["brackets", "$"]); }); xit("should list implicitly defined globals from JSLint annotations", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["alert", "console", "confirm", "navigator", "window", "frames"]); }); it("should NOT list implicitly defined globals from missing JSLint annotations", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsAbsent(hintObj, ["ActiveXObject", "CScript", "VBArray"]); }); it("should NOT list explicitly defined globals from JSLint annotations in other files", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsAbsent(hintObj, ["crazyGlobal", "anotherCrazyGlobal"]); }); it("should NOT list implicitly defined globals from JSLint annotations in other files", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsAbsent(hintObj, ["spawn", "version", "toint32"]); }); it("should list literal constants", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["null", "undefined", "true", "false"]); }); it("should NOT list variables, function names and parameter names out of scope", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsAbsent(hintObj, ["paramB2", "paramB1"]); }); it("should NOT list variables, function names and parameter names in other files", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsAbsent(hintObj, ["E1", "E2"]); }); it("should NOT list property names on value lookups", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsAbsent(hintObj, ["propA", "propB", "propC"]); }); it("should list declared variable, function and parameter names in inner scope", function () { testEditor.setCursorPos({ line: 12, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["B1", "B2", "funC", "paramB1", "paramB2", "funB", "A1", "A2", "A3"]); }); xit("should list string literals that occur in the file", function () { testEditor.setCursorPos({ line: 12, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["use strict"]); }); it("should NOT list string literals from other files", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsAbsent(hintObj, ["a very nice string"]); }); it("should list property names that have been declared in the file", function () { testEditor.setCursorPos({ line: 17, ch: 11 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["propB"]); }); it("should list identifier names that occur in other files", function () { testEditor.setCursorPos({ line: 16, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["D1", "D2"]); }); it("should NOT list variable, parameter or function names on property lookups", function () { testEditor.setCursorPos({ line: 17, ch: 11 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsAbsent(hintObj, ["A1", "A2", "funB", "paramB1", "paramB2", "B1", "B2", "funC", "paramC1", "paramC2"]); }); it("should NOT list keywords on property lookups", function () { testEditor.setCursorPos({ line: 17, ch: 11 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsAbsent(hintObj, ["case", "function", "var"]); }); it("should close hints when move over '.' ", function () { testEditor.setCursorPos({ line: 17, ch: 11 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 17, ch: 10 }, true); }); it("should close hints only when move off the end of a property ", function () { testEditor.setCursorPos({ line: 17, ch: 11 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 17, ch: 12 }, false); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 17, ch: 13 }, false); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 17, ch: 14 }, false); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 17, ch: 15 }, false); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 17, ch: 16 }, false); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 17, ch: 17 }, true); }); it("should close hints only when move off the beginning of an identifier ", function () { testEditor.setCursorPos({ line: 17, ch: 10 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 17, ch: 9 }, false); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 17, ch: 8 }, false); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 17, ch: 7 }, true); }); it("should close hints only when move off the beginning of a keyword ", function () { testEditor.setCursorPos({ line: 24, ch: 7 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["var"]); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 24, ch: 6 }, false); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 24, ch: 5 }, false); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 24, ch: 4 }, false); expectCloseHints(JSCodeHints.jsHintProvider, hintObj, { line: 24, ch: 3 }, true); }); it("should NOT list implicit hints on left-brace", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); expectNoHints(JSCodeHints.jsHintProvider, "{"); }); it("should list explicit hints for variable and function names", function () { testEditor.setCursorPos({ line: 6, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider, null); hintsPresent(hintObj, ["A2", "A3", "funB", "A1"]); }); it("should list implicit hints when typing property lookups", function () { testEditor.setCursorPos({ line: 17, ch: 10 }); var hintObj = expectHints(JSCodeHints.jsHintProvider, "."); hintsPresent(hintObj, ["B1", "paramB1"]); }); it("should give priority to identifier names associated with the current context", function () { testEditor.setCursorPos({ line: 16, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentOrdered(hintObj, ["C1", "B1"]); hintsPresentOrdered(hintObj, ["C2", "B2"]); }); it("should give priority to property names associated with the current context from other files", function () { testEditor.setCursorPos({ line: 16, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentOrdered(hintObj, ["C1", "D1"]); hintsPresentOrdered(hintObj, ["B1", "D1"]); hintsPresentOrdered(hintObj, ["A1", "D1"]); hintsPresentOrdered(hintObj, ["funB", "funE"]); }); xit("should choose the correct delimiter for string literal hints with no query", function () { var start = { line: 18, ch: 0 }, end = { line: 18, ch: 18 }; testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); selectHint(JSCodeHints.jsHintProvider, hintObj, 13); // hint 13 is "hello\\\"world!" runs(function () { expect(testEditor.getCursorPos()).toEqual(end); expect(testDoc.getRange(start, end)).toEqual('"hello\\\\\\" world!"'); }); }); it("should insert value hints with no current query", function () { var start = { line: 6, ch: 0 }, end = { line: 6, ch: 2 }; testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); selectHint(JSCodeHints.jsHintProvider, hintObj, "A2"); runs(function () { //expect(testEditor.getCursorPos()).toEqual(end); expect(testDoc.getRange(start, end)).toEqual("A2"); }); }); it("should insert value hints replacing the current query", function () { var start = { line: 5, ch: 10 }, // A3 = A<here>2; before = { line: 5, ch: 9 }, end = { line: 5, ch: 11 }; testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresent(hintObj, ["A1", "A2", "A3"]); selectHint(JSCodeHints.jsHintProvider, hintObj, "A1"); runs(function () { //expect(testEditor.getCursorPos()).toEqual(end); expect(testDoc.getRange(before, end)).toEqual("A1"); }); }); it("should insert property hints with no current query", function () { var start = { line: 6, ch: 0 }, middle = { line: 6, ch: 3 }, end = { line: 6, ch: 8 }; testDoc.replaceRange("A1.", start, start); testEditor.setCursorPos(middle); var hintObj = expectHints(JSCodeHints.jsHintProvider); selectHint(JSCodeHints.jsHintProvider, hintObj, "propA"); runs(function () { expect(fixPos(testEditor.getCursorPos())).toEqual(fixPos(end)); expect(testDoc.getRange(start, end)).toEqual("A1.propA"); expect(testDoc.getLine(end.line).length).toEqual(8); }); }); it("should insert, not replace, property hints with no current query", function () { var start = { line: 6, ch: 0 }, middle = { line: 6, ch: 3 }, end = { line: 6, ch: 8 }, endplus = { line: 6, ch: 12 }; testDoc.replaceRange("A1.prop", start, start); testEditor.setCursorPos(middle); var hintObj = expectHints(JSCodeHints.jsHintProvider); selectHint(JSCodeHints.jsHintProvider, hintObj, "propA"); runs(function () { expect(fixPos(testEditor.getCursorPos())).toEqual(fixPos(end)); expect(testDoc.getRange(start, endplus)).toEqual("A1.propAprop"); expect(testDoc.getLine(end.line).length).toEqual(12); }); }); it("should insert, not replace, property hints with a partial current query", function () { var start = { line: 6, ch: 0 }, middle = { line: 6, ch: 6 }, end = { line: 6, ch: 8 }; testDoc.replaceRange("A1.pro", start, start); testEditor.setCursorPos(middle); var hintObj = expectHints(JSCodeHints.jsHintProvider); selectHint(JSCodeHints.jsHintProvider, hintObj, "propA"); runs(function () { expect(fixPos(testEditor.getCursorPos())).toEqual(fixPos(end)); expect(testDoc.getRange(start, end)).toEqual("A1.propA"); expect(testDoc.getLine(end.line).length).toEqual(8); }); }); it("should replace property hints replacing a partial current query", function () { var start = { line: 6, ch: 0 }, middle = { line: 6, ch: 6 }, end = { line: 6, ch: 8 }, endplus = { line: 6, ch: 10 }; testDoc.replaceRange("A1.propB", start, start); testEditor.setCursorPos(middle); var hintObj = expectHints(JSCodeHints.jsHintProvider); selectHint(JSCodeHints.jsHintProvider, hintObj, "propA"); runs(function () { expect(fixPos(testEditor.getCursorPos())).toEqual(fixPos(end)); expect(testDoc.getRange(start, endplus)).toEqual("A1.propApB"); expect(testDoc.getLine(end.line).length).toEqual(10); }); }); it("should replace property hints but not following delimiters", function () { var start = { line: 6, ch: 0 }, middle = { line: 6, ch: 4 }, end = { line: 6, ch: 9 }, endplus = { line: 6, ch: 14 }; testDoc.replaceRange("(A1.prop)", start, start); testEditor.setCursorPos(middle); var hintObj = expectHints(JSCodeHints.jsHintProvider); selectHint(JSCodeHints.jsHintProvider, hintObj, "propA"); runs(function () { expect(fixPos(testEditor.getCursorPos())).toEqual(fixPos(end)); expect(testDoc.getRange(start, endplus)).toEqual("(A1.propAprop)"); expect(testDoc.getLine(endplus.line).length).toEqual(14); }); }); it("should list hints for string, as string assigned to 's', 's' assigned to 'r' and 'r' assigned to 't'", function () { var start = { line: 26, ch: 0 }, middle = { line: 26, ch: 6 }; // pad spaces here as tern has issue,without space, no code hint testDoc.replaceRange(" t.", start); testEditor.setCursorPos(middle); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresentOrdered(hintObj, ["charAt", "charCodeAt", "concat", "indexOf"]); }); }); it("should list function type", function () { var start = { line: 37, ch: 0 }, middle = { line: 37, ch: 5 }; testDoc.replaceRange("funD(", start, start); testEditor.setCursorPos(middle); runs(function () { expectParameterHint([{name: "a", type: "String"}, {name: "b", type: "Number"}], 0); }); }); it("should list exports from a requirejs module", function () { var start = { line: 40, ch: 21 }; testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresentExact(hintObj, ["a", "b", "c", "j"]); }); }); it("should list later defined property names", function () { var start = { line: 17, ch: 11 }; testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresentExact(hintObj, ["foo", "propB"]); }); }); it("should list matching property names", function () { var cursor1 = { line: 12, ch: 0 }, cursor2 = { line: 12, ch: 6 }; testDoc.replaceRange("paramB", cursor1, cursor1); testEditor.setCursorPos(cursor2); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresentExact(hintObj, ["paramB1", "paramB2"]); }); }); it("should take anotation parameter type:String", function () { var start = { line: 37, ch: 21 }; testDoc.replaceRange("var k= funD(10,11).x.", start, start); testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresentOrdered(hintObj, ["charAt", "charCodeAt", "concat", "indexOf"]); }); }); it("should take anotation parameter type:Number", function () { var start = { line: 37, ch: 21 }; testDoc.replaceRange("var k= funD(10,11).y.", start, start); testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresentOrdered(hintObj, ["toExponential", "toFixed", "toString"]); }); }); it("should add new method on String .prototype", function () { var start = { line: 37, ch: 0 }; var testPos = { line: 40, ch: 12 }; testDoc.replaceRange("String.prototype.times = function (count) {\n" + "\treturn count < 1 ? '' : new Array[count + 1].join(this);\n};\n\"hello\".tim", start, start); testEditor.setCursorPos(testPos); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresentOrdered(hintObj, ["times", "trim"]); }); }); it("should list function defined from .prototype", function () { var start = { line: 59, ch: 5 }; testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresentExact(hintObj, ["calc"]); }); }); it("should list function type defined from .prototype", function () { var start = { line: 59, ch: 10 }; testEditor.setCursorPos(start); runs(function () { expectParameterHint([{name: "a4", type: "Number"}, {name: "b4", type: "Number"}], 0); }); }); it("should list function inherited from super class", function () { var start = { line: 79, ch: 11 }; testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresentExact(hintObj, ["amountDue", "getAmountDue", "getName", "name", "setAmountDue"]); }); }); it("should show argument from from .prototype.Method", function () { var start = { line: 80, ch: 0 }, testPos = { line: 80, ch: 24 }; testDoc.replaceRange("myCustomer.setAmountDue(", start); testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "amountDue", type: "Object"}], 0); }); }); it("should show inner function type", function () { var testPos = { line: 96, ch: 23 }; testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "arg", type: "String"}], 0); }); }); it("should show type for inner function returned function", function () { var testPos = { line: 96, ch: 33 }; testEditor.setCursorPos(testPos); expectHints(JSCodeHints.jsHintProvider); runs(function () { expectParameterHint([], 0); }); }); // parameter type anotation tests, due to another bug #3670: first argument has ? xit("should list parameter Date,boolean type", function () { var start = { line: 109, ch: 0 }, testPos = { line: 109, ch: 11 }; testDoc.replaceRange("funTypeAn1(", start); testEditor.setCursorPos(testPos); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresentExact(hintObj, ["funTypeAn1((a: bool, b: Date) -> {x, y}"]); }); }); // parameter type anotation tests, due to another bug #3670: first argument has ? xit("should list parameter function type and best guess for its argument/return types", function () { var testPos = { line: 123, ch: 11 }; testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "f", type: "function(): number"}], 0); }); }); // parameter type annotation tests it("should list parameter function type and best guess for function call/return types", function () { var testPos = { line: 139, ch: 12 }; testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "f", type: "function(String, Number):String"}], 0); }); }); it("should list array containing functions", function () { var testPos = { line: 142, ch: 7 }; testEditor.setCursorPos(testPos); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresent(hintObj, ["index1", "index2"]); }); }); it("should list function reference", function () { var start = { line: 144, ch: 0 }, testPos = { line: 144, ch: 14 }; testDoc.replaceRange("funArr.index1(", start); testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([], 0); }); }); it("should insert hint as [\"my-key\"] since 'my-key' is not a valid property name", function () { var start = { line: 49, ch: 0 }, middle = { line: 49, ch: 5 }, end = { line: 49, ch: 13 }; testDoc.replaceRange("arr.m", start, start); testEditor.setCursorPos(middle); var hintObj = expectHints(JSCodeHints.jsHintProvider); selectHint(JSCodeHints.jsHintProvider, hintObj, "my-key"); runs(function () { expect(fixPos(testEditor.getCursorPos())).toEqual(fixPos(end)); expect(testDoc.getRange(start, end)).toEqual("arr[\"my-key\"]"); expect(testDoc.getLine(end.line).length).toEqual(13); }); }); it("should insert hint as [\"my-key\"] make sure this works if nothing is typed after the '.'", function () { var start = { line: 49, ch: 0 }, middle = { line: 49, ch: 4 }, end = { line: 49, ch: 13 }; testDoc.replaceRange("arr.", start, start); testEditor.setCursorPos(middle); var hintObj = expectHints(JSCodeHints.jsHintProvider); selectHint(JSCodeHints.jsHintProvider, hintObj, "my-key"); runs(function () { expect(fixPos(testEditor.getCursorPos())).toEqual(fixPos(end)); expect(testDoc.getRange(start, end)).toEqual("arr[\"my-key\"]"); expect(testDoc.getLine(end.line).length).toEqual(13); }); }); it("should insert hint as '.for' since keywords can be used as property names", function () { var start = { line: 49, ch: 0 }, middle = { line: 49, ch: 5 }, end = { line: 49, ch: 7 }; testDoc.replaceRange("arr.f", start, start); testEditor.setCursorPos(middle); var hintObj = expectHints(JSCodeHints.jsHintProvider); selectHint(JSCodeHints.jsHintProvider, hintObj, "for"); runs(function () { expect(fixPos(testEditor.getCursorPos())).toEqual(fixPos(end)); expect(testDoc.getRange(start, end)).toEqual("arr.for"); expect(testDoc.getLine(end.line).length).toEqual(7); }); }); it("should jump to function", function () { var start = { line: 43, ch: 0 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 7, ch: 13}); }); }); it("should jump to var", function () { var start = { line: 44, ch: 10 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 3, ch: 6}); }); }); it("should jump to closure, early defined var", function () { var start = { line: 17, ch: 9 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 10, ch: 10}); }); }); it("should jump to the definition in new module file", function () { var start = { line: 40, ch: 22 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 4, ch: 13, file: "MyModule.js"}); //jump to another file }); }); it("should jump to the method definition in .prototype", function () { var start = { line: 59, ch: 8 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 53, ch: 21}); //jump to prototype.calc }); }); it("should jump to parameter passed in the method", function () { var start = { line: 63, ch: 20 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 61, ch: 27}); }); }); it("should jump to parameter passed in anonymous method", function () { var start = { line: 83, ch: 25 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 81, ch: 53}); }); }); it("should jump to inner method", function () { var start = { line: 96, ch: 32 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 94, ch: 17}); }); }); it("should jump to the actual function definition, and not the exports line", function () { var start = { line: 159, ch: 22 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 11, ch: 14, file: "MyModule.js"}); //jump to another file }); }); it("should not hint function, variable, or param decls", function () { var func = { line: 7, ch: 12 }, param = { line: 7, ch: 18 }, variable = { line: 10, ch: 10 }; runs(function () { testEditor.setCursorPos(func); expectNoParameterHint(); testEditor.setCursorPos(param); expectNoHints(JSCodeHints.jsHintProvider); testEditor.setCursorPos(variable); expectNoHints(JSCodeHints.jsHintProvider); }); }); it("should sort underscore names to the bottom", function () { testEditor.setCursorPos({ line: 146, ch: 0 }); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentOrdered(hintObj, ["A1", "A2", "A3", "funB", "_A1"]); }); it("should list all properties for unknown type", function () { var start = { line: 149, ch: 0 }, end = { line: 149, ch: 5 }; testDoc.replaceRange("help.", start, start); testEditor.setCursorPos(end); var hintObj = expectHints(JSCodeHints.jsHintProvider); // check we have a properties from "Function", "String", and "Array" hintsPresentOrdered(hintObj, ["apply", "charCodeAt", "concat"]); }); it("should switch to guesses after typing a query that does not match any hints", function () { var start = { line: 150, ch: 0 }, end = { line: 150, ch: 5 }; testDoc.replaceRange("s.shift", start, start); testEditor.setCursorPos(end); var hintObj = expectHints(JSCodeHints.jsHintProvider); // check we have a properties that start with "shift" hintsPresentOrdered(hintObj, ["shift", "shiftKey"]); }); it("should handle valid non-ascii characters in a property name", function () { var start = { line: 153, ch: 0 }, end = { line: 153, ch: 13 }; testDoc.replaceRange("hope.frenchçP", start, start); testEditor.setCursorPos(end); var hintObj = expectHints(JSCodeHints.jsHintProvider); // check we have a properties that start with "shift" hintsPresentOrdered(hintObj, ["frenchçProp"]); }); it("should show guessed argument type from current passing parameter", function () { var start = { line: 80, ch: 0 }, testPos = { line: 80, ch: 24 }; testDoc.replaceRange("myCustomer.setAmountDue(10)", start); testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "amountDue", type: "Number"}], 0); }); }); it("should list parameter hint for record type annotation", function () { var testPos = { line: 178, ch: 25 }; testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "t", type: "{index: Number, name: String}"}], -1); }); }); it("should list parameter hint for optional parameters", function () { var testPos = { line: 214, ch: 17 }; testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "a", type: "Number", isOptional: true}, {name: "b", type: "String", isOptional: true}], 0); }); }); it("should list parameter hint for a function parameter", function () { var testPos = { line: 181, ch: 12 }; testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "compare", type: "function(Object, Object):Number", isOptional: true}], -1); }); }); it("should list parameter hint for an array parameter", function () { var testPos = { line: 184, ch: 12 }; testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "other", type: "Array.<Object>"}], -1); }); }); it("should list parameter hint for a source array annotation", function () { var testPos = { line: 200, ch: 20 }; testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "a", type: "Array.<String>"}], 0); }); }); it("should close parameter hint when move off function", function () { var testPos = { line: 184, ch: 12 }, endPos = { line: 184, ch: 19 }; testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "other", type: "Array.<Object>"}], -1); }); runs(function () { testEditor.setCursorPos(endPos); expectParameterHintClosed(); }); }); it("should close parameter hint when move off function to another function", function () { var testPos = { line: 184, ch: 12 }, newPos = { line: 181, ch: 12 }; testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "other", type: "Array.<Object>"}], -1); }); runs(function () { testEditor.setCursorPos(newPos); expectParameterHintClosed(); }); }); it("should update current parameter as the cursor moves", function () { var testPos = { line: 186, ch: 19 }, newPos = { line: 186, ch: 20 }; testEditor.setCursorPos(testPos); runs(function () { expectParameterHint([{name: "char", type: "String"}, {name: "from", type: "Number", isOptional: true}], 0); }); runs(function () { testEditor.setCursorPos(newPos); expectParameterHint([{name: "char", type: "String"}, {name: "from", type: "Number", isOptional: true}], 1); }); }); // Test `jscodehints.noHintsOnDot` preference it("should consider dot a hintable key based on preference", function () { var noHintsOnDot = PreferencesManager.get("jscodehints.noHintsOnDot"); testEditor.setCursorPos({ line: 44, ch: 10 }); // Default is falsey expect(noHintsOnDot).toBeFalsy(); // Should get hints after dot expectHints(JSCodeHints.jsHintProvider, "."); // Set preference to true PreferencesManager.set("jscodehints.noHintsOnDot", true); // Should no longer get hints after dot expectNoHints(JSCodeHints.jsHintProvider, "."); // Set preference back to original value (converted to boolean) PreferencesManager.set("jscodehints.noHintsOnDot", !!noHintsOnDot); }); }); describe("JavaScript Code Hinting in a HTML file", function () { beforeEach(function () { setupTest(testHtmlPath, false); }); afterEach(function () { tearDownTest(); }); it("basic codehints in html file", function () { var start = { line: 37, ch: 9 }, end = { line: 37, ch: 13}; testDoc.replaceRange("x100.", start); testEditor.setCursorPos(end); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresentOrdered(hintObj, ["charAt", "charCodeAt", "concat", "indexOf"]); }); }); it("function type hint in html file", function () { var start = { line: 36, ch: 12 }; testEditor.setCursorPos(start); runs(function () { expectParameterHint([{name: "a", type: "Number"}], 0); }); }); it("should show function type code hint for function in script file inside html file", function () { var start = { line: 22, ch: 17 }; testEditor.setCursorPos(start); runs(function () { expectParameterHint([{name: "a", type: "String"}, {name: "b", type: "Number"}], 0); }); }); it("should show function type code hint for function in another script file inside html file", function () { var start = { line: 23, ch: 17 }; testEditor.setCursorPos(start); runs(function () { expectParameterHint([{name: "paramE1", type: "D1"}, {name: "paramE2", type: "Number"}], 0); }); }); it("should show global variable in another script file inside html file", function () { var start = { line: 27, ch: 8 }, end = { line: 27, ch: 13}, testPosStart = { line: 27, ch: 11}, testPosEnd = { line: 27, ch: 21}; testDoc.replaceRange("arr.m", start); testEditor.setCursorPos(end); var hintObj = expectHints(JSCodeHints.jsHintProvider); runs(function () { hintsPresent(hintObj, ["my-key"]); }); selectHint(JSCodeHints.jsHintProvider, hintObj, "my-key"); runs(function () { expect(testDoc.getRange(testPosStart, testPosEnd)).toEqual("[\"my-key\"]"); }); }); it("should jump to definition inside html file", function () { var start = { line: 36, ch: 10 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 19, ch: 20}); }); }); it("should jump to funtion definition to loaded file1", function () { var start = { line: 22, ch: 15 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 33, ch: 13}); }); }); it("should jump to funtion definition to loaded file2", function () { var start = { line: 23, ch: 15 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 6, ch: 13}); }); }); it("should jump to property definition to loaded file1", function () { var start = { line: 23, ch: 28 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 4, ch: 16}); }); }); it("should jump to property definition to loaded file2", function () { var start = { line: 23, ch: 18 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 3, ch: 6}); }); }); }); describe("JavaScript Code Hinting without modules", function () { var testPath = extensionPath + "/unittest-files/non-module-test-files/app.js"; ScopeManager.handleProjectOpen(extensionPath + "/unittest-files/non-module-test-files/"); beforeEach(function () { setupTest(testPath, true); }); afterEach(function () { tearDownTest(); }); // Test reading multiple files and subdirectories // Turned for per #7646 xit("should handle reading all files when modules not used", function () { var start = { line: 8, ch: 8 }; runs(function () { testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["a", "b", "b1", "c", "d"]); }); }); }); describe("JavaScript Code Hinting with modules", function () { var testPath = extensionPath + "/unittest-files/module-test-files/module_tests.js"; beforeEach(function () { setupTest(testPath, true); }); afterEach(function () { tearDownTest(); }); it("should read methods created in submodule on this", function () { var start = { line: 8, ch: 17 }; runs(function () { testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["addMessage", "name", "privilegedMethod", "publicMethod1"]); }); }); // bug: wait for fix in tern xit("should read methods created in submodule", function () { var start = { line: 19, ch: 15 }; runs(function () { testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["addMessage", "name", "privilegedMethod", "publicMethod1"]); }); }); it("should read properties created in parent module", function () { var start = { line: 30, ch: 8 }, testPos = { line: 30, ch: 15}; testDoc.replaceRange("parent.", start); runs(function () { testEditor.setCursorPos(testPos); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["addMessage", "name", "privilegedMethod", "publicMethod1"]); }); }); // bug: wait for tern xit("should read methods created in submodule module", function () { var start = { line: 62, ch: 0 }, testPos = { line: 62, ch: 13}; testDoc.replaceRange("SearchEngine.", start); runs(function () { testEditor.setCursorPos(testPos); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["getYourLuckyNumber", "subSearch"]); }); }); it("should read methods created in parent module", function () { var start = { line: 78, ch: 41 }; runs(function () { testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["getYourLuckyNumber", "subSearch"]); }); }); it("should load module by file path from require", function () { var start = { line: 88, ch: 20 }; runs(function () { testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["color", "material", "size"]); }); }); // tern bug: https://github.com/marijnh/tern/issues/147 xit("should read properties from exported module", function () { var start = { line: 96, ch: 0 }, testPos = { line: 96, ch: 9}; testDoc.replaceRange("hondaCar.", start); runs(function () { testEditor.setCursorPos(testPos); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["model", "name"]); }); }); // bug in test framework? can't run sequential jump, verification is wrong xit("should jump to a module, depending module", function () { var start = { line: 93, ch: 25 }, testPos = { line: 8, ch: 35 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 5, ch: 23}); }); testEditor.setCursorPos(testPos); runs(function () { editorJumped({line: 5, ch: 23}); }); }); }); describe("JavaScript Code Hinting preference tests", function () { var testPath = extensionPath + "/unittest-files/preference-test-files/", preferences; function getPreferences(path) { preferences = null; FileSystem.resolve(path, function (err, file) { if (!err) { FileUtils.readAsText(file).done(function (text) { var configObj = null; try { configObj = JSON.parse(text); } catch (e) { // continue with null configObj console.log(e); } preferences = new Preferences(configObj); }).fail(function (error) { preferences = new Preferences(); }); } else { preferences = new Preferences(); } }); } // Test preferences file with no entries. Preferences should contain // default values. it("should handle reading an empty configuration file", function () { getPreferences(testPath + "defaults-test/.jscodehints"); waitsFor(function () { return preferences !== null; }); runs(function () { expect(preferences.getExcludedDirectories()).toEqual(/node_modules/); expect(preferences.getExcludedFiles().source). toBe(/^require.*\.js$|^jquery.*\.js$/.source); expect(preferences.getMaxFileCount()).toBe(100); expect(preferences.getMaxFileSize()).toBe(512 * 1024); }); }); // Test preferences file with empty or out of ranges values. Preferences // should contain default values. it("should handle reading an invalid configuration file", function () { getPreferences(testPath + "negative-test/.jscodehints"); waitsFor(function () { return preferences !== null; }); runs(function () { expect(preferences.getExcludedDirectories()).toEqual(/node_modules/); expect(preferences.getExcludedFiles().source). toBe(/^require.*\.js$|^jquery.*\.js$/.source); expect(preferences.getMaxFileCount()).toBe(100); expect(preferences.getMaxFileSize()).toBe(512 * 1024); }); }); // Positive test. Test pattern matching. it("should handle a valid configuration file", function () { getPreferences(testPath + "positive-test/.jscodehints"); waitsFor(function () { return preferences !== null; }); runs(function () { var excludedDirs = preferences.getExcludedDirectories(), excludedFiles = preferences.getExcludedFiles(); // test "excluded-dir1" expect(excludedDirs.test("excluded-dir1")).toBeTruthy(); expect(excludedDirs.test("xexcluded-dir1")).toBeFalsy(); // test "excluded-dir2-*" expect(excludedDirs.test("excluded-dir2-1")).toBeTruthy(); expect(excludedDirs.test("excluded-dir2-12")).toBeFalsy(); expect(excludedDirs.test("excluded-dir2-z")).toBeFalsy(); expect(excludedDirs.test("excluded-dir2-")).toBeFalsy(); expect(excludedDirs.test("xexcluded-dir2-1")).toBeFalsy(); // test "file1?.js" expect(excludedFiles.test("file1.js")).toBeTruthy(); expect(excludedFiles.test("file12.js")).toBeTruthy(); expect(excludedFiles.test("file123.js")).toBeFalsy(); // test "file2*.js" expect(excludedFiles.test("file2.js")).toBeTruthy(); expect(excludedFiles.test("file2xxx.js")).toBeTruthy(); expect(excludedFiles.test("filexxxx.js")).toBeFalsy(); // test "file3.js" expect(excludedFiles.test("file3.js")).toBeTruthy(); expect(excludedFiles.test("xfile3.js")).toBeFalsy(); // test "/file4[x|y|z]?.js/" expect(excludedFiles.test("file4.js")).toBeTruthy(); expect(excludedFiles.test("file4x.js")).toBeTruthy(); expect(excludedFiles.test("file4y.js")).toBeTruthy(); expect(excludedFiles.test("file4z.js")).toBeTruthy(); expect(excludedFiles.test("file4b.js")).toBeFalsy(); expect(excludedFiles.test("file4xyz.js")).toBeFalsy(); expect(excludedFiles.test("xfile4.js")).toBeTruthy(); // test builtin exclusions are also present expect(excludedFiles.test("require.js")).toBeTruthy(); expect(excludedFiles.test("jquery.js")).toBeTruthy(); expect(preferences.getMaxFileCount()).toBe(512); expect(preferences.getMaxFileSize()).toBe(100000); }); }); }); describe("regression tests", function () { it("should return true for valid identifier, false for invalid one", function () { var identifierList = ["ᾩ", "ĦĔĽĻŎ", "〱〱〱〱", "जावास्क्रि", "KingGeorgeⅦ", "π", "ಠ_ಠ", "price_9̶9̶_89", "$_3423", "TRUE", "FALSE", "IV"]; var invalidIdentifierList = [" break", "\tif", "\ntrade"]; invalidIdentifierList.forEach(function (element) { var result = HintUtils.maybeIdentifier(element); expect(result).toBe(false); }); identifierList.forEach(function (element) { var result = HintUtils.maybeIdentifier(element); expect(result).toBe(true); }); }); }); describe("JavaScript Code Hinting with test.html file", function () { var testFile = extensionPath + "/unittest-files/basic-test-files/test.html"; beforeEach(function () { setupTest(testFile, true); }); afterEach(function () { tearDownTest(); }); // FIXME (issue #3915) xit("should read function name has double byte chars", function () { var start = { line: 15, ch: 8 }, testPos = { line: 15, ch: 10 }; runs(function () { testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["fun測试"]); }); runs(function () { testEditor.setCursorPos(testPos); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["fun測试()"]); }); }); it("should jump to function name with double byte chars", function () { var start = { line: 16, ch: 9 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 12, ch: 20}); }); }); // FIXME (issue #3915) xit("should read function name has non ascii chars", function () { var start = { line: 16, ch: 16 }; runs(function () { testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["frenchçProp()"]); }); }); it("should jump to function name with non ascii chars", function () { var start = { line: 16, ch: 12 }; testEditor.setCursorPos(start); runs(function () { editorJumped({line: 12, ch: 20}); }); }); }); describe("Code Hinting Regression", function () { var testFile = extensionPath + "/unittest-files/module-test-files/china/cupFiller.js"; beforeEach(function () { setupTest(testFile, true); }); afterEach(function () { tearDownTest(); }); // The test is disabled, because the TernWorker will consult the ProjectManager to // determine all the files in the project root. We don't have a project root for this // testcase. Perhaps we need to change the testsetup or find another way of dealing with this // Test makes sure that http://github.com/adobe/brackets/issue/6931 doesn't show up xit("should show hints for members of referenced class", function () { var start = { line: 8, ch: 15 }; runs(function () { testEditor.setCursorPos(start); var hintObj = expectHints(JSCodeHints.jsHintProvider); hintsPresentExact(hintObj, ["empty", "emptyIt", "fill", "full"]); }); }); }); describe("JavaScript Code Hinting format parameters tests", function () { it("should format parameters with no params", function () { var params = []; expect(HintUtils2.formatParameterHint(params)).toBe(""); }); it("should format parameters with one param", function () { var params = [{name: "param1", type: "String"}]; expect(HintUtils2.formatParameterHint(params)).toBe("String param1"); }); it("should format parameters with one optional param", function () { var params = [{name: "param1", type: "String", isOptional: true}]; expect(HintUtils2.formatParameterHint(params)).toBe("[String param1]"); }); it("should format parameters with one required, one optional param", function () { var params = [{name: "param1", type: "String"}, {name: "param2", type: "String", isOptional: true}]; expect(HintUtils2.formatParameterHint(params)).toBe("String param1, [String param2]"); }); it("should format parameters with required param following an optional param", function () { var params = [{name: "param1", type: "String"}, {name: "param2", type: "String", isOptional: true}, {name: "param3", type: "String"}]; expect(HintUtils2.formatParameterHint(params)).toBe("String param1, [String param2, String param3]"); }); it("should format parameters with optional param following an optional param", function () { var params = [{name: "param1", type: "String"}, {name: "param2", type: "String", isOptional: true}, {name: "param3", type: "String", isOptional: true}]; expect(HintUtils2.formatParameterHint(params)).toBe("String param1, [String param2], [String param3]"); }); it("should format parameters with optional param following optional and required params", function () { var params = [{name: "param1", type: "String"}, {name: "param2", type: "String", isOptional: true}, {name: "param3", type: "String"}, {name: "param4", type: "String", isOptional: true}]; expect(HintUtils2.formatParameterHint(params)).toBe("String param1, [String param2, String param3], [String param4]"); }); }); }); });