diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 44cdd24..92fba09 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -1,15 +1,30 @@ { - "require": ["ts-node/register/transpile-only"], - "include": ["src/**/*.ts"], - "exclude": ["src/logger/*.ts", "src/panels/*.ts", "src/webSocketServer/*.ts", "src/output-channel-log.ts", "src/youi-adapter.ts"], - "reporter": ["lcov", "text"], - "extension": [".ts"], - "all": true, - "temp-dir": "./reports/.nyc_output", - "report-dir": "./reports/coverage", - "check-coverage": true, - "branches": 98, - "lines": 99, - "functions": 97, - "statements": 99 - } + "require": [ + "ts-node/register/transpile-only" + ], + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/logger/*.ts", + "src/panels/*.ts", + "src/webSocketServer/*.ts", + "src/output-channel-log.ts", + "src/youi-adapter.ts" + ], + "reporter": [ + "lcov", + "text" + ], + "extension": [ + ".ts" + ], + "all": true, + "temp-dir": "./reports/.nyc_output", + "report-dir": "./reports/coverage", + "check-coverage": true, + "branches": 98, + "lines": 99, + "functions": 97, + "statements": 99 +} diff --git a/backend/mocha.opts b/backend/mocha.opts deleted file mode 100644 index bdab613..0000000 --- a/backend/mocha.opts +++ /dev/null @@ -1,4 +0,0 @@ ---require ts-node/register/transpile-only ---require source-map-support/register ---recursive "tests/**/*.spec.ts" ---timeout 80000 \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 9ca99df..c209a08 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,7 +1,7 @@ { "name": "code-snippet", - "version": "0.0.22", - "displayName": "Code Snippet", + "version": "0.0.23", + "displayName": "Code Snippet", "publisher": "SAPOSS", "author": { "name": "SAP SE" @@ -110,29 +110,29 @@ "compile": "tsc -p ./", "watch": "tsc -watch -p ./", "package": "npm run webpack && vsce package .", - "test": "nyc mocha -p tsconfig.json --opts ./mocha.opts", + "test": "nyc mocha -p tsconfig.json --recursive tests/**/*.spec.ts", "ws:run": "node ./out/src/webSocketServer/index.js", "lint": "eslint . --ext .ts,.tsx --cache", "lint:fix": "eslint . --ext .ts,.tsx --cache --fix" }, "dependencies": { - "@sap-devx/webview-rpc": "^0.2.2", - "@vscode-logging/logger": "1.1.0", - "datauri": "^2.0.0", - "fs-extra": "^8.1.0", - "lodash": "^4.17.15", - "strip-ansi": "^6.0.0", - "ws": "^7.2.5", + "@sap-devx/webview-rpc": "0.2.3", + "@vscode-logging/logger": "1.2.1", + "datauri": "3.0.0", + "fs-extra": "9.0.1", + "lodash": "4.17.20", + "strip-ansi": "6.0.0", + "ws": "7.4.0", "yeoman-environment": "2.10.3" }, "devDependencies": { - "@types/chai": "^4.2.9", - "@types/fs-extra": "^8.1.0", + "@types/chai": "^4.2.14", + "@types/fs-extra": "^9.0.4", "@types/inquirer": "^6.5.0", - "@types/lodash": "^4.14.150", - "@types/mocha": "^5.2.7", + "@types/lodash": "^4.14.165", + "@types/mocha": "^7.0.0", "@types/node": "^10.17.21", - "@types/sinon": "^7.5.0", + "@types/sinon": "^9.0.9", "@types/ws": "^6.0.3", "@types/yeoman-environment": "2.10.2", "@typescript-eslint/parser": "^2.30.0", @@ -143,9 +143,9 @@ "typescript": "^3.9.7", "chai": "^4.2.0", "copy-webpack-plugin": "^5.0.5", - "mocha": "^6.2.2", - "nyc": "^14.1.1", - "sinon": "^7.5.0", + "mocha": "^7.0.0", + "nyc": "^15.1.0", + "sinon": "^9.2.1", "ts-loader": "^6.2.1", "ts-node": "^8.9.1", "string-replace-loader": "^2.1.1", diff --git a/backend/src/code-snippet.ts b/backend/src/code-snippet.ts index e95be55..da94afe 100644 --- a/backend/src/code-snippet.ts +++ b/backend/src/code-snippet.ts @@ -1,5 +1,4 @@ import * as _ from "lodash"; -import * as Environment from "yeoman-environment"; import * as inquirer from "inquirer"; import { AppLog } from "./app-log"; import { AppEvents } from "./app-events"; @@ -8,6 +7,7 @@ import Generator = require("yeoman-generator"); import { IChildLogger } from "@vscode-logging/logger"; import TerminalAdapter = require("yeoman-environment/lib/adapter"); + export class CodeSnippet { private static funcReplacer(key: any, value: any) { @@ -24,7 +24,6 @@ export class CodeSnippet { private currentQuestions: TerminalAdapter.Questions; private snippetName: string; private readonly customQuestionEventHandlers: Map>; - private errorThrown = false; constructor(rpc: IRpc, appEvents: AppEvents, outputChannel: AppLog, logger: IChildLogger, uiOptions: any) { this.rpc = rpc; @@ -50,7 +49,17 @@ export class CodeSnippet { } private async getState() { - return this.uiOptions; + let state = _.omit(this.uiOptions, ["snippet"]); + try { + // valiation for rpc + JSON.stringify(state); + } catch (error) { + // save stateError and remove contributorInfo.context + state = _.omit(state, ["contributorInfo.context"]); + _.set(state, "stateError", true); + } + + return state; } public registerCustomQuestionEventHandler(questionType: string, methodName: string, handler: Function): void { @@ -165,7 +174,6 @@ export class CodeSnippet { } private async onFailure(snippetrName: string, error: any) { - this.errorThrown = true; const messagePrefix = `${snippetrName} snippet failed.`; const errorMessage: string = await this.logError(error, messagePrefix); this.appEvents.doSnippeDone(false, errorMessage); diff --git a/backend/src/contributors.ts b/backend/src/contributors.ts index 6c5ae0a..ebdaaf1 100644 --- a/backend/src/contributors.ts +++ b/backend/src/contributors.ts @@ -1,41 +1,51 @@ import * as vscode from 'vscode'; import * as _ from 'lodash'; +import { IChildLogger } from '@vscode-logging/logger'; +import { getClassLogger } from './logger/logger-wrapper'; + export class Contributors { - public static async getSnippet(contributerInfo: any) { - const contributorId = _.get(contributerInfo, "contributorId"); - const extension = Contributors.getContributorExtension(contributorId); + private readonly logger: IChildLogger; + + constructor() { + this.logger = getClassLogger("Contributors"); + } + + public async getSnippet(contributorInfo: any) { + const contributorId = _.get(contributorInfo, "contributorId"); + const extension = this.getContributorExtension(contributorId); if (extension) { try { const api = await this.getApiPromise(extension as vscode.Extension); - const snippetContext = _.get(contributerInfo, "context"); + const snippetContext = _.get(contributorInfo, "context"); const snippets = api.getCodeSnippets(snippetContext); - const snippetName = _.get(contributerInfo, "snippetName"); + const snippetName = _.get(contributorInfo, "snippetName"); return snippets.get(snippetName); } catch (error) { const errorMessage = _.get(error, "stack", _.get(error, "message", error)); - console.error(errorMessage); - // TODO: Add Logger.error + this.logger.error(`Could not get '${contributorId}' snippet`, errorMessage); } } } - private static getApiPromise(extension: vscode.Extension) { - return (extension.isActive ? extension.exports : extension.activate()); + private getApiPromise(extension: vscode.Extension): Thenable { + return (extension.isActive ? Promise.resolve(extension.exports) : extension.activate()); } - private static getContributorExtension(contributorId: string) { + private getContributorExtension(contributorId: string) { return _.find(vscode.extensions.all, (extension: vscode.Extension) => { const extensionDependencies: string[] = _.get(extension, "packageJSON.extensionDependencies"); if (_.includes(extensionDependencies, "saposs.code-snippet")) { - if (contributorId === Contributors.getExtensionId(extension)) { + if (contributorId === this.getExtensionId(extension)) { return extension; } } + + this.logger.warn(`Extension '${contributorId}' could not be found.`); }); } - private static getExtensionId(extension: vscode.Extension) { + private getExtensionId(extension: vscode.Extension) { const extensionName: string = _.get(extension, "packageJSON.name"); const extensionPublisher: string = _.get(extension, "packageJSON.publisher"); return `${extensionPublisher}.${extensionName}`; diff --git a/backend/src/extension.ts b/backend/src/extension.ts index 84cace0..03dadd5 100644 --- a/backend/src/extension.ts +++ b/backend/src/extension.ts @@ -29,8 +29,8 @@ function registerAndSubscribeCommand(cId: string, cAction: any) { function registerWebviewPanelSerializer(abstractPanel: AbstractWebviewPanel) { vscode.window.registerWebviewPanelSerializer(abstractPanel.viewType, { - async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, state?: any) { - abstractPanel.setWebviewPanel(webviewPanel, state); + async deserializeWebviewPanel(webViewPanel: vscode.WebviewPanel, state?: any) { + abstractPanel.setWebviewPanel(webViewPanel, state); } }); } diff --git a/backend/src/panels/AbstractWebviewPanel.ts b/backend/src/panels/AbstractWebviewPanel.ts index a523a87..1b81b69 100644 --- a/backend/src/panels/AbstractWebviewPanel.ts +++ b/backend/src/panels/AbstractWebviewPanel.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import * as _ from 'lodash'; import * as fsextra from 'fs-extra'; import { IChildLogger } from '@vscode-logging/logger'; -import { getLogger } from '../logger/logger-wrapper'; +import { getClassLogger } from '../logger/logger-wrapper'; export abstract class AbstractWebviewPanel { @@ -24,7 +24,7 @@ export abstract class AbstractWebviewPanel { this.extensionPath = context.extensionPath; this.mediaPath = path.join(context.extensionPath, "dist", "media"); this.htmlFileName = "index.html"; - this.logger = getLogger(); + this.logger = getClassLogger("AbstractWebviewPanel"); this.disposables = []; } diff --git a/backend/src/panels/CodeSnippetPanel.ts b/backend/src/panels/CodeSnippetPanel.ts index 4709ba3..a250ca6 100644 --- a/backend/src/panels/CodeSnippetPanel.ts +++ b/backend/src/panels/CodeSnippetPanel.ts @@ -15,7 +15,6 @@ import { Contributors } from "../contributors"; export class CodeSnippetPanel extends AbstractWebviewPanel { public static CODE_SNIPPET = "Code Snippet"; - private static channel: vscode.OutputChannel; public toggleOutput() { @@ -23,15 +22,22 @@ export class CodeSnippetPanel extends AbstractWebviewPanel { } public setWebviewPanel(webViewPanel: vscode.WebviewPanel, uiOptions?: any) { - super.setWebviewPanel(webViewPanel, uiOptions); + const contributorInfo = _.get(uiOptions, "contributorInfo", uiOptions); + + if (_.get(uiOptions, "stateError")) { + this.logger.error("test"); + this.logger.error(`'${contributorInfo.contributorId}' snippet state could not be saved. JSON.stringify issue.`); + return webViewPanel.dispose(); + } - const contributerInfo = _.get(uiOptions, "contributerInfo", uiOptions); - Contributors.getSnippet(contributerInfo).then(snippet => { + this.contributors.getSnippet(contributorInfo).then(snippet => { if (_.isNil(snippet)) { - this.webViewPanel.dispose(); - return vscode.window.showErrorMessage("Can not find snippet."); + this.logger.error(`'${contributorInfo.contributorId}' snippet could not be found.`); + return this.webViewPanel.dispose(); } + super.setWebviewPanel(webViewPanel, uiOptions); + this.messages = _.assign({}, backendMessages, snippet.getMessages()); const rpc = new RpcExtension(this.webViewPanel.webview); this.outputChannel = new OutputChannelLog(this.messages.channelName); @@ -40,7 +46,7 @@ export class CodeSnippetPanel extends AbstractWebviewPanel { vscodeEvents, this.outputChannel, this.logger, - { messages: this.messages, snippet, contributerInfo}); + { messages: this.messages, snippet, contributorInfo}); this.codeSnippet.registerCustomQuestionEventHandler("file-browser", "getFilePath", this.showOpenFileDialog.bind(this)); this.codeSnippet.registerCustomQuestionEventHandler("folder-browser", "getPath", this.showOpenFolderDialog.bind(this)); @@ -59,12 +65,14 @@ export class CodeSnippetPanel extends AbstractWebviewPanel { private codeSnippet: CodeSnippet; private messages: any; private outputChannel: AppLog; + private readonly contributors: Contributors; public constructor(context: vscode.ExtensionContext) { super(context); this.viewType = "codeSnippet"; this.viewTitle = CodeSnippetPanel.CODE_SNIPPET; this.focusedKey = "codeSnippet.Focused"; + this.contributors = new Contributors(); } private async showOpenFileDialog(currentPath: string): Promise { diff --git a/backend/tests/code-snippet.spec.ts b/backend/tests/code-snippet.spec.ts index 9d74568..8804764 100644 --- a/backend/tests/code-snippet.spec.ts +++ b/backend/tests/code-snippet.spec.ts @@ -4,7 +4,7 @@ const datauri = require("datauri"); // eslint-disable-line @typescript-eslint/no import * as fsextra from "fs-extra"; import { expect } from "chai"; import * as _ from "lodash"; -import {CodeSnippet} from "../src/code-snippet"; +import { CodeSnippet } from "../src/code-snippet"; import { AppLog } from "../src/app-log"; import { AppEvents } from '../src/app-events'; import { IMethod, IPromiseCallbacks, IRpc } from "@sap-devx/webview-rpc/out.ext/rpc-common"; @@ -31,30 +31,30 @@ describe('codeSnippet unit test', () => { } } class TestRpc implements IRpc { - public timeout: number; + public timeout: number; public promiseCallbacks: Map; public methods: Map; public sendRequest(): void { return; - } + } public sendResponse(): void { return; - } + } public setResponseTimeout(): void { return; } public registerMethod(): void { return; - } + } public unregisterMethod(): void { return; - } + } public listLocalMethods(): string[] { return []; } public handleResponse(): void { return; - } + } public listRemoteMethods(): Promise { return Promise.resolve([]); } @@ -68,31 +68,31 @@ describe('codeSnippet unit test', () => { class TestOutputChannel implements AppLog { public log(): void { return; - } + } public writeln(): void { return; - } + } public create(): void { return; - } + } public force(): void { return; - } + } public conflict(): void { return; - } + } public identical(): void { return; - } + } public skip(): void { return; - } + } public showOutput(): boolean { return false; - } + } } - const testLogger = { debug: () => "", error: () => "", fatal: () => "", warn: () => "", info: () => "", trace: () => "", getChildLogger: () => ({} as IChildLogger)}; + const testLogger = { debug: () => "", error: () => "", fatal: () => "", warn: () => "", info: () => "", trace: () => "", getChildLogger: () => ({} as IChildLogger) }; const snippet: any = { getMessages() { @@ -109,7 +109,7 @@ describe('codeSnippet unit test', () => { const rpc = new TestRpc(); const outputChannel = new TestOutputChannel(); const appEvents = new TestEvents(); - const uiOptions = {messages: {title: "snippet title"}, snippet: snippet}; + const uiOptions = { messages: { title: "snippet title" }, snippet: snippet }; const codeSnippet: CodeSnippet = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, uiOptions); before(() => { @@ -145,17 +145,25 @@ describe('codeSnippet unit test', () => { } }); - it("getState", async () => { - const state = await codeSnippet["getState"](); - expect(state).to.deep.equal(uiOptions); + describe("getState", () => { + it("valid uiOptions", async () => { + const state = await codeSnippet["getState"](); + expect(state.messages).to.be.not.empty; + }); + + it("invalid uiOptions", async () => { + codeSnippet["uiOptions"].test = codeSnippet["uiOptions"]; + const state = await codeSnippet["getState"](); + expect(state.stateError).to.be.true; + }); }); describe("receiveIsWebviewReady", () => { it("flow is successfull", async () => { rpcMock.expects("invoke").withArgs("showPrompt").resolves( - {actionName: "actionName"}, - {actionTemplate: "OData action"}, - {actionType: "Create entity"}); + { actionName: "actionName" }, + { actionTemplate: "OData action" }, + { actionType: "Create entity" }); appEventsMock.expects("doApply"); await codeSnippet["receiveIsWebviewReady"](); }); @@ -209,9 +217,9 @@ describe('codeSnippet unit test', () => { describe("answersUtils", () => { it("setDefaults", () => { const questions = [ - {name: "q1", default: "a"}, - {name: "q2", default: () => { return "b";}}, - {name: "q3"} + { name: "q1", default: "a" }, + { name: "q2", default: () => { return "b"; } }, + { name: "q3" } ]; const answers = { q1: "x", @@ -244,9 +252,9 @@ describe('codeSnippet unit test', () => { }; }; const codeSnippetInstance: CodeSnippet = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, {}); - const questions = [{name: "q1"}]; + const questions = [{ name: "q1" }]; const response = await codeSnippetInstance.showPrompt(questions); - expect (response.firstName).to.equal(firstName); + expect(response.firstName).to.equal(firstName); }); }); @@ -280,7 +288,7 @@ describe('codeSnippet unit test', () => { }; const questions = [ { - name:"q1", + name: "q1", guiType: "questionType" } ]; @@ -303,25 +311,29 @@ describe('codeSnippet unit test', () => { }; const codeSnippetInstance: CodeSnippet = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, {}); codeSnippetInstance.registerCustomQuestionEventHandler("questionType", "testEvent", testEventFunction); - codeSnippetInstance["currentQuestions"] = [{name:"question1", guiType: "questionType"}]; + codeSnippetInstance["currentQuestions"] = [{ name: "question1", guiType: "questionType" }]; const response = await codeSnippetInstance["evaluateMethod"](null, "question1", "testEvent"); expect(response).to.be.true; }); it("question method is called", async () => { const codeSnippetInstance: CodeSnippet = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, {}); - codeSnippetInstance["currentQuestions"] = [{name:"question1", method1:()=>{ - return true; - }}]; + codeSnippetInstance["currentQuestions"] = [{ + name: "question1", method1: () => { + return true; + } + }]; const response = await codeSnippetInstance["evaluateMethod"](null, "question1", "method1"); expect(response).to.be.true; }); it("no relevant question", async () => { const codeSnippetInstance: CodeSnippet = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, {}); - codeSnippetInstance["currentQuestions"] = [{name:"question1", method1:()=>{ - return true; - }}]; + codeSnippetInstance["currentQuestions"] = [{ + name: "question1", method1: () => { + return true; + } + }]; const response = await codeSnippetInstance["evaluateMethod"](null, "question2", "method2"); expect(response).to.be.undefined; }); @@ -336,12 +348,14 @@ describe('codeSnippet unit test', () => { const codeSnippetInstance: CodeSnippet = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, {}); codeSnippetInstance["gen"] = Object.create({}); codeSnippetInstance["gen"].options = {}; - codeSnippetInstance["currentQuestions"] = [{name:"question1", method1:()=>{ - throw new Error("Error"); - }}]; + codeSnippetInstance["currentQuestions"] = [{ + name: "question1", method1: () => { + throw new Error("Error"); + } + }]; try { await codeSnippetInstance["evaluateMethod"](null, "question1", "method1"); - } catch(e) { + } catch (e) { expect(e.toString()).to.contain("method1"); } }); @@ -353,7 +367,7 @@ describe('codeSnippet unit test', () => { let codeSnippetInstance: CodeSnippet; beforeEach(() => { - codeSnippetInstance = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, {messages: {title: title}}); + codeSnippetInstance = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, { messages: { title: title } }); codeSnippetInstanceMock = sandbox.mock(codeSnippetInstance); }); @@ -388,10 +402,10 @@ describe('codeSnippet unit test', () => { onFailureSpy.restore(); }); }); - + describe("createCodeSnippetWorkspaceEdit", () => { it("snippet has getWorkspaceEdit ---> call getWorkspaceEdit", async () => { - const myCodeSnippet = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, {snippet: snippet}); + const myCodeSnippet = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, { snippet: snippet }); const we = await myCodeSnippet["createCodeSnippetWorkspaceEdit"]({}); expect(we).to.be.equal("getWorkspaceEdit"); }); @@ -405,10 +419,16 @@ describe('codeSnippet unit test', () => { describe("createCodeSnippetQuestions", () => { it("snippet has getQuestions ---> call getQuestions", async () => { - const myCodeSnippet = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, {snippet: snippet}); + const myCodeSnippet = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, { snippet: snippet }); const we = await myCodeSnippet["createCodeSnippetQuestions"](); expect(we).to.be.equal("createCodeSnippetQuestions"); }); + + it("no snippet provided ---> call getQuestions", async () => { + const myCodeSnippet = new CodeSnippet(rpc, appEvents, outputChannel, testLogger, { snippet: null }); + const we = await myCodeSnippet["createCodeSnippetQuestions"](); + expect(we).to.be.empty; + }); }); describe("registerCustomQuestionEventHandler", () => { @@ -421,7 +441,7 @@ describe('codeSnippet unit test', () => { codeSnippetInstance.registerCustomQuestionEventHandler("questionType", "testEvent1", testEventFunction); expect(codeSnippetInstance["customQuestionEventHandlers"].size).to.be.equal(1); - codeSnippetInstance.registerCustomQuestionEventHandler("questionType", "testEvent2", testEventFunction); + codeSnippetInstance.registerCustomQuestionEventHandler("questionType", "testEvent2", testEventFunction); expect(codeSnippetInstance["customQuestionEventHandlers"].size).to.be.equal(1); }); diff --git a/backend/tests/contributors.spec.ts b/backend/tests/contributors.spec.ts index ad82724..43eadbe 100644 --- a/backend/tests/contributors.spec.ts +++ b/backend/tests/contributors.spec.ts @@ -1,6 +1,7 @@ import * as mocha from 'mocha'; import { expect } from 'chai'; import * as _ from 'lodash'; +import * as sinon from "sinon"; import { mockVscode } from './mockUtil'; const testVscode = {}; @@ -8,8 +9,33 @@ _.set(testVscode, "extensions.all", []); mockVscode(testVscode, "src/contributors.ts"); import { Contributors } from "../src/contributors"; +import * as loggerWrapper from "../src/logger/logger-wrapper"; + describe('Contributors unit test', () => { + let sandbox: any; + let loggerWrapperMock: any; + const logger = { + error: () => "", + warn: () => "" + }; + + before(() => { + sandbox = sinon.createSandbox(); + }); + + after(() => { + sandbox.restore(); + }); + + beforeEach(() => { + loggerWrapperMock = sandbox.mock(loggerWrapper); + }); + + afterEach(() => { + loggerWrapperMock.verify(); + }); + describe('getSnippet', () => { function createCodeSnippetQuestions(): any[] { const questions: any[] = [{ @@ -77,10 +103,11 @@ describe('Contributors unit test', () => { } }; const extensionId = "BLABLA3.vscode-snippet-contrib"; - + it("receives no contributorId and no snippetName ---> returns undefined snippet", async () => { - const uiOptions = {}; - const snippet = await Contributors.getSnippet(uiOptions); + loggerWrapperMock.expects("getClassLogger").returns(logger); + const contributors = new Contributors(); + const snippet = await contributors.getSnippet({}); expect(snippet).to.be.undefined; }); @@ -91,7 +118,10 @@ describe('Contributors unit test', () => { "contributorId": extensionId, "snippetName": snippetName }; - const snippet = await Contributors.getSnippet(uiOptions); + + loggerWrapperMock.expects("getClassLogger").returns(logger); + const contributors = new Contributors(); + const snippet = await contributors.getSnippet(uiOptions); expect(snippet.getMessages()).to.deep.equal(messageValue); }); @@ -103,7 +133,10 @@ describe('Contributors unit test', () => { "contributorId": extensionId, "snippetName": snippetName }; - const snippet = await Contributors.getSnippet(uiOptions); + + loggerWrapperMock.expects("getClassLogger").returns(logger); + const contributors = new Contributors(); + const snippet = await contributors.getSnippet(uiOptions); expect(snippet.getMessages()).to.deep.equal(messageValue); }); @@ -118,11 +151,17 @@ describe('Contributors unit test', () => { "contributorId": extensionId, "snippetName": snippetName }; - const res = await Contributors.getSnippet(uiOptions); + + loggerWrapperMock.expects("getClassLogger").returns(logger); + const errorSpy = sinon.spy(logger, "error"); + const contributors = new Contributors(); + const res = await contributors.getSnippet(uiOptions); expect(res).to.be.undefined; + expect(errorSpy.calledOnce).to.be.true; + errorSpy.restore(); }); - it("no contributer extension not found", async () => { + it("contributer extension not found", async () => { api.packageJSON = { name: "vscode-snippet-contrib", publisher: "BLABLA3", @@ -134,11 +173,17 @@ describe('Contributors unit test', () => { "contributorId": extensionId, "snippetName": snippetName }; - const res = await Contributors.getSnippet(uiOptions); + + loggerWrapperMock.expects("getClassLogger").returns(logger); + const contributors = new Contributors(); + const warnSpy = sinon.spy(logger, "warn"); + const res = await contributors.getSnippet(uiOptions); expect(res).to.be.undefined; + expect(warnSpy.calledOnce).to.be.true; + warnSpy.restore(); }); - it("no contributer extension not found by contributorId", async () => { + it("contributer extension not found by contributorId", async () => { api.packageJSON = { name: "vscode-snippet-contrib", publisher: "BLABLA3", @@ -150,8 +195,15 @@ describe('Contributors unit test', () => { "contributorId": extensionId + "-other", "snippetName": snippetName }; - const res = await Contributors.getSnippet(uiOptions); + + loggerWrapperMock.expects("getClassLogger").returns(logger); + const warnSpy = sinon.spy(logger, "warn"); + const contributors = new Contributors(); + const res = await contributors.getSnippet(uiOptions); expect(res).to.be.undefined; + const warnMessage = `Extension '${uiOptions.contributorId}' could not be found.`; + expect(warnSpy.calledOnce).to.be.true; + warnSpy.restore(); }); }); }); diff --git a/backend/tests/extension.spec.ts b/backend/tests/extension.spec.ts index d273fd3..3289c34 100644 --- a/backend/tests/extension.spec.ts +++ b/backend/tests/extension.spec.ts @@ -3,7 +3,6 @@ import { expect } from "chai"; import * as sinon from "sinon"; import * as _ from "lodash"; import { mockVscode } from "./mockUtil"; -import { Contributors } from "../src/contributors"; const oRegisteredCommands = {}; const testVscode = { @@ -59,7 +58,7 @@ describe('extension unit test', () => { describe('activate', () => { it("commands registration", () => { loggerWrapperMock.expects("createExtensionLoggerAndSubscribeToLogSettingsChanges"); - loggerWrapperMock.expects("getLogger").once(); + loggerWrapperMock.expects("getClassLogger").twice(); extension.activate(testContext); expect(_.size(_.keys(oRegisteredCommands))).to.be.equal(2); expect( _.get(oRegisteredCommands, "loadCodeSnippet")).to.be.not.undefined; diff --git a/frontend/package.json b/frontend/package.json index 6c6fdc2..97fff92 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,11 +26,11 @@ "material-design-icons-iconfont": "6.1.0", "vue": "2.6.12", "vue-loading-overlay": "3.3.0", - "vuetify": "2.3.10" + "vuetify": "2.3.10", + "@sap-devx/webview-rpc": "0.2.3" }, "devDependencies": { "@babel/preset-env": "7.11.5", - "@sap-devx/webview-rpc": "0.2.3", "@vue/cli-plugin-babel": "4.5.4", "@vue/cli-plugin-eslint": "4.5.4", "@vue/cli-plugin-unit-jest": "4.5.4",