1
0
mirror of https://github.com/adobe/brackets.git synced 2024-11-20 09:53:00 +01:00
brackets/test/SpecRunner.js
Subhash Jha df7aea423a Language Server Protocol Support for Brackets (#14606)
* LSP Initial set of changes

* Adding comments and a bit of cleanup

* Adding php client for lsp

* further cleanup

* removing dependency on HintUtils

* removing phpClient extension from this branch

* Cleanup

* fixing eslint errors

* Refactoring code- Removing dependency on JSUtils ANd adding basic structure for client capabilities

* Bug Fix: too many listeners were getting attached to node process + code cleanup

* putting null check and settign capabilities to default values

* reinitializing server on workspace change and moving out capabilities from client code

* cleanup

* First cut for LSP support in Brackets

* First cut for LSP support in Brackets

* Adding client infrastructure

* Adding client infrastructure

* Adding handlers on Language Client Proxy, fixing eslint errors

* Adding handlers on Language Client Proxy, fixing eslint errors

* Fixing protocol adapter

* Fixing protocol adapter

* Fix typo

* Fix typo

* Removing older implementation

* Removing older implementation

* Added error checks to the auto update mechanism. So in case the auto update mechansim fails, we will now give chance to the default update process Handler to handle the update mechanism (Which is essentially taking the user to brackets.io). (#14605)

* First cut for LSP support in Brackets

* First cut for LSP support in Brackets

* Adding client infrastructure

* Adding client infrastructure

* Adding handlers on Language Client Proxy, fixing eslint errors

* Adding handlers on Language Client Proxy, fixing eslint errors

* Fixing protocol adapter

* Fixing protocol adapter

* Fix typo

* Fix typo

* Removing older implementation

* Removing older implementation

* Removing custom comments

* Removing custom comments

* Fixing Typo

* Fixing Typo

* Add missing Params in function call

* Add missing Params in function call

* Correcting message type, handlers

* Correcting message type, handlers

* Minor correction on active project change

* Minor correction on active project change

* Correcting the message format for didChange

* Correcting the message format for didChange

* Changing custom notification and request handlers, correcting typo, adding catch block for Connection

* Changing custom notification and request handlers, correcting typo, adding catch block for Connection

* Stop Creation of Multiple Language Servers

* Stop Creation of Multiple Language Servers

* Make Language Client Generic, address review comments

* Make Language Client Generic, address review comments

* Correcting param descriptions

* Correcting param descriptions

* Modifying events handling logic for Language Client, add formatting option for communication params

* Modifying events handling logic for Language Client, add formatting option for communication params

* Add handlers for node side

* Add handlers for node side

* Removing explicit param creation, substituting with appropriate checks

* Removing explicit param creation, substituting with appropriate checks

* Fixing lint errors in MessageHandler.js

* Fixing lint errors in MessageHandler.js

* Messaging related cleanup

* Messaging related cleanup

* Adding default providers and feature managers

* Adding default providers and feature managers

* Adding banner and fixing lint error

* Adding banner and fixing lint error

* fix spacing issue

* fix spacing issue

* Fix spacing issues

* Fix spacing issues

* Add filetype checks for all events, minor server info corrections

* Add filetype checks for all events, minor server info corrections

* Handling Reload with Extension Scenario, minor JumpToDef provider fix

* Handling Reload with Extension Scenario, minor JumpToDef provider fix

* Correcting Typo

* Correcting Typo

* Adding bug fixes

* Adding bug fixes

* Adding bug fixes 2

* Adding bug fixes 2

* Addressing Review: Fixing minor typo

* Addressing Review: Fixing minor typo

* Minor bug fixes, functionality enhancements

* Minor bug fixes, functionality enhancements

* Adding tests for Language Server Support: first cut

* Adding tests for Language Server Support: first cut

* Adding banner, fixing lint errors

* Adding banner, fixing lint errors

* Adding dependency related tasks

* Adding dependency related tasks

* Fixing npm environment string

* Fixing npm environment string

* Changing handler name

* Changing handler name

* Changing file name to ClientLoader

* Changing file name to ClientLoader

* Changing variable name appropriately

* Changing variable name appropriately

* Grunt related changes for build

* Grunt related changes for build

* Adding additional requests and notifications for handling various scenarios

* Adding additional requests and notifications for handling various scenarios

* Adding Path Converter Utilities

* Adding Path Converter Utilities

* Changing Ternary operator to OR operater

* Changing Ternary operator to OR operater

* Addressing review comments

* Addressing review comments

* Removing the handler for editor change, will be handled explicitely

* Removing the handler for editor change, will be handled explicitely

* Patching JavaScriptCodeHints

* Patching JavaScriptCodeHints

* Preferences infra for LanguageTools

* Preferences infra for LanguageTools

* Fixing JS ParameterHints

* Fixing JS ParameterHints

* Fixing Default Parameter Hints Provider

* Fixing Default Parameter Hints Provider

* Fixing Path Converters

* Fixing Path Converters

* Fixing Lint in PathConverters

* Fixing Lint in PathConverters

* Retaining Posix Path on Win

* Retaining Posix Path on Win

* Fixing lint errors

* Fixing lint errors

* Fixing Node side Utils

* Fixing Node side Utils

* Fixing Promise related Issues

* Fixing Promise related Issues

* Set Server Capability in Start call

* Set Server Capability in Start call

* Review Comments & Bug Fixes

* Review Comments & Bug Fixes

* Addressing Review Comments

* Addressing Review Comments

* Fixing Lint

* Fixing Lint
2019-04-02 15:05:43 +05:30

444 lines
17 KiB
JavaScript

/*
* Copyright (c) 2012 - 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.
*
*/
/*global beforeEach, afterEach, beforeFirst, afterLast, jasmine */
// Set the baseUrl to brackets/src
require.config({
baseUrl: "../src",
paths: {
"test" : "../test",
"perf" : "../test/perf",
"spec" : "../test/spec",
"text" : "thirdparty/text/text",
"i18n" : "thirdparty/i18n/i18n",
"fileSystemImpl" : "filesystem/impls/appshell/AppshellFileSystem",
"preferences/PreferencesImpl" : "../test/TestPreferencesImpl",
"preact-compat" : "thirdparty/preact-compat/preact-compat.min",
"preact" : "thirdparty/preact/preact",
"preact-test-utils" : "thirdparty/preact-test-utils/preact-test-utils",
"simulate-event" : "thirdparty/simulate-event/simulate-event",
"xtend" : "thirdparty/xtend"
},
map: {
"*": {
"thirdparty/preact" : "preact-compat",
"thirdparty/preact-test-utils" : "preact-test-utils"
}
}
});
define(function (require, exports, module) {
'use strict';
// Utility dependencies
var AppInit = require("utils/AppInit"),
SpecRunnerUtils = require("spec/SpecRunnerUtils"),
ExtensionLoader = require("utils/ExtensionLoader"),
Async = require("utils/Async"),
FileSystem = require("filesystem/FileSystem"),
FileUtils = require("file/FileUtils"),
UrlParams = require("utils/UrlParams").UrlParams,
UnitTestReporter = require("test/UnitTestReporter").UnitTestReporter,
NodeConnection = require("utils/NodeConnection"),
BootstrapReporterView = require("test/BootstrapReporterView").BootstrapReporterView,
NativeApp = require("utils/NativeApp");
// Load modules for later use
require("language/CodeInspection");
require("thirdparty/lodash");
require("editor/CodeHintManager");
require("utils/Global");
require("command/Menus");
require("utils/NodeDomain");
require("utils/ColorUtils");
require("preferences/PreferencesBase");
require("JSUtils/Session");
require("JSUtils/ScopeManager");
require("widgets/InlineMenu");
// Load modules that self-register and just need to get included in the test-runner window
require("document/ChangedDocumentTracker");
// TODO (#2155): These are used by extensions via brackets.getModule(), so tests that run those
// extensions need these to be required up front. We need a better solution for this eventually.
require("utils/ExtensionUtils");
// Load both top-level suites. Filtering is applied at the top-level as a filter to BootstrapReporter.
require("test/UnitTestSuite");
require("test/PerformanceTestSuite");
// Load JUnitXMLReporter
require("test/thirdparty/jasmine-reporters/jasmine.junit_reporter");
// Load CodeMirror add-ons--these attach themselves to the CodeMirror module
require("thirdparty/CodeMirror/addon/fold/xml-fold");
require("thirdparty/CodeMirror/addon/edit/matchtags");
require("thirdparty/CodeMirror/addon/edit/matchbrackets");
require("thirdparty/CodeMirror/addon/edit/closebrackets");
require("thirdparty/CodeMirror/addon/edit/closetag");
require("thirdparty/CodeMirror/addon/selection/active-line");
require("thirdparty/CodeMirror/addon/mode/multiplex");
require("thirdparty/CodeMirror/addon/mode/overlay");
require("thirdparty/CodeMirror/addon/search/searchcursor");
require("thirdparty/CodeMirror/keymap/sublime");
//load Language Tools Module
require("languageTools/PathConverters");
require("languageTools/LanguageTools");
require("languageTools/ClientLoader");
require("languageTools/BracketsToNodeInterface");
require("languageTools/DefaultProviders");
require("languageTools/DefaultEventHandlers");
//load language features
require("features/ParameterHintsManager");
require("features/JumpToDefManager");
var selectedSuites,
params = new UrlParams(),
reporter,
reporterView,
_writeResults = new $.Deferred(),
resultsPath;
/**
* @const
* Amount of time to wait before automatically rejecting the connection
* deferred. If we hit this timeout, we'll never have a node connection
* for the installer in this run of Brackets.
*/
var NODE_CONNECTION_TIMEOUT = 30000; // 30 seconds - TODO: share with StaticServer?
// parse URL parameters
params.parse();
resultsPath = params.get("resultsPath");
function _loadExtensionTests() {
// augment jasmine to identify extension unit tests
var addSuite = jasmine.Runner.prototype.addSuite;
jasmine.Runner.prototype.addSuite = function (suite) {
suite.category = "extension";
addSuite.call(this, suite);
};
var bracketsPath = FileUtils.getNativeBracketsDirectoryPath(),
paths = ["default"];
// load dev and user extensions only when running the extension test suite
if (selectedSuites.indexOf("extension") >= 0) {
paths.push("dev");
paths.push(ExtensionLoader.getUserExtensionPath());
}
// This returns path to test folder, so convert to src
bracketsPath = bracketsPath.replace(/\/test$/, "/src");
return Async.doInParallel(paths, function (dir) {
var extensionPath = dir;
// If the item has "/" in it, assume it is a full path. Otherwise, load
// from our source path + "/extensions/".
if (dir.indexOf("/") === -1) {
extensionPath = bracketsPath + "/extensions/" + dir;
}
return ExtensionLoader.testAllExtensionsInNativeDirectory(extensionPath);
});
}
function _documentReadyHandler() {
if (brackets.app.showDeveloperTools) {
$("#show-dev-tools").click(function () {
brackets.app.showDeveloperTools();
});
} else {
$("#show-dev-tools").remove();
}
$("#reload").click(function () {
window.location.reload(true);
});
if (selectedSuites.length === 1) {
$("#" + (selectedSuites[0])).closest("li").toggleClass("active", true);
}
AppInit._dispatchReady(AppInit.APP_READY);
jasmine.getEnv().execute();
}
function writeResults(path, text) {
// check if the file already exists
var file = FileSystem.getFileForPath(path);
file.exists(function (err, exists) {
if (err) {
_writeResults.reject(err);
return;
}
if (exists) {
// file exists, do not overwrite
_writeResults.reject();
} else {
// file not found, write the new file with xml content
FileUtils.writeText(file, text)
.done(function () {
_writeResults.resolve();
})
.fail(function (err) {
_writeResults.reject(err);
});
}
});
}
/**
* Listener for UnitTestReporter "runnerEnd" event. Attached only if
* "resultsPath" URL parameter exists. Does not overwrite existing file.
*
* @param {!$.Event} event
* @param {!UnitTestReporter} reporter
*/
function _runnerEndHandler(event, reporter) {
if (resultsPath && resultsPath.substr(-5) === ".json") {
writeResults(resultsPath, reporter.toJSON());
}
_writeResults.always(function () { brackets.app.quit(); });
}
/**
* Patch JUnitXMLReporter to use FileSystem and to consolidate all results
* into a single file.
*/
function _patchJUnitReporter() {
jasmine.JUnitXmlReporter.prototype.reportSpecResultsOriginal = jasmine.JUnitXmlReporter.prototype.reportSpecResults;
jasmine.JUnitXmlReporter.prototype.getNestedOutputOriginal = jasmine.JUnitXmlReporter.prototype.getNestedOutput;
jasmine.JUnitXmlReporter.prototype.reportSpecResults = function (spec) {
if (spec.results().skipped) {
return;
}
this.reportSpecResultsOriginal(spec);
};
jasmine.JUnitXmlReporter.prototype.getNestedOutput = function (suite) {
if (suite.results().totalCount === 0) {
return "";
}
return this.getNestedOutputOriginal(suite);
};
jasmine.JUnitXmlReporter.prototype.reportRunnerResults = function (runner) {
var suites = runner.suites(),
output = '<?xml version="1.0" encoding="UTF-8" ?>',
i;
output += "\n<testsuites>";
for (i = 0; i < suites.length; i++) {
var suite = suites[i];
if (!suite.parentSuite) {
output += this.getNestedOutput(suite);
}
}
output += "\n</testsuites>";
writeResults(resultsPath, output);
// When all done, make it known on JUnitXmlReporter
jasmine.JUnitXmlReporter.finished_at = (new Date()).getTime();
};
jasmine.JUnitXmlReporter.prototype.writeFile = function (path, filename, text) {
// do nothing
};
}
function _registerBeforeAfterHandlers() {
// Initiailize unit test preferences for each spec
beforeEach(function () {
// Unique key for unit testing
window.localStorage.setItem("preferencesKey", SpecRunnerUtils.TEST_PREFERENCES_KEY);
// Reset preferences from previous test runs
window.localStorage.removeItem("doLoadPreferences");
window.localStorage.removeItem(SpecRunnerUtils.TEST_PREFERENCES_KEY);
SpecRunnerUtils.runBeforeFirst();
});
// Revert unit test preferences after each spec
afterEach(function () {
// Clean up preferencesKey
window.localStorage.removeItem("preferencesKey");
SpecRunnerUtils.runAfterLast();
});
// Delete temp folder before running the first test
beforeFirst(function () {
SpecRunnerUtils.removeTempDirectory();
});
// Delete temp folder after running the last test
afterLast(function () {
SpecRunnerUtils.removeTempDirectory();
});
}
function init() {
selectedSuites = (params.get("suite") || window.localStorage.getItem("SpecRunner.suite") || "unit").split(",");
// Create a top-level filter to show/hide performance and extensions tests
var runAll = (selectedSuites.indexOf("all") >= 0);
var topLevelFilter = function (spec) {
// special case "all" suite to run unit, perf, extension, and integration tests
if (runAll) {
return true;
}
var currentSuite = spec.suite,
category = spec.category;
if (!category) {
// find the category from the closest suite
while (currentSuite) {
if (currentSuite.category) {
category = currentSuite.category;
break;
}
currentSuite = currentSuite.parentSuite;
}
}
// if unit tests are selected, make sure there is no category in the heirarchy
// if not a unit test, make sure the category is selected
return (selectedSuites.indexOf("unit") >= 0 && category === undefined) ||
(selectedSuites.indexOf(category) >= 0);
};
/*
* TODO (jason-sanjose): extension unit tests should only load the
* extension and the extensions dependencies. We should not load
* unrelated extensions. Currently, this solution is all or nothing.
*/
// configure spawned test windows to load extensions
SpecRunnerUtils.setLoadExtensionsInTestWindow(selectedSuites.indexOf("extension") >= 0);
_loadExtensionTests(selectedSuites).always(function () {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
_registerBeforeAfterHandlers();
// Create the reporter, which is really a model class that just gathers
// spec and performance data.
reporter = new UnitTestReporter(jasmineEnv, topLevelFilter, params.get("spec"));
SpecRunnerUtils.setUnitTestReporter(reporter);
// Optionally emit JUnit XML file for automated runs
if (resultsPath) {
if (resultsPath.substr(-4) === ".xml") {
_patchJUnitReporter();
jasmineEnv.addReporter(new jasmine.JUnitXmlReporter(null, true, false));
}
// Close the window
$(reporter).on("runnerEnd", _runnerEndHandler);
} else {
_writeResults.resolve();
}
jasmineEnv.addReporter(reporter);
// Create the view that displays the data from the reporter. (Usually in
// Jasmine this is part of the reporter, but we separate them out so that
// we can more easily grab just the model data for output during automatic
// testing.)
reporterView = new BootstrapReporterView(window.document, reporter);
// remember the suite for the next unit test window launch
window.localStorage.setItem("SpecRunner.suite", selectedSuites);
$(window.document).ready(_documentReadyHandler);
});
// Prevent clicks on any link from navigating to a different page (which could lose unsaved
// changes). We can't use a simple .on("click", "a") because of http://bugs.jquery.com/ticket/3861:
// jQuery hides non-left clicks from such event handlers, yet middle-clicks still cause CEF to
// navigate. Also, a capture handler is more reliable than bubble.
window.document.body.addEventListener("click", function (e) {
// Check parents too, in case link has inline formatting tags
var node = e.target, url;
while (node) {
if (node.tagName === "A") {
url = node.getAttribute("href");
if (url && url.match(/^http/)) {
NativeApp.openURLInDefaultBrowser(url);
e.preventDefault();
}
break;
}
node = node.parentElement;
}
}, true);
}
function connectToTestDomain() {
var _nodeConnectionDeferred = new $.Deferred(),
_nodeConnection = new NodeConnection();
_nodeConnection.connect(true).then(function () {
var domainPath = FileUtils.getNativeBracketsDirectoryPath() + "/" + FileUtils.getNativeModuleDirectoryPath(module) + "/../test/node/TestingDomain";
_nodeConnection.loadDomains(domainPath, true)
.then(init, function () {
// Failed to connect
console.error("[SpecRunner] Failed to connect to node", arguments);
var container = $('<div class="container-fluid">');
container.append('<div class="alert alert-error">Failed to connect to Node</div>');
$(window.document.body).append(container);
});
});
Async.withTimeout(_nodeConnectionDeferred.promise(), NODE_CONNECTION_TIMEOUT);
brackets.testing = { nodeConnection: _nodeConnection };
}
connectToTestDomain();
});