Skip to content

feat(amazonq): Add Pin Context Tests and Update to pinContextHelper #7829

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

Merged
merged 7 commits into from
Aug 15, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 101 additions & 67 deletions packages/amazonq/test/e2e_new/amazonq/helpers/pinContextHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,25 @@ import { WebElement } from 'vscode-extension-tester'
/**
* Clicks the "Pin Context" button in the chat interface
* @param webview The WebviewView instance
* @returns Promise<boolean> True if button was found and clicked, false otherwise
* @throws Error if button is not found
*/
export async function clickPinContextButton(webview: WebviewView): Promise<boolean> {
try {
const topBar = await waitForElement(webview, By.css('.mynah-prompt-input-top-bar'))
const buttons = await topBar.findElements(
By.css('.mynah-button.mynah-button-secondary.fill-state-always.status-clear.mynah-ui-clickable-item')
)
// double check the label to make sure it says "Pin Context"
for (const button of buttons) {
const label = await button.findElement(By.css('.mynah-button-label'))
const labelText = await label.getText()
console.log('THE BUTTON TEXT LABEL IS:', labelText)
if (labelText === '@Pin Context') {
console.log('Found Pin Context button, clicking...')
await button.click()
return true
}
export async function clickPinContextButton(webview: WebviewView): Promise<void> {
const topBar = await waitForElement(webview, By.css('.mynah-prompt-input-top-bar'))
const buttons = await topBar.findElements(
By.css('.mynah-button.mynah-button-secondary.fill-state-always.status-clear.mynah-ui-clickable-item')
)
// double check the label to make sure it says "Pin Context"
for (const button of buttons) {
const label = await button.findElement(By.css('.mynah-button-label'))
const labelText = await label.getText()
console.log('THE BUTTON TEXT LABEL IS:', labelText)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this for debugging? Do we want to this run on text execution.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh do you mean the console.log statements?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah maybe we can build a toggle for logging with a logging abstraction as a follow up

if (labelText === '@Pin Context') {
console.log('Found Pin Context button, clicking...')
await button.click()
return
}
console.log('Pin Context button not found')
return false
} catch (e) {
console.error('Error clicking Pin Context button:', e)
return false
}
throw new Error('Pin Context button not found')
}

/**
Expand All @@ -42,65 +36,105 @@ export async function clickPinContextButton(webview: WebviewView): Promise<boole
* @returns Promise<boolean> Returns the items as a WebElement List and the labels in a string array
*/
export async function getPinContextMenuItems(webview: WebviewView): Promise<{ items: WebElement[]; labels: string[] }> {
try {
const menuList = await waitForElement(webview, By.css('.mynah-detailed-list-items-block'))
await sleep(3000)
const menuListItems = await menuList.findElements(By.css('.mynah-detailed-list-item.mynah-ui-clickable-item'))
const labels: string[] = []
const menuList = await waitForElement(webview, By.css('.mynah-detailed-list-items-block'))
// TODO: Fix the need for a sleep function to be required at all.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ty

await sleep(100)
const menuListItems = await menuList.findElements(By.css('.mynah-detailed-list-item.mynah-ui-clickable-item'))

for (const item of menuListItems) {
try {
const textWrapper = await item.findElement(By.css('.mynah-detailed-list-item-text'))
const nameElement = await textWrapper.findElement(By.css('.mynah-detailed-list-item-name'))
const labelText = await nameElement.getText()
labels.push(labelText)
console.log('Menu item found:', labelText)
} catch (e) {
labels.push('')
console.log('Could not get text for menu item')
}
}
if (menuListItems.length === 0) {
throw new Error('No pin context menu items found')
}

return { items: menuListItems, labels }
} catch (e) {
console.error('Error getting Pin Context menu items:', e)
return { items: [], labels: [] }
const labels: string[] = []
for (const item of menuListItems) {
const textWrapper = await item.findElement(By.css('.mynah-detailed-list-item-text'))
const nameElement = await textWrapper.findElement(By.css('.mynah-detailed-list-item-name'))
const labelText = await nameElement.getText()
labels.push(labelText)
console.log('Menu item found:', labelText)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, how noisy are the logs when running the full test suite?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logs aren't too noisy, I actually think they're helpful to see the process of the test in my opinion

}

return { items: menuListItems, labels }
}

/**
* Clicks a specific item in the Pin Context menu by its label text
* @param webview The WebviewView instance
* @param itemName The text label of the menu item to click
* @returns Promise<boolean> True if the item was found and clicked, false otherwise
* @throws Error if the menu item is not found or DOM structure is invalid
*
* NOTE: To find all possible text labels, you can call getPinContextMenuItems
*/
export async function clickPinContextMenuItem(webview: WebviewView, itemName: string): Promise<boolean> {
try {
const menuList = await waitForElement(webview, By.css('.mynah-detailed-list-items-block'))
await sleep(3000)
const menuListItems = await menuList.findElements(By.css('.mynah-detailed-list-item.mynah-ui-clickable-item'))
for (const item of menuListItems) {
try {
const textWrapper = await item.findElement(By.css('.mynah-detailed-list-item-text'))
const nameElement = await textWrapper.findElement(By.css('.mynah-detailed-list-item-name'))
const labelText = await nameElement.getText()
export async function clickPinContextMenuItem(webview: WebviewView, itemName: string): Promise<void> {
const menuList = await waitForElement(webview, By.css('.mynah-detailed-list-items-block'))
await sleep(100)
const menuListItems = await menuList.findElements(By.css('.mynah-detailed-list-item.mynah-ui-clickable-item'))
for (const item of menuListItems) {
const textWrapper = await item.findElement(By.css('.mynah-detailed-list-item-text'))
const nameElement = await textWrapper.findElement(By.css('.mynah-detailed-list-item-name'))
const labelText = await nameElement.getText()

if (labelText === itemName) {
console.log(`Clicking Pin Context menu item: ${itemName}`)
await item.click()
return true
}
} catch (e) {
continue
}
if (labelText === itemName) {
console.log(`Clicking Pin Context menu item: ${itemName}`)
await item.click()
return
}
}

throw new Error(`Pin Context menu item not found: ${itemName}`)
}
/**
* Lists all the possible Sub-menu items in the console.
* @param webview The WebviewView instance
* @returns Promise<boolean> Returns the items as a WebElement List and the labels in a string array
*/
export async function getSubMenuItems(webview: WebviewView): Promise<{ items: WebElement[]; labels: string[] }> {
const menuList = await waitForElement(webview, By.css('.mynah-detailed-list-items-block'))
await sleep(100)
const menuListItems = await menuList.findElements(By.css('.mynah-detailed-list-item.mynah-ui-clickable-item'))

console.log(`Pin Context menu item not found: ${itemName}`)
return false
} catch (e) {
console.error(`Error clicking Pin Context menu item ${itemName}:`, e)
return false
if (menuListItems.length === 0) {
throw new Error('No sub-menu items found')
}

const labels: string[] = []
for (const item of menuListItems) {
const textWrapper = await item.findElement(
By.css('.mynah-detailed-list-item-text.mynah-detailed-list-item-text-direction-row')
)
const nameElement = await textWrapper.findElement(By.css('.mynah-detailed-list-item-name'))
const labelText = await nameElement.getText()
labels.push(labelText)
console.log('Menu item found:', labelText)
}

return { items: menuListItems, labels }
}
/**
* Clicks a specific item in the Sub-Menu by its label text
* @param webview The WebviewView instance
* @param itemName The text label of the menu item to click
* @throws Error if the menu item is not found or DOM structure is invalid
*
* NOTE: To find all possible text labels, you can call getPinContextMenuItems
*/
export async function clickSubMenuItem(webview: WebviewView, itemName: string): Promise<void> {
const menuList = await waitForElement(webview, By.css('.mynah-detailed-list-items-block'))
await sleep(100)
const menuListItems = await menuList.findElements(By.css('.mynah-detailed-list-item.mynah-ui-clickable-item'))
for (const item of menuListItems) {
const textWrapper = await item.findElement(
By.css('.mynah-detailed-list-item-text.mynah-detailed-list-item-text-direction-row')
)
const nameElement = await textWrapper.findElement(By.css('.mynah-detailed-list-item-name'))
const labelText = await nameElement.getText()

if (labelText === itemName) {
console.log(`Clicking Pin Context menu item: ${itemName}`)
await item.click()
return
}
}

throw new Error(`Pin Context menu item not found: ${itemName}`)
}
37 changes: 26 additions & 11 deletions packages/amazonq/test/e2e_new/amazonq/tests/pinContext.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
* SPDX-License-Identifier: Apache-2.0
*/
import '../utils/setup'
import { WebviewView } from 'vscode-extension-tester'
import { WebviewView, By } from 'vscode-extension-tester'
import { closeAllTabs, dismissOverlayIfPresent } from '../utils/cleanupUtils'
import { testContext } from '../utils/testContext'
import { clickPinContextButton, getPinContextMenuItems, clickPinContextMenuItem } from '../helpers/pinContextHelper'
import { clearChat } from '../utils/generalUtils'
import { clickPinContextButton, clickPinContextMenuItem, clickSubMenuItem } from '../helpers/pinContextHelper'
import { waitForElement } from '../utils/generalUtils'

describe('Amazon Q Pin Context Functionality', function () {
// this timeout is the general timeout for the entire test suite
Expand All @@ -18,18 +18,33 @@ describe('Amazon Q Pin Context Functionality', function () {
webviewView = testContext.webviewView
})

after(async function () {
await closeAllTabs(webviewView)
})

afterEach(async () => {
await dismissOverlayIfPresent(webviewView)
await clearChat(webviewView)
await closeAllTabs(webviewView)
})

it('Pin Context Test', async () => {
it('Allows User to Add File Context', async () => {
await clickPinContextButton(webviewView)
await clickPinContextMenuItem(webviewView, 'Files')
await clickPinContextMenuItem(webviewView, 'Active file')
})
it('Allows User to Pin Workspace Context', async () => {
await clickPinContextButton(webviewView)
await getPinContextMenuItems(webviewView)
await clickPinContextMenuItem(webviewView, '@workspace')
})
it('Allows User to Add Prompt Context', async () => {
await clickPinContextButton(webviewView)
await clickPinContextMenuItem(webviewView, 'Prompts')
const addPrompt = await waitForElement(webviewView, By.css('.mynah-ui-icon.mynah-ui-icon-list-add'))
await addPrompt.click()
const chatInput = await waitForElement(webviewView, By.css('[data-testid="chat-item-form-item-text-input"]'))
await chatInput.sendKeys('test')
const createPrompt = await waitForElement(
webviewView,
By.css('.mynah-button.fill-state-always.status-primary.mynah-ui-clickable-item')
)
await createPrompt.click()
await clickPinContextButton(webviewView)
await clickPinContextMenuItem(webviewView, 'Prompts')
await clickSubMenuItem(webviewView, 'test')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my understanding is that this returns a boolean false if it fails, but this won't cause the test to fail.

})
})
Loading