-
Notifications
You must be signed in to change notification settings - Fork 197
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf: refresh add plugin treeview item (#12376)
* perf: refresh add plugin treeview item * test: ut
- Loading branch information
1 parent
7a85440
commit bc1eb6c
Showing
10 changed files
with
294 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT license. | ||
|
||
"use strict"; | ||
|
||
import * as vscode from "vscode"; | ||
import { | ||
isDeclarativeCopilotApp, | ||
updateIsDeclarativeCopilotApp, | ||
workspaceUri, | ||
} from "./globalVariables"; | ||
import path from "path"; | ||
import { | ||
AppPackageFolderName, | ||
ManifestTemplateFileName, | ||
TeamsAppManifest, | ||
} from "@microsoft/teamsfx-api"; | ||
import TreeViewManagerInstance from "./treeview/treeViewManager"; | ||
import { ExtTelemetry } from "./telemetry/extTelemetry"; | ||
import { TelemetryEvent, TelemetryProperty } from "./telemetry/extTelemetryEvents"; | ||
import { isValidProjectV3 } from "@microsoft/teamsfx-core"; | ||
|
||
function setAbortableTimeout(ms: number, signal: any) { | ||
return new Promise((resolve, reject) => { | ||
const timeoutId = setTimeout(() => { | ||
// Resolve the promise after 5 seconds | ||
resolve("After timeout. Checking app."); | ||
}, ms); | ||
|
||
// Listen for the abort event | ||
signal.addEventListener("abort", () => { | ||
// Clear the timeout and reject the promise if aborted | ||
clearTimeout(timeoutId); | ||
reject("resolved after clear"); | ||
}); | ||
}); | ||
} | ||
|
||
export function manifestListener(): vscode.Disposable { | ||
let abortController: undefined | AbortController; | ||
const disposable = vscode.workspace.onDidSaveTextDocument( | ||
async (event): Promise<boolean | undefined> => { | ||
try { | ||
if ( | ||
workspaceUri && | ||
isValidProjectV3(workspaceUri.fsPath) && | ||
event.fileName === | ||
path.join(workspaceUri.fsPath, AppPackageFolderName, ManifestTemplateFileName) | ||
) { | ||
if (abortController) { | ||
abortController.abort(); | ||
} | ||
abortController = new AbortController(); | ||
|
||
await setAbortableTimeout(5000, abortController.signal); | ||
if (!abortController.signal.aborted) { | ||
const currValue = isDeclarativeCopilotApp; | ||
const manifest: TeamsAppManifest = JSON.parse(event.getText()); | ||
const newValue = updateIsDeclarativeCopilotApp(manifest); | ||
if (currValue !== newValue) { | ||
ExtTelemetry.sendTelemetryEvent(TelemetryEvent.UpdateAddPluginTreeview, { | ||
[TelemetryProperty.ShowAddPluginTreeView]: newValue.toString(), | ||
}); | ||
TreeViewManagerInstance.updateDevelopmentTreeView(); | ||
} | ||
|
||
return currValue !== newValue; | ||
} | ||
} | ||
} catch (error) {} | ||
} | ||
); | ||
|
||
return disposable; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
180 changes: 180 additions & 0 deletions
180
packages/vscode-extension/test/handlers/manifestListener.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
import * as chai from "chai"; | ||
import * as sinon from "sinon"; | ||
import * as vscode from "vscode"; | ||
import * as globalVariables from "../../src/globalVariables"; | ||
import { manifestListener } from "../../src/manifestListener"; | ||
import { TeamsAppManifest } from "@microsoft/teamsfx-api"; | ||
import path from "path"; | ||
import TreeViewManagerInstance from "../../src/treeview/treeViewManager"; | ||
import * as projectSettingsHelper from "@microsoft/teamsfx-core/build/common/projectSettingsHelper"; | ||
import { ExtTelemetry } from "../../src/telemetry/extTelemetry"; | ||
|
||
describe("registerManifestListener", () => { | ||
const sandbox = sinon.createSandbox(); | ||
let clock: sinon.SinonFakeTimers; | ||
|
||
beforeEach(() => { | ||
sandbox.stub(ExtTelemetry, "sendTelemetryEvent").returns(); | ||
}); | ||
|
||
afterEach(() => { | ||
sandbox.restore(); | ||
if (clock) { | ||
clock.restore(); | ||
} | ||
}); | ||
it("successfully refresh item", async () => { | ||
clock = sandbox.useFakeTimers(); | ||
let handler = async (event: any) => {}; | ||
sandbox.stub(projectSettingsHelper, "isValidProjectV3").returns(true); | ||
sandbox.stub(vscode.workspace, "onDidSaveTextDocument").callsFake((listener: any) => { | ||
handler = listener; | ||
return new vscode.Disposable(() => { | ||
return; | ||
}); | ||
}); | ||
sandbox.stub(globalVariables, "isDeclarativeCopilotApp").value(false); | ||
sandbox.stub(globalVariables, "workspaceUri").value(vscode.Uri.file(".")); | ||
sandbox | ||
.stub(globalVariables, "updateIsDeclarativeCopilotApp") | ||
.onFirstCall() | ||
.returns(true) | ||
.onSecondCall() | ||
.returns(false); | ||
sandbox.stub(TreeViewManagerInstance, "updateDevelopmentTreeView").returns(); | ||
|
||
const fakeDocument = { | ||
fileName: path.join(vscode.Uri.file(".").fsPath, "appPackage", "manifest.json"), | ||
getText: () => { | ||
return JSON.stringify(new TeamsAppManifest()); | ||
}, | ||
}; | ||
|
||
manifestListener(); | ||
let job = handler(fakeDocument); | ||
|
||
await clock.tickAsync(5000); | ||
let res = await job; | ||
chai.assert.isTrue(res); | ||
|
||
job = handler(fakeDocument); | ||
await clock.tickAsync(5000); | ||
res = await job; | ||
chai.assert.isFalse(res); | ||
}); | ||
|
||
it("abort previous one", async () => { | ||
clock = sandbox.useFakeTimers(); | ||
let handler = async (event: any) => {}; | ||
sandbox.stub(projectSettingsHelper, "isValidProjectV3").returns(true); | ||
sandbox.stub(vscode.workspace, "onDidSaveTextDocument").callsFake((listener: any) => { | ||
handler = listener; | ||
return new vscode.Disposable(() => { | ||
return; | ||
}); | ||
}); | ||
sandbox.stub(globalVariables, "isDeclarativeCopilotApp").value(false); | ||
sandbox.stub(globalVariables, "workspaceUri").value(vscode.Uri.file(".")); | ||
sandbox | ||
.stub(globalVariables, "updateIsDeclarativeCopilotApp") | ||
.onFirstCall() | ||
.returns(true) | ||
.onSecondCall() | ||
.returns(false); | ||
sandbox.stub(TreeViewManagerInstance, "updateDevelopmentTreeView").returns(); | ||
|
||
const fakeDocument = { | ||
fileName: path.join(vscode.Uri.file(".").fsPath, "appPackage", "manifest.json"), | ||
getText: () => { | ||
return JSON.stringify(new TeamsAppManifest()); | ||
}, | ||
}; | ||
|
||
manifestListener(); | ||
const job1 = handler(fakeDocument); | ||
await clock.tickAsync(1000); | ||
const job2 = handler(fakeDocument); | ||
|
||
await clock.tickAsync(5000); | ||
const res1 = await job1; | ||
const res2 = await job2; | ||
|
||
chai.assert.isUndefined(res1); | ||
chai.assert.isTrue(res2); | ||
}); | ||
|
||
it("not run if invalid project", async () => { | ||
clock = sandbox.useFakeTimers(); | ||
let handler = async (event: any) => {}; | ||
sandbox.stub(projectSettingsHelper, "isValidProjectV3").returns(false); | ||
sandbox.stub(globalVariables, "workspaceUri").value(vscode.Uri.file(".")); | ||
sandbox.stub(vscode.workspace, "onDidSaveTextDocument").callsFake((listener: any) => { | ||
handler = listener; | ||
return new vscode.Disposable(() => { | ||
return; | ||
}); | ||
}); | ||
|
||
const fakeDocument = { | ||
fileName: path.join(vscode.Uri.file(".").fsPath, "appPackage", "manifest.json"), | ||
getText: () => { | ||
return JSON.stringify(new TeamsAppManifest()); | ||
}, | ||
}; | ||
|
||
manifestListener(); | ||
const res = await handler(fakeDocument); | ||
|
||
chai.assert.isUndefined(res); | ||
}); | ||
|
||
it("not run if empty workspace", async () => { | ||
clock = sandbox.useFakeTimers(); | ||
let handler = async (event: any) => {}; | ||
sandbox.stub(globalVariables, "workspaceUri").value(""); | ||
sandbox.stub(projectSettingsHelper, "isValidProjectV3").returns(false); | ||
sandbox.stub(vscode.workspace, "onDidSaveTextDocument").callsFake((listener: any) => { | ||
handler = listener; | ||
return new vscode.Disposable(() => { | ||
return; | ||
}); | ||
}); | ||
|
||
const fakeDocument = { | ||
fileName: path.join(vscode.Uri.file(".").fsPath, "appPackage", "manifest.json"), | ||
getText: () => { | ||
return JSON.stringify(new TeamsAppManifest()); | ||
}, | ||
}; | ||
|
||
manifestListener(); | ||
const res = await handler(fakeDocument); | ||
|
||
chai.assert.isUndefined(res); | ||
}); | ||
|
||
it("not run if not default app manifest", async () => { | ||
clock = sandbox.useFakeTimers(); | ||
let handler = async (event: any) => {}; | ||
sandbox.stub(globalVariables, "workspaceUri").value("."); | ||
sandbox.stub(projectSettingsHelper, "isValidProjectV3").returns(false); | ||
sandbox.stub(vscode.workspace, "onDidSaveTextDocument").callsFake((listener: any) => { | ||
handler = listener; | ||
return new vscode.Disposable(() => { | ||
return; | ||
}); | ||
}); | ||
|
||
const fakeDocument = { | ||
fileName: path.join(vscode.Uri.file(".").fsPath, "appPackage", "unknown.json"), | ||
getText: () => { | ||
return JSON.stringify(new TeamsAppManifest()); | ||
}, | ||
}; | ||
|
||
manifestListener(); | ||
const res = await handler(fakeDocument); | ||
|
||
chai.assert.isUndefined(res); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters