Skip to content

Commit

Permalink
fix: [DEVXBUGS-10337] project templates are not refreshed when genera…
Browse files Browse the repository at this point in the history
…tors installed in background (#712)
  • Loading branch information
alex-gilin authored Jul 20, 2022
1 parent 303371f commit 95c07f3
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 34 deletions.
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@
]
},
"scripts": {
"release:version": "lerna version",
"release:publish": "lerna publish from-git --yes",
"ci": "npm-run-all coverage:clean format:validate lint:validate legal:* ci:subpackages coverage:merge",
"ci:subpackages": "lerna run ci",
"compile": "lerna run clean && tsc --build",
"compile:watch": "lerna run clean && tsc --build --watch",
"coverage:clean": "rimraf ./coverage",
"coverage:merge": "lcov-result-merger \"./coverage/lcov*.info\" \"./coverage/lcov.info\"",
"format:fix": "prettier --print-width 120 --write \"**/*.@(js|ts|json|md|vue)\" --ignore-path=.gitignore",
"format:validate": "prettier --print-width 120 --check \"**/*.@(js|ts|json|md|vue)\" --ignore-path=.gitignore",
"legal:copy": "lerna exec \"shx cp -r ../../.reuse .reuse && shx cp -r ../../LICENSES LICENSES\"",
"legal:delete": "lerna exec \"shx rm -rf .reuse LICENSES\" || true",
"lint:fix": "eslint . --ext=js,ts,vue --fix --max-warnings=0 --ignore-path=.gitignore",
"lint:validate": "eslint . --ext=js,ts,vue --max-warnings=0 --ignore-path=.gitignore",
"coverage:clean": "rimraf ./coverage",
"coverage:merge": "lcov-result-merger \"./coverage/lcov*.info\" \"./coverage/lcov.info\"",
"legal:delete": "lerna exec \"shx rm -rf .reuse LICENSES\" || true",
"legal:copy": "lerna exec \"shx cp -r ../../.reuse .reuse && shx cp -r ../../LICENSES LICENSES\""
"release:publish": "lerna publish from-git --yes",
"release:version": "lerna version"
},
"husky": {
"hooks": {
Expand Down
10 changes: 5 additions & 5 deletions packages/backend/.nycrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"src/utils/npm.ts",
"src/utils/customLocation.ts",
"src/swa-tracker/*.ts",
"src/panels/*.ts",
"src/panels/[Abs|Exp]*.ts",
"src/images/*.ts",
"src/webSocketServer/*.ts",
"src/vscode-output.ts",
Expand All @@ -21,8 +21,8 @@
"extension": [".ts"],
"all": true,
"check-coverage": true,
"branches": 89,
"lines": 94,
"functions": 90,
"statements": 94
"branches": 91,
"lines": 93,
"functions": 89,
"statements": 93
}
5 changes: 3 additions & 2 deletions packages/backend/src/panels/YeomanUIPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class YeomanUIPanel extends AbstractWebviewPanel {
} else {
yeomanUi._notifyGeneratorsInstall(this.installGens);
if (isEmpty(this.installGens)) {
Env.loadNpmPath(true); // force to reload the env existing npm paths
yeomanUi._notifyGeneratorsChange();
this.installGens = undefined;
}
Expand Down Expand Up @@ -114,11 +115,11 @@ export class YeomanUIPanel extends AbstractWebviewPanel {
}

private async showOpenFileDialog(currentPath: string): Promise<string> {
return await this.showOpenDialog(currentPath, true);
return this.showOpenDialog(currentPath, true);
}

private async showOpenFolderDialog(currentPath: string): Promise<string> {
return await this.showOpenDialog(currentPath, false);
return this.showOpenDialog(currentPath, false);
}

private async showOpenDialog(currentPath: string, canSelectFiles: boolean): Promise<string> {
Expand Down
20 changes: 19 additions & 1 deletion packages/backend/src/utils/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { isWin32, NpmCommand } from "./npm";
import * as customLocation from "./customLocation";
import * as Environment from "yeoman-environment";
import TerminalAdapter = require("yeoman-environment/lib/adapter");
import { IChildLogger } from "@vscode-logging/logger";
import { getClassLogger } from "../logger/logger-wrapper";

const GENERATOR = "generator-";
const NAMESPACE = "namespace";
Expand All @@ -27,11 +29,27 @@ export class GeneratorNotFoundError extends Error {
}

class EnvUtil {
private logger: IChildLogger;
private existingNpmPathsPromise: Promise<string[]>;
private allInstalledGensMeta: Environment.LookupGeneratorMeta[];

constructor() {
this.existingNpmPathsPromise = this.getExistingNpmPath();
try {
this.logger = getClassLogger(EnvUtil.name);
} catch (e) {
// nothing TODO : testing scope
}
this.loadNpmPath();
}

public loadNpmPath(force = false) {
if (_.isNil(this.existingNpmPathsPromise) || force === true) {
this.existingNpmPathsPromise = this.getExistingNpmPath().then((paths) => {
this.logger?.debug("existing npm paths", { paths: paths.join(";") });
return paths;
});
}
return this;
}

private getEnvNpmPath(): Promise<string[]> {
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/src/utils/vscodeProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const Uri = {
const workspace = {
getConfiguration: () => configObj,
updateWorkspaceFolders: returnValue,
workspaceFolders: [Uri.file()],
};

const oRegisteredCommands = {};
Expand All @@ -66,6 +67,9 @@ const window = {
createWebviewPanel: returnPromise,
showQuickPick: returnPromise,
createOutputChannel: returnValue,
showOpenDialog: () => {
throw new Error("not implemented");
},
};

const ViewColumn = {
Expand Down
128 changes: 128 additions & 0 deletions packages/backend/test/panels/YeomanUIPanel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import * as YeomanUIPanel from "../../src/panels/YeomanUIPanel";
import { Env } from "../../src/utils/env";
import { Constants } from "../../src/utils/constants";
import { NpmCommand } from "../../src/utils/npm";
import { YeomanUI } from "../../src/yeomanui";
import { set } from "lodash";
import { expect } from "chai";
import { join } from "path";
import { homedir } from "os";

describe("YeomanUIPanel unit test", () => {
let sandbox: SinonSandbox;
Expand Down Expand Up @@ -126,4 +131,127 @@ describe("YeomanUIPanel unit test", () => {
});
});
});

describe("toggleOutput", () => {
let mockOutput: SinonMock;
beforeEach(() => {
mockOutput = sandbox.mock(panel["output"]);
});

afterEach(() => {
mockOutput.verify();
});

it("toggleOutput - output exists", () => {
mockOutput.expects("show").returns(undefined);
panel.toggleOutput();
});
});

describe("notifyGeneratorsChange", () => {
let mockYeomanui: SinonMock;
const objYeomanui: Partial<YeomanUI> = {
_notifyGeneratorsChange: () => Promise.resolve(),
_notifyGeneratorsInstall: () => Promise.resolve(),
};

beforeEach(() => {
mockYeomanui = sandbox.mock(objYeomanui);
});

afterEach(() => {
mockYeomanui.verify();
});

it("notifyGeneratorsChange - no args received", () => {
set(panel, "yeomanui", objYeomanui);
mockYeomanui.expects("_notifyGeneratorsChange");
panel.notifyGeneratorsChange();
});

it("notifyGeneratorsChange - args provided", () => {
set(panel, "yeomanui", objYeomanui);
const args = ["gen"];
mockYeomanui.expects("_notifyGeneratorsInstall").withExactArgs(args);
mockYeomanui.expects("_notifyGeneratorsChange").never();
panel.notifyGeneratorsChange(args);
});

it("notifyGeneratorsChange - empty args provided", () => {
set(panel, "yeomanui", objYeomanui);
const args: any[] = [];
mockYeomanui.expects("_notifyGeneratorsInstall").withExactArgs(args);
mockYeomanui.expects("_notifyGeneratorsChange");
envUtilsMock.expects("loadNpmPath").withExactArgs(true);
panel.notifyGeneratorsChange(args);
expect(panel["installGens"]).to.be.undefined;
});

it("notifyGeneratorsChange - yeomanui object does not exist on the panel", () => {
set(panel, "yeomanui", undefined);
panel.notifyGeneratorsChange();
expect(panel["installGens"]).to.be.undefined;
});
});

describe("showOpenDialog", () => {
const selected = vscode.Uri.file("selected");
const required = "some/path/file";

it("showOpenFileDialog", async () => {
const spyShowOpen = sandbox.stub(panel, <any>"showOpenDialog").returns(selected.fsPath);
expect(await panel["showOpenFileDialog"](required)).be.equal(selected.fsPath);
spyShowOpen.calledWithExactly(required, true);
});

it("showOpenFolderDialog", async () => {
const spyShowOpen = sandbox.stub(panel, <any>"showOpenDialog").returns(selected.fsPath);
expect(await panel["showOpenFolderDialog"](required)).be.equal(selected.fsPath);
spyShowOpen.calledWithExactly(required, false);
});

it("showOpenDialog - empty path provided, ws folder exists", async () => {
const canSelectFiles = true;
const objWs = [{ uri: { fsPath: "rootFolderPath" } }];
sandbox.stub(vscode.workspace, "workspaceFolders").value(objWs);
windowMock
.expects("showOpenDialog")
.withExactArgs({ canSelectFiles, canSelectFolders: !canSelectFiles, defaultUri: objWs[0].uri })
.resolves([selected]);
expect(await panel["showOpenDialog"]("", canSelectFiles)).to.equal(selected.fsPath);
});

it("showOpenDialog - empty path provided, ws folder not exists", async () => {
const canSelectFiles = false;
const objWs = [{}];
sandbox.stub(vscode.workspace, "workspaceFolders").value(objWs);
windowMock
.expects("showOpenDialog")
.withExactArgs({
canSelectFiles,
canSelectFolders: !canSelectFiles,
defaultUri: vscode.Uri.file(join(homedir())),
})
.resolves([selected]);
expect(await panel["showOpenDialog"](undefined, canSelectFiles)).to.equal(selected.fsPath);
});

it("showOpenDialog - path provided", async () => {
const canSelectFiles = false;
windowMock
.expects("showOpenDialog")
.withExactArgs({ canSelectFiles, canSelectFolders: !canSelectFiles, defaultUri: vscode.Uri.file(required) })
.resolves([selected]);
expect(await panel["showOpenDialog"](required, canSelectFiles)).to.equal(selected.fsPath);
});

it("showOpenDialog - path provided, showOpen throws error", async () => {
const canSelectFiles = true;
windowMock
.expects("showOpenDialog")
.withExactArgs({ canSelectFiles, canSelectFolders: !canSelectFiles, defaultUri: vscode.Uri.file(required) })
.throws(new Error("unexpected"));
expect(await panel["showOpenDialog"](required, canSelectFiles)).to.equal(required);
});
});
});
43 changes: 23 additions & 20 deletions packages/backend/test/yeomanui.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ describe("yeomanui unit test", () => {
});

it("there are no generators", async () => {
envUtilsMock.expects("getGeneratorsData").resolves([]);
envUtilsMock.expects("getGeneratorsData").withExactArgs().resolves([]);
const result = await yeomanUi["getGeneratorsPrompt"]();
const generatorQuestion: any = {
type: "list",
Expand All @@ -499,7 +499,7 @@ describe("yeomanui unit test", () => {

it("get generators with type project", async () => {
wsConfigMock.expects("get").withExactArgs("ApplicationWizard.Workspace").returns({});
envUtilsMock.expects("getGeneratorsData").resolves(gensMeta);
envUtilsMock.expects("getGeneratorsData").withExactArgs().resolves(gensMeta);
wsConfigMock.expects("get").withExactArgs(yeomanUi["TARGET_FOLDER_CONFIG_PROP"]);
const genFilter: GeneratorFilter = GeneratorFilter.create({
type: "project",
Expand All @@ -518,7 +518,7 @@ describe("yeomanui unit test", () => {
});

it("get generators with type module", async () => {
envUtilsMock.expects("getGeneratorsData").resolves(gensMeta);
envUtilsMock.expects("getGeneratorsData").withExactArgs().resolves(gensMeta);
const genFilter = GeneratorFilter.create({ type: "module" });
yeomanUi["uiOptions"] = { filter: genFilter, messages };
const result = await yeomanUi["getGeneratorsPrompt"]();
Expand All @@ -542,19 +542,22 @@ describe("yeomanui unit test", () => {

it("wrong generators filter type is provided", async () => {
wsConfigMock.expects("get").withExactArgs("ApplicationWizard.Workspace").returns({});
envUtilsMock.expects("getGeneratorsData").resolves([
{
generatorMeta: {
generatorPath: "test1Path/app/index.js",
namespace: "test1:app",
packagePath: "test1Path",
},
generatorPackageJson: {
"generator-filter": { type: "project123" },
description: "test4Description",
envUtilsMock
.expects("getGeneratorsData")
.withExactArgs()
.resolves([
{
generatorMeta: {
generatorPath: "test1Path/app/index.js",
namespace: "test1:app",
packagePath: "test1Path",
},
generatorPackageJson: {
"generator-filter": { type: "project123" },
description: "test4Description",
},
},
},
]);
]);

wsConfigMock.expects("get").withExactArgs(yeomanUi["TARGET_FOLDER_CONFIG_PROP"]);
yeomanUi["uiOptions"] = {
Expand Down Expand Up @@ -583,7 +586,7 @@ describe("yeomanui unit test", () => {
"generator-filter": { type: "project", categories: ["cat1"] },
description: "test4Description",
};
envUtilsMock.expects("getGeneratorsData").resolves(gensMeta);
envUtilsMock.expects("getGeneratorsData").withExactArgs().resolves(gensMeta);

const genFilter: GeneratorFilter = GeneratorFilter.create({
type: ["project"],
Expand All @@ -608,7 +611,7 @@ describe("yeomanui unit test", () => {
description: "test3Description",
displayName: "3rd - Test",
};
envUtilsMock.expects("getGeneratorsData").resolves(gensMeta.slice(0, 3));
envUtilsMock.expects("getGeneratorsData").withExactArgs().resolves(gensMeta.slice(0, 3));

yeomanUi["uiOptions"] = {
filter: GeneratorFilter.create({ type: undefined }),
Expand Down Expand Up @@ -638,7 +641,7 @@ describe("yeomanui unit test", () => {
homepage: "https://myhomepage.com/ANY/generator-test2-module#readme",
};

envUtilsMock.expects("getGeneratorsData").resolves(gensMeta.slice(0, 3));
envUtilsMock.expects("getGeneratorsData").withExactArgs().resolves(gensMeta.slice(0, 3));

yeomanUi["uiOptions"] = { filter: GeneratorFilter.create(), messages };
const result = await yeomanUi["getGeneratorsPrompt"]();
Expand All @@ -654,7 +657,7 @@ describe("yeomanui unit test", () => {
});

it("generator with type project", async () => {
envUtilsMock.expects("getGeneratorsData").resolves(gensMeta.slice(0, 1));
envUtilsMock.expects("getGeneratorsData").withExactArgs().resolves(gensMeta.slice(0, 1));
_.set(vscode, "workspace.workspaceFolders", [
{ uri: { fsPath: "rootFolderPath" } },
{ uri: { fsPath: "testRoot" } },
Expand All @@ -674,7 +677,7 @@ describe("yeomanui unit test", () => {
"generator-filter": { type: "tools-suite" },
description: "test4Description",
};
envUtilsMock.expects("getGeneratorsData").resolves(gensMeta.slice(0, 1));
envUtilsMock.expects("getGeneratorsData").withExactArgs().resolves(gensMeta.slice(0, 1));
_.set(vscode, "workspace.workspaceFolders", [
{ uri: { fsPath: "rootFolderPath" } },
{ uri: { fsPath: "testRoot" } },
Expand Down

0 comments on commit 95c07f3

Please sign in to comment.