-
Notifications
You must be signed in to change notification settings - Fork 746
feat(amazonq): adding a simple chat prompt test #7643
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
98688bf
5959a38
4540f16
f1afe95
4fa90ec
e1c33d8
ea46464
66f198d
dd62e27
866478a
35c656f
ed3c220
824635e
b30f7f4
5da6336
c8ccbae
667619e
ade9906
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1322,26 +1322,40 @@ | |
| "fontCharacter": "\\f1de" | ||
| } | ||
| }, | ||
| "aws-schemas-registry": { | ||
| "aws-sagemaker-code-editor": { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this seems unrelated to your changes?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes this is unrelated to my changes, i think they appeared when i ran "npm install" when we were resolving the merge conflicts, should i delete them?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should we able to resolve this by rebasing. If not, we can manually take the changes out of the PR since I'm unsure of the side effects. |
||
| "description": "AWS Contributed Icon", | ||
| "default": { | ||
| "fontPath": "./resources/fonts/aws-toolkit-icons.woff", | ||
| "fontCharacter": "\\f1df" | ||
| } | ||
| }, | ||
| "aws-schemas-schema": { | ||
| "aws-sagemaker-jupyter-lab": { | ||
| "description": "AWS Contributed Icon", | ||
| "default": { | ||
| "fontPath": "./resources/fonts/aws-toolkit-icons.woff", | ||
| "fontCharacter": "\\f1e0" | ||
| } | ||
| }, | ||
| "aws-stepfunctions-preview": { | ||
| "aws-schemas-registry": { | ||
| "description": "AWS Contributed Icon", | ||
| "default": { | ||
| "fontPath": "./resources/fonts/aws-toolkit-icons.woff", | ||
| "fontCharacter": "\\f1e1" | ||
| } | ||
| }, | ||
| "aws-schemas-schema": { | ||
| "description": "AWS Contributed Icon", | ||
| "default": { | ||
| "fontPath": "./resources/fonts/aws-toolkit-icons.woff", | ||
| "fontCharacter": "\\f1e2" | ||
| } | ||
| }, | ||
| "aws-stepfunctions-preview": { | ||
| "description": "AWS Contributed Icon", | ||
| "default": { | ||
| "fontPath": "./resources/fonts/aws-toolkit-icons.woff", | ||
| "fontCharacter": "\\f1e3" | ||
| } | ||
| } | ||
| }, | ||
| "walkthroughs": [ | ||
|
|
||
laura-codess marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,59 +2,114 @@ | |
| * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
| import { Workbench, By, WebviewView, WebElement } from 'vscode-extension-tester' | ||
| import { until } from 'selenium-webdriver' | ||
|
|
||
| import { Workbench, By, EditorView, WebviewView, WebElement } from 'vscode-extension-tester' | ||
|
|
||
| describe('Amazon Q Login Flow', function () { | ||
| describe('Amazon Q E2E UI Test', function () { | ||
| // need this timeout because Amazon Q takes awhile to load | ||
| this.timeout(30000) | ||
| this.timeout(150000) | ||
| let webviewView: WebviewView | ||
|
|
||
| let workbench: Workbench | ||
| // NOTE: I tested all the timeouts and they are necessary for the webview to load properly | ||
| before(async function () { | ||
| const workbench = new Workbench() | ||
| this.timeout(120000) | ||
| workbench = new Workbench() | ||
| await workbench.executeCommand('Amazon Q: Open Chat') | ||
|
|
||
| await new Promise((resolve) => setTimeout(resolve, 15000)) | ||
laura-codess marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| await new Promise((resolve) => setTimeout(resolve, 5000)) | ||
| webviewView = new WebviewView() | ||
| await webviewView.switchToFrame() | ||
| }) | ||
|
|
||
| after(async () => { | ||
| await webviewView.switchBack() | ||
| try { | ||
| await new EditorView().closeAllEditors() | ||
| } catch {} | ||
| }) | ||
|
|
||
| it('Should click through the Amazon Q login screen', async () => { | ||
| // Select company account option | ||
| const driver = webviewView.getDriver() | ||
| await driver.wait(until.elementsLocated(By.css('.selectable-item')), 30000) | ||
| const selectableItems = await webviewView.findWebElements(By.css('.selectable-item')) | ||
| console.log(typeof selectableItems) | ||
| if (selectableItems.length === 0) { | ||
| throw new Error('No selectable login options found') | ||
| } | ||
|
|
||
| // Find and click company account | ||
| const companyItem = await findItemByText(selectableItems, 'Company account') | ||
| await companyItem.click() | ||
| await new Promise((resolve) => setTimeout(resolve, 2000)) | ||
|
|
||
| // Click first continue button | ||
| const signInContinue = await webviewView.findWebElement(By.css('#connection-selection-continue-button')) | ||
| await signInContinue.click() | ||
| await new Promise((resolve) => setTimeout(resolve, 2000)) | ||
|
|
||
| // Enter start URL | ||
| const startUrlInput = await webviewView.findWebElement(By.id('startUrl')) | ||
| await startUrlInput.clear() | ||
| await startUrlInput.sendKeys('https://amzn.awsapps.com/start') | ||
| await new Promise((resolve) => setTimeout(resolve, 1000)) | ||
|
|
||
| // Click second continue button | ||
| const UrlContinue = await webviewView.findWebElement(By.css('button.continue-button.topMargin')) | ||
| await UrlContinue.click() | ||
| await new Promise((resolve) => setTimeout(resolve, 2000)) | ||
| console.log('Waiting for manual authentication...') | ||
| await new Promise((resolve) => setTimeout(resolve, 12000)) | ||
| console.log('Manual authentication should be done') | ||
| await webviewView.switchBack() | ||
|
|
||
| // AFTER AUTHENTICATION WE MUST RELOAD THE WEBVIEW BECAUSE MULTIPLE WEVIEWS CANNOT BE READ AT THE SAME TIME | ||
| const editorView = workbench.getEditorView() | ||
| console.log('editorview successfully created') | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume these are just debugging logs? We should be careful of this becoming super noisy, but if its helpful we should keep them. I imagine a subset of these are helpful? |
||
| await editorView.closeAllEditors() | ||
| console.log('Closed all editors') | ||
| await new Promise((resolve) => setTimeout(resolve, 1500)) | ||
laura-codess marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| webviewView = new WebviewView() | ||
| console.log('Reopened webview view') | ||
| await webviewView.switchToFrame() | ||
| await new Promise((resolve) => setTimeout(resolve, 1200)) | ||
| }) | ||
|
|
||
| after(async () => { | ||
| // TO-DO: Close all the chat windows after the test is done so that when the test runs again it does not have memory | ||
| // from the previous test | ||
|
|
||
| /* | ||
| mynah-tabs-container is the css that contains all the mynah ui tabs | ||
| inside that there are two spans that have key values | ||
| inside those spans there is a div with the css mynah-tab-item-label | ||
| and finally INSIDE THAT there is a button with the css mynah-tabs-close-button, we need to click that button and close all the tabs after the test is done | ||
|
|
||
|
|
||
| Logic: | ||
| Find all the tahs by looking for the close buttons and then close them one by one. To check if all the tabs are closed, we can check if the mynah-tabs-container is empty. | ||
| */ | ||
| try { | ||
| // find all the close buttons and click them | ||
| const closeButtons = await webviewView.findWebElements(By.css('.mynah-tabs-close-button')) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need to wait here as well? |
||
|
|
||
| for (const button of closeButtons) { | ||
| await button.click() | ||
| // small delay to ensure the tab closes properly | ||
| await new Promise((resolve) => setTimeout(resolve, 500)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could we use |
||
| } | ||
|
|
||
| // double check that all tabs are closed by checking if the mynah-tabs-container is empty | ||
| const tabsContainer = await webviewView.findWebElements(By.css('.mynah-tabs-container')) | ||
| if ( | ||
| tabsContainer.length === 0 || | ||
| (await tabsContainer[0].findElements(By.css('.mynah-tab-item-label'))).length === 0 | ||
| ) { | ||
| console.log('All chat tabs successfully closed') | ||
| } | ||
| } catch (error) { | ||
| console.log('Error closing tabs:', error) | ||
| } | ||
| await webviewView.switchBack() | ||
| }) | ||
|
|
||
| it('Chat Prompt Test', async () => { | ||
| const driver = webviewView.getDriver() | ||
| await driver.wait(until.elementsLocated(By.css('.mynah-chat-prompt-input')), 300000) | ||
laura-codess marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // In order to test the chat prompt, we need to find the input field and send keys | ||
| const chatInput = await webviewView.findWebElement(By.css('.mynah-chat-prompt-input')) | ||
| await chatInput.sendKeys('Hello, Amazon Q!') | ||
| await driver.wait(until.elementsLocated(By.css('.mynah-chat-prompt-button')), 300000) | ||
| // In order to submit the chat prompt, we need to find the send button and click it | ||
| const sendButton = await webviewView.findWebElement(By.css('.mynah-chat-prompt-button')) | ||
| await sendButton.click() | ||
|
|
||
| await new Promise((resolve) => setTimeout(resolve, 12000)) | ||
| // Wait for response using conversation container check | ||
| const responseReceived = await waitForChatResponse(webviewView) | ||
| if (!responseReceived) { | ||
| throw new Error('Chat response not received within timeout') | ||
| } | ||
|
|
||
| console.log('Chat response detected successfully') | ||
| }) | ||
|
|
||
| // Helper to find item by text content | ||
|
|
@@ -70,4 +125,33 @@ describe('Amazon Q Login Flow', function () { | |
| } | ||
| throw new Error(`Item with text "${text}" not found`) | ||
| } | ||
|
|
||
| /* My Idea: Basically the conversation container's css is .mynah-chat-items-conversation-container | ||
| Instead of looking for a specific message like how we look for other elements in the test, | ||
| I can check how many elements there are in our specific conversation container. If there is 2 elements, | ||
| we can assume that the chat response has been generated. The challenge is, we must grab the latest | ||
| conversation container, as there can be multiple conversations in the webview. | ||
| */ | ||
| async function waitForChatResponse(webview: WebviewView, timeout = 30000): Promise<boolean> { | ||
laura-codess marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const startTime = Date.now() | ||
|
|
||
| while (Date.now() - startTime < timeout) { | ||
| const conversationContainers = await webview.findWebElements( | ||
| By.css('.mynah-chat-items-conversation-container') | ||
| ) | ||
|
|
||
| if (conversationContainers.length > 0) { | ||
| const latestContainer = conversationContainers[conversationContainers.length - 1] | ||
|
|
||
| const chatItems = await latestContainer.findElements(By.css('*')) | ||
|
|
||
| if (chatItems.length >= 2) { | ||
Hweinstock marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return true | ||
| } | ||
| } | ||
| await new Promise((resolve) => setTimeout(resolve, 500)) | ||
| } | ||
|
|
||
| return false | ||
| } | ||
| }) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these automatically applied by the linter?