Skip to content

Commit

Permalink
AAP-34645: Add “Generate a Playbook” Button to Side Panel
Browse files Browse the repository at this point in the history
  • Loading branch information
manstis committed Dec 10, 2024
1 parent faa433b commit 68b0b01
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/features/lightspeed/utils/explorerView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ export function getWebviewContentWithActiveSession(
"style.css",
]);
const nonce = getNonce();
const generateForm = `<div class="button-container">
<form id="playbook-generation-form">
<vscode-button id="lightspeed-explorer-playbook-generation-submit" class="lightspeedExplorerButton">Generate a playbook</vscode-button>
<script type="module" nonce="${nonce}" src="${webviewUri}"></script>
</form>
</div>`;
const explainForm = `<div class="button-container">
<form id="playbook-explanation-form">
<vscode-button id="lightspeed-explorer-playbook-explanation-submit" class="lightspeedExplorerButton" ${
Expand Down Expand Up @@ -97,6 +103,7 @@ export function getWebviewContentWithActiveSession(
<body>
<div id="lightspeedExplorerView">
${content}
${generateForm}
${explainForm}
</div>
</body>
Expand All @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions src/webview/apps/lightspeed/explorer/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -29,6 +33,10 @@ function lightspeedConnect() {
vscode.postMessage({ command: "connect" });
}

function lightspeedExplorerPlaybookGeneration() {
vscode.postMessage({ command: "generate" });
}

function lightspeedExplorerPlaybookExplanation() {
vscode.postMessage({ command: "explain" });
}
6 changes: 6 additions & 0 deletions test/ui-test/lightspeedOneClickTrialUITest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ViewControl,
ViewSection,
VSBrowser,
until,
WebElement,
WebView,
WebviewView,
Expand Down Expand Up @@ -258,6 +259,11 @@ describe("Test One Click Trial feature", () => {
await tab.select();
await tab.sendKeys(Key.CONTROL, "z", "z", "z", Key.NULL);
await editorView.closeAllEditors();

// The undo's don't seem to (always) work.. So discard changes
const dialog = new ModalDialog();
await dialog.pushButton(`Don't Save`);
await dialog.getDriver().wait(until.stalenessOf(dialog), 2000);
});

it("Sign out using Accounts global action", async () => {
Expand Down
240 changes: 240 additions & 0 deletions test/ui-test/lightspeedUiTestExplorerTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
// BEFORE: ansible.lightspeed.enabled: true

import {
ActionsControl,
ActivityBar,
By,
ContextMenu,
EditorView,
InputBox,
ModalDialog,
SideBarView,
VSBrowser,
ViewControl,
ViewSection,
WebView,
WebviewView,
Workbench,
} from "vscode-extension-tester";
import {
getFixturePath,
getModalDialogAndMessage,
getWebviewByLocator,
sleep,
workbenchExecuteCommand,
} from "./uiTestHelper";
import { WizardGenerationActionType } from "../../src/definitions/lightspeed";
import { PlaybookGenerationActionEvent } from "../../src/interfaces/lightspeed";
import { expect } from "chai";
import axios from "axios";

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;

beforeEach(function () {
if (process.platform === "darwin") {
this.skip();
}

if (!process.env.TEST_LIGHTSPEED_URL) {
this.skip();
}
});

before(async () => {
// We need this because before() is called ... before beforeEach()
if (process.platform === "darwin") {
return;
}

if (!process.env.TEST_LIGHTSPEED_URL) {
return;
}

// Enable Lightspeed and open Ansible Light view on sidebar
workbench = new Workbench();
// Close settings and other open editors (if any)
await new EditorView().closeAllEditors();

// Set "UI Test" and "One Click" options for mock server
await axios.post(
`${process.env.TEST_LIGHTSPEED_URL}/__debug__/options`,
["--ui-test"],
{ 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, "contentCreatorWebView 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",
);
}
});
});
2 changes: 2 additions & 0 deletions test/ui-test/lightspeedUiTestPlaybookGenTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Workbench,
VSBrowser,
EditorView,
until,
WebView,
ModalDialog,
} from "vscode-extension-tester";
Expand Down Expand Up @@ -144,6 +145,7 @@ describe("Verify playbook generation features work as expected", function () {
await workbenchExecuteCommand("View: Close All Editor Groups");
const dialog = new ModalDialog();
await dialog.pushButton(`Don't Save`);
await dialog.getDriver().wait(until.stalenessOf(dialog), 2000);

/* verify generated events */
const expected = [
Expand Down
2 changes: 2 additions & 0 deletions test/ui-test/lightspeedUiTestPlaybookGenWebviewPart2Test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Workbench,
VSBrowser,
EditorView,
until,
WebView,
ModalDialog,
} from "vscode-extension-tester";
Expand Down Expand Up @@ -173,6 +174,7 @@ describe("Verify playbook generation features work as expected", function () {
await workbenchExecuteCommand("View: Close All Editor Groups");
const dialog = new ModalDialog();
await dialog.pushButton(`Don't Save`);
await dialog.getDriver().wait(until.stalenessOf(dialog), 2000);

/* verify generated events */
const expected = [
Expand Down
2 changes: 2 additions & 0 deletions test/ui-test/walkthroughUiTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
EditorView,
ModalDialog,
SettingsEditor,
until,
Workbench,
} from "vscode-extension-tester";
import { updateSettings, sleep } from "./uiTestHelper";
Expand Down Expand Up @@ -98,5 +99,6 @@ describe("Check walkthroughs, elements and associated commands", async () => {
await workbench.executeCommand("View: Close All Editor Groups");
const dialogBox = new ModalDialog();
await dialogBox.pushButton(`Don't Save`);
await dialogBox.getDriver().wait(until.stalenessOf(dialogBox), 2000);
});
});

0 comments on commit 68b0b01

Please sign in to comment.