UNPKG

lsp-ws-connection

Version:
424 lines 16.4 kB
import { expect } from 'chai'; import * as sinon from 'sinon'; import { LspWsConnection } from '..'; var serverUri = 'ws://localhost:8080'; var mockInfo = { uri: 'file://' + __dirname, version: 0, languageId: 'plaintext', text: '' }; // There is a library that can be used to mock WebSockets, but the API surface tested here is small // enough that it is not necessary to use the library. This mock is a simple EventEmitter var MockSocket = /** @class */ (function () { function MockSocket(url, protocols) { var _this = this; this.listeners = {}; /** * Mocks sending data to the server. The fake implementation needs to respond with some data */ this.send = sinon.stub(); this.addEventListener = sinon .mock() .callsFake(function (type, listener) { var listeners = _this.listeners[type]; if (!listeners) { _this.listeners[type] = []; } listeners.push(listener); }); this.removeEventListener = sinon .mock() .callsFake(function (type, listener) { var index = _this.listeners[type].indexOf(function (l) { return l === listener; }); if (index > -1) { _this.listeners[type].splice(index, 1); } }); this.close = sinon.stub(); /** * Sends a synthetic event to the client code, for example to imitate a server response */ this.dispatchEvent = function (event) { var listeners = _this.listeners[event.type]; if (!listeners) { return false; } listeners.forEach(function (listener) { return listener.call(null, event); }); return true; }; // nothing here yet } Object.defineProperty(MockSocket.prototype, "onclose", { set: function (handler) { if (handler) { this.listeners.close = [handler]; } }, enumerable: false, configurable: true }); Object.defineProperty(MockSocket.prototype, "onerror", { set: function (handler) { if (handler) { this.listeners.error = [handler]; } }, enumerable: false, configurable: true }); Object.defineProperty(MockSocket.prototype, "onmessage", { set: function (handler) { if (handler) { this.listeners.message = [handler]; } }, enumerable: false, configurable: true }); Object.defineProperty(MockSocket.prototype, "onopen", { set: function (handler) { if (handler) { this.listeners.open = [handler]; } }, enumerable: false, configurable: true }); return MockSocket; }()); describe('LspWsConnection', function () { var connection; var mockSocket; beforeEach(function () { connection = new LspWsConnection({ languageId: 'plaintext', rootUri: 'file://' + __dirname, serverUri: serverUri }); mockSocket = new MockSocket('ws://localhost:8080'); }); afterEach(function () { sinon.restore(); }); it('initializes the connection in the right order', function (done) { // 1. It sends initialize and expects a response with capabilities mockSocket.send.onFirstCall().callsFake(function (str) { var message = JSON.parse(str); expect(message.method).equal('initialize'); // This is an actual response from the html language server var data = JSON.stringify({ jsonrpc: '2.0', id: message.id, result: { capabilities: { textDocumentSync: 1, hoverProvider: true, documentHighlightProvider: true, documentRangeFormattingProvider: false, documentLinkProvider: { resolveProvider: false }, documentSymbolProvider: true, definitionProvider: true, signatureHelpProvider: { triggerCharacters: ['('] }, typeDefinitionProvider: true, referencesProvider: true, colorProvider: {}, foldingRangeProvider: true, workspaceSymbolProvider: true, completionProvider: { resolveProvider: true, triggerCharacters: ['.'] }, codeActionProvider: true, renameProvider: true, executeCommandProvider: { commands: [] } } } }); mockSocket.dispatchEvent(new MessageEvent('message', { data: data })); }); // 2. After receiving capabilities from the server, it sends more configuration options mockSocket.send.onSecondCall().callsFake(function (str) { var message = JSON.parse(str); expect(message.method).equal('initialized'); setTimeout(function () { var mock = mockSocket.send; expect(mock.callCount).equal(3); // 3 is sent after initialization expect(JSON.parse(mock.getCall(2).args[0]).method).equal('workspace/didChangeConfiguration'); done(); }, 0); }); connection.connect(mockSocket); mockSocket.dispatchEvent(new Event('open')); // Send the messages expect(mockSocket.send.callCount).equal(1); expect(JSON.parse(mockSocket.send.firstCall.args[0]).method).equal('initialize'); }); describe('register/unregister capability', function () { beforeEach(function () { mockSocket.send.onFirstCall().callsFake(function (str) { var data = JSON.stringify({ jsonrpc: '2.0', id: 0, result: { capabilities: { definitionProvider: true } } }); mockSocket.dispatchEvent(new MessageEvent('message', { data: data })); }); }); it('registers a new server capability', function (done) { mockSocket.send.onSecondCall().callsFake(function () { expect(connection.isDefinitionSupported()).equal(true); expect(connection.isImplementationSupported()).equal(false); var data = JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'client/registerCapability', params: { registrations: [ { id: 'id', method: 'textDocument/implementation' } ] } }); mockSocket.dispatchEvent(new MessageEvent('message', { data: data })); setTimeout(function () { expect(connection.isDefinitionSupported()).equal(true); expect(connection.isImplementationSupported()).equal(true); done(); }, 0); }); connection.connect(mockSocket); mockSocket.dispatchEvent(new Event('open')); }); it('unregisters a server capability', function (done) { mockSocket.send.onSecondCall().callsFake(function () { expect(connection.isDefinitionSupported()).equal(true); var data = JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'client/unregisterCapability', params: { unregisterations: [ { id: 'id', method: 'textDocument/definition' } ] } }); mockSocket.dispatchEvent(new MessageEvent('message', { data: data })); setTimeout(function () { expect(connection.isDefinitionSupported()).equal(false); done(); }); }); connection.connect(mockSocket); mockSocket.dispatchEvent(new Event('open')); }); }); describe('hover', function () { var hoverResponse; beforeEach(function () { // Fake response just includes the hover provider mockSocket.send.onFirstCall().callsFake(function (str) { var data = JSON.stringify({ jsonrpc: '2.0', id: 0, result: { capabilities: { hoverProvider: true } } }); mockSocket.dispatchEvent(new MessageEvent('message', { data: data })); }); // 2. After receiving capabilities from the server, we will send a hover mockSocket.send.onSecondCall().callsFake(function (str) { void connection.getHoverTooltip({ line: 1, ch: 0 }, mockInfo); }); }); it('emits a null hover event', function (done) { // 3. Fake a server response for the hover mockSocket.send.onThirdCall().callsFake(function (str) { var message = JSON.parse(str); var data = JSON.stringify({ jsonrpc: '2.0', id: message.id, result: null }); mockSocket.dispatchEvent(new MessageEvent('message', { data: data })); }); connection.connect(mockSocket); mockSocket.dispatchEvent(new Event('open')); connection.on('hover', function (response) { expect(response).to.be.a('null'); done(); }); }); it('emits a complete hover event', function (done) { hoverResponse = { contents: 'Details of hover', range: { start: { line: 1, character: 0 }, end: { line: 2, character: 0 } } }; // 3. Fake a server response for the hover mockSocket.send.onThirdCall().callsFake(function (str) { var message = JSON.parse(str); var data = JSON.stringify({ jsonrpc: '2.0', id: message.id, result: hoverResponse }); mockSocket.dispatchEvent(new MessageEvent('message', { data: data })); }); connection.connect(mockSocket); mockSocket.dispatchEvent(new Event('open')); connection.on('hover', function (response) { expect(response).to.deep.equal(hoverResponse); done(); }); }); }); describe('completion', function () { var completionResponse; beforeEach(function () { // Fake response just includes the hover provider mockSocket.send.onFirstCall().callsFake(function (str) { var data = JSON.stringify({ jsonrpc: '2.0', id: 0, result: { capabilities: { completionProvider: { triggerCharacters: ['.'], resolveProvider: false } } } }); mockSocket.dispatchEvent(new MessageEvent('message', { data: data })); }); // 2. After receiving capabilities from the server, we will send a completion mockSocket.send.onSecondCall().callsFake(function (str) { void connection.getCompletion({ line: 1, ch: 8 }, { start: { line: 1, ch: 8 }, end: { line: 1, ch: 9 }, text: '.' }, mockInfo); }); }); it('emits a null completion event', function (done) { // 3. Fake a server response for the hover mockSocket.send.onThirdCall().callsFake(function (str) { var message = JSON.parse(str); var data = JSON.stringify({ jsonrpc: '2.0', id: message.id, result: null }); mockSocket.dispatchEvent(new MessageEvent('message', { data: data })); }); connection.connect(mockSocket); mockSocket.dispatchEvent(new Event('open')); connection.on('completion', function (response) { expect(response).to.be.a('null'); done(); }); }); it('emits a completion event using CompletionList', function (done) { completionResponse = { isIncomplete: false, items: [ { label: 'log' }, { label: 'info' } ] }; // 3. Fake a server response for the hover mockSocket.send.onThirdCall().callsFake(function (str) { var message = JSON.parse(str); var data = JSON.stringify({ jsonrpc: '2.0', id: message.id, result: completionResponse }); mockSocket.dispatchEvent(new MessageEvent('message', { data: data })); }); connection.connect(mockSocket); mockSocket.dispatchEvent(new Event('open')); connection.on('completion', function (response) { expect(response).to.deep.equal(completionResponse.items); done(); }); }); it('emits a completion event of CompletionItem[]', function (done) { var completion = [ { label: 'log' }, { label: 'info' } ]; // 3. Fake a server response for the hover mockSocket.send.onThirdCall().callsFake(function (str) { var message = JSON.parse(str); var data = JSON.stringify({ jsonrpc: '2.0', id: message.id, result: completion }); mockSocket.dispatchEvent(new MessageEvent('message', { data: data })); }); connection.connect(mockSocket); mockSocket.dispatchEvent(new Event('open')); connection.on('completion', function (response) { expect(response).to.deep.equal(completion); done(); }); }); }); it('closes the socket connection and stops sending messages', function () { connection.connect(mockSocket); connection.close(); connection.sendChange(mockInfo); expect(mockSocket.send.callCount).equal(0); }); }); //# sourceMappingURL=connection.test.js.map