From 95350a88515d2bec7b285478745b618d677544f7 Mon Sep 17 00:00:00 2001 From: Michael Anstis Date: Fri, 29 Nov 2024 15:49:20 +0000 Subject: [PATCH] =?UTF-8?q?AAP-34645:=20Add=20=E2=80=9CGenerate=20a=20Play?= =?UTF-8?q?book=E2=80=9D=20Button=20to=20Side=20Panel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/lightspeed/utils/explorerView.ts | 10 + src/webview/apps/lightspeed/explorer/main.ts | 8 + test/ui-test/lightspeedUiTestExplorer.ts | 271 ++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 test/ui-test/lightspeedUiTestExplorer.ts diff --git a/src/features/lightspeed/utils/explorerView.ts b/src/features/lightspeed/utils/explorerView.ts index 60314258c..bcc33f6f2 100644 --- a/src/features/lightspeed/utils/explorerView.ts +++ b/src/features/lightspeed/utils/explorerView.ts @@ -70,6 +70,12 @@ export function getWebviewContentWithActiveSession( "style.css", ]); const nonce = getNonce(); + const generateForm = `
+
+ Generate a playbook + +
+
`; const explainForm = `
${content} + ${generateForm} ${explainForm}
@@ -120,6 +127,9 @@ export function setWebviewMessageListener( case "connect": commands.executeCommand("ansible.lightspeed.oauth"); return; + case "generate": + commands.executeCommand("ansible.lightspeed.playbookGeneration"); + return; case "explain": commands.executeCommand("ansible.lightspeed.playbookExplanation"); return; diff --git a/src/webview/apps/lightspeed/explorer/main.ts b/src/webview/apps/lightspeed/explorer/main.ts index a253d977b..118ebc1ab 100644 --- a/src/webview/apps/lightspeed/explorer/main.ts +++ b/src/webview/apps/lightspeed/explorer/main.ts @@ -19,6 +19,10 @@ function setListener(id: string, func: any) { function main() { setListener("lightspeed-explorer-connect", lightspeedConnect); + setListener( + "lightspeed-explorer-playbook-generation-submit", + lightspeedExplorerPlaybookGeneration, + ); setListener( "lightspeed-explorer-playbook-explanation-submit", lightspeedExplorerPlaybookExplanation, @@ -29,6 +33,10 @@ function lightspeedConnect() { vscode.postMessage({ command: "connect" }); } +function lightspeedExplorerPlaybookGeneration() { + vscode.postMessage({ command: "generate" }); +} + function lightspeedExplorerPlaybookExplanation() { vscode.postMessage({ command: "explain" }); } diff --git a/test/ui-test/lightspeedUiTestExplorer.ts b/test/ui-test/lightspeedUiTestExplorer.ts new file mode 100644 index 000000000..458353bfd --- /dev/null +++ b/test/ui-test/lightspeedUiTestExplorer.ts @@ -0,0 +1,271 @@ +import { + ActionsControl, + ActivityBar, + By, + ContextMenu, + EditorView, + InputBox, + ModalDialog, + SideBarView, + VSBrowser, + ViewControl, + ViewSection, + WebView, + WebviewView, + Workbench, +} from "vscode-extension-tester"; +import { + getFixturePath, + expectNotification, + getModalDialogAndMessage, + getWebviewByLocator, + sleep, + updateSettings, + workbenchExecuteCommand, +} from "./uiTestHelper"; +import { WizardGenerationActionType } from "../../src/definitions/lightspeed"; +import { PlaybookGenerationActionEvent } from "../../src/interfaces/lightspeed"; +import { expect } from "chai"; +import axios from "axios"; + +export function lightspeedUIExplorerTest(): void { + describe("Test Lightspeed Explorer features", () => { + let workbench: Workbench; + let explorerView: WebviewView; + let modalDialog: ModalDialog; + let dialogMessage: string; + let sideBar: SideBarView; + let view: ViewControl; + let adtView: ViewSection; + + before(async () => { + // Enable Lightspeed and open Ansible Light view on sidebar + workbench = new Workbench(); + const settingsEditor = await workbench.openSettings(); + await updateSettings(settingsEditor, "ansible.lightspeed.enabled", true); + await updateSettings( + settingsEditor, + "ansible.lightspeed.URL", + process.env.TEST_LIGHTSPEED_URL, + ); + await updateSettings( + settingsEditor, + "ansible.lightspeed.suggestions.enabled", + true, + ); + // Close settings and other open editors (if any) + await new EditorView().closeAllEditors(); + + // Set "UI Test" option for mock server + await axios.post( + `${process.env.TEST_LIGHTSPEED_URL}/__debug__/options`, + ["--ui-test"], + { headers: { "Content-Type": "application/json" } }, + ); + }); + + after(async function () { + if (explorerView) { + await explorerView.switchBack(); + } + const settingsEditor = await workbench.openSettings(); + await updateSettings(settingsEditor, "ansible.lightspeed.enabled", false); + await updateSettings(settingsEditor, "ansible.lightspeed.URL", ""); + await updateSettings( + settingsEditor, + "ansible.lightspeed.suggestions.enabled", + false, + ); + // Close settings and other open editors (if any) + await new EditorView().closeAllEditors(); + + // Clear "UI Test" option for mock server + await axios.post( + `${process.env.TEST_LIGHTSPEED_URL}/__debug__/options`, + [], + { headers: { "Content-Type": "application/json" } }, + ); + }); + + it("Focus on Ansible Lightspeed View", async () => { + view = (await new ActivityBar().getViewControl("Ansible")) as ViewControl; + sideBar = await view.openView(); + + adtView = await sideBar + .getContent() + .getSection("Ansible Development Tools"); + adtView.collapse(); + + await sleep(3000); + explorerView = new WebviewView(); + expect(explorerView, "explorerView should not be undefined").not.to.be + .undefined; + }); + + it("Click Connect button Ansible Lightspeed webview", async () => { + await explorerView.switchToFrame(5000); + + const connectButton = await explorerView.findWebElement( + By.id("lightspeed-explorer-connect"), + ); + expect(connectButton).not.to.be.undefined; + if (connectButton) { + await connectButton.click(); + } + await explorerView.switchBack(); + }); + + it("Click Allow to use Lightspeed", async () => { + // Click Allow to use Lightspeed + const { dialog, message } = await getModalDialogAndMessage(true); + expect(message).equals( + "The extension 'Ansible' wants to sign in using Ansible Lightspeed.", + ); + await dialog.pushButton("Allow"); + }); + + it("Verify a modal dialog pops up", async () => { + const { dialog, message } = await getModalDialogAndMessage(); + expect(dialog).not.to.be.undefined; + expect(message).not.to.be.undefined; + modalDialog = dialog; + dialogMessage = message; + }); + + it("Click Open if a dialog shows up for opening the external website", async () => { + // If the dialog to open the external website is not suppressed, click Open + if (dialogMessage === "Do you want Code to open the external website?") { + await modalDialog.pushButton("Configure Trusted Domains"); + const input = await InputBox.create(); + input.confirm(); + + const d = await getModalDialogAndMessage(); + modalDialog = d.dialog; + dialogMessage = d.message; + } + }); + + it("Click Open to open the callback URI", async () => { + // Click Open to allow Ansible extension to open the callback URI + expect(dialogMessage).equals( + "Allow 'Ansible' extension to open this URI?", + ); + await modalDialog.pushButton("Open"); + await sleep(2000); + }); + + it("Verify Ansible Lightspeed Generate Playbook button", async () => { + await explorerView.switchToFrame(2000); + + const generatePlaybookButton = await explorerView.findWebElement( + By.id("lightspeed-explorer-playbook-generation-submit"), + ); + expect(generatePlaybookButton).not.to.be.undefined; + + // Open playbook generation webview. + await generatePlaybookButton.click(); + await sleep(2000); + + // Locate the playbook explanation webview + await explorerView.switchBack(); + const webView = await getWebviewByLocator( + By.xpath("//*[text()='Create a playbook with Ansible Lightspeed']"), + ); + expect(webView, "webView should not be undefined").not.to.be.undefined; + + await webView.switchBack(); + await workbenchExecuteCommand("View: Close All Editor Groups"); + + /* verify generated events */ + const expected = [ + [WizardGenerationActionType.OPEN, undefined, 1], + [WizardGenerationActionType.CLOSE_CANCEL, 1, undefined], + ]; + const res = await axios.get( + `${process.env.TEST_LIGHTSPEED_URL}/__debug__/feedbacks`, + ); + expect(res.data.feedbacks.length).equals(expected.length); + for (let i = 0; i < expected.length; i++) { + const evt: PlaybookGenerationActionEvent = + res.data.feedbacks[i].playbookGenerationAction; + expect(evt.action).equals(expected[i][0]); + expect(evt.fromPage).equals(expected[i][1]); + expect(evt.toPage).equals(expected[i][2]); + } + }); + + it("Verify Ansible Lightspeed Explain Playbook button", async () => { + const folder = "lightspeed"; + const file = "playbook_4.yml"; + const filePath = getFixturePath(folder, file); + + // Open file in the editor + await VSBrowser.instance.openResources(filePath); + + await explorerView.switchToFrame(2000); + + const explainPlaybookButton = await explorerView.findWebElement( + By.id("lightspeed-explorer-playbook-explanation-submit"), + ); + expect(explainPlaybookButton).not.to.be.undefined; + + // Open playbook explanation webview. + await explainPlaybookButton.click(); + await sleep(2000); + + // Locate the playbook explanation webview + await explorerView.switchBack(); + let webView = (await new EditorView().openEditor( + "Explanation", + 1, + )) as WebView; + expect(webView, "webView should not be undefined").not.to.be.undefined; + webView = await getWebviewByLocator( + By.xpath("//div[@class='playbookGeneration']"), + ); + await webView.findWebElement( + By.xpath("//h2[contains(text(), 'Playbook Overview and Structure')]"), + ); + + await webView.switchBack(); + await workbenchExecuteCommand("View: Close All Editor Groups"); + + /* verify generated events */ + const res = await axios.get( + `${process.env.TEST_LIGHTSPEED_URL}/__debug__/feedbacks`, + ); + expect(res.data.feedbacks.length).equals(1); + }); + + it("Sign out using Accounts global action", async () => { + workbench = new Workbench(); + const activityBar = new ActivityBar(); + const actions = (await activityBar.getGlobalAction( + "Accounts", + )) as ActionsControl; + expect(actions).not.to.be.undefined; + await actions.click(); + const menus = await workbench.findElements(By.className("context-view")); + expect(menus.length).greaterThan(0); + const menu = new ContextMenu(workbench); + expect(menu).not.to.be.undefined; + if (menu) { + await menu.select( + "EXTERNAL_USERNAME (licensed) (Ansible Lightspeed)", + "Sign Out", + ); + } + }); + + it("Click Sign Out button on the modal dialog", async () => { + const dialog = new ModalDialog(); + expect(dialog).not.to.be.undefined; + await dialog.pushButton("Sign Out"); + }); + + it("Verify the notification message", async () => { + await sleep(1000); + await expectNotification("Successfully signed out."); + }); + }); +}