Skip to content

Commit 1e78ac7

Browse files
authored
fix(amazonq): XPath Selector for pinContextHelpers and fixing PinContext ability to run in full test suite (#7928)
## Problem We were faced with the problem that when all our tests and helpers were merged together, and then run as a full suite, we saw errors with the pinContext.test.ts file. Namely, it was targeting a background overlay that had identical css components to the pinContext overlay. This is problematic since our entire suite relies on these css components, and even test-ids were not differentiated. Additionally, our pinContextHelpers used sleep functions in the range of 100-3000 ms which is naturally arbitrary values. ## Solution We implement the XPath css selectors that are used within Selenium to identify the pinContext Buttons by text, not css classes or ids. This drastically decreases the length and complexity of our helpers while also eliminating the need for sleep functions other than a sleep(0) function for subMenuItems that is needed for the DOM to be loaded. Below is our success of the tests: <img width="313" height="77" alt="Screenshot 2025-08-19 at 1 49 34 PM" src="https://github.com/user-attachments/assets/dd378c02-67c1-4f73-a6e7-cd709e028c80" /> --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent ff86b49 commit 1e78ac7

File tree

2 files changed

+33
-55
lines changed

2 files changed

+33
-55
lines changed

packages/amazonq/test/e2e_new/amazonq/helpers/pinContextHelper.ts

Lines changed: 31 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,23 @@ export async function clickPinContextButton(webview: WebviewView): Promise<void>
3636
* @returns Promise<boolean> Returns the items as a WebElement List and the labels in a string array
3737
*/
3838
export async function getPinContextMenuItems(webview: WebviewView): Promise<{ items: WebElement[]; labels: string[] }> {
39-
const menuList = await waitForElement(webview, By.css('.mynah-detailed-list-items-block'))
40-
// TODO: Fix the need for a sleep function to be required at all.
41-
await sleep(100)
42-
const menuListItems = await menuList.findElements(By.css('.mynah-detailed-list-item.mynah-ui-clickable-item'))
39+
const items = await webview.findElements(
40+
By.xpath(`//div[contains(@class, 'mynah-detailed-list-item') and contains(@class, 'mynah-ui-clickable-item')]`)
41+
)
4342

44-
if (menuListItems.length === 0) {
43+
if (items.length === 0) {
4544
throw new Error('No pin context menu items found')
4645
}
4746

4847
const labels: string[] = []
49-
for (const item of menuListItems) {
50-
const textWrapper = await item.findElement(By.css('.mynah-detailed-list-item-text'))
51-
const nameElement = await textWrapper.findElement(By.css('.mynah-detailed-list-item-name'))
48+
for (const item of items) {
49+
const nameElement = await item.findElement(By.css('.mynah-detailed-list-item-description'))
5250
const labelText = await nameElement.getText()
5351
labels.push(labelText)
5452
console.log('Menu item found:', labelText)
5553
}
5654

57-
return { items: menuListItems, labels }
55+
return { items, labels }
5856
}
5957

6058
/**
@@ -66,49 +64,38 @@ export async function getPinContextMenuItems(webview: WebviewView): Promise<{ it
6664
* NOTE: To find all possible text labels, you can call getPinContextMenuItems
6765
*/
6866
export async function clickPinContextMenuItem(webview: WebviewView, itemName: string): Promise<void> {
69-
const menuList = await waitForElement(webview, By.css('.mynah-detailed-list-items-block'))
70-
await sleep(100)
71-
const menuListItems = await menuList.findElements(By.css('.mynah-detailed-list-item.mynah-ui-clickable-item'))
72-
for (const item of menuListItems) {
73-
const textWrapper = await item.findElement(By.css('.mynah-detailed-list-item-text'))
74-
const nameElement = await textWrapper.findElement(By.css('.mynah-detailed-list-item-name'))
75-
const labelText = await nameElement.getText()
76-
77-
if (labelText === itemName) {
78-
console.log(`Clicking Pin Context menu item: ${itemName}`)
79-
await item.click()
80-
return
81-
}
82-
}
83-
84-
throw new Error(`Pin Context menu item not found: ${itemName}`)
67+
const item = await waitForElement(
68+
webview,
69+
By.xpath(
70+
`//div[contains(@class, 'mynah-detailed-list-item') and contains(@class, 'mynah-ui-clickable-item')]//div[contains(@class, 'mynah-detailed-list-item-name') and text()='${itemName}']`
71+
)
72+
)
73+
console.log(`Clicking Pin Context menu item: ${itemName}`)
74+
await item.click()
8575
}
8676
/**
8777
* Lists all the possible Sub-menu items in the console.
8878
* @param webview The WebviewView instance
8979
* @returns Promise<boolean> Returns the items as a WebElement List and the labels in a string array
9080
*/
9181
export async function getSubMenuItems(webview: WebviewView): Promise<{ items: WebElement[]; labels: string[] }> {
92-
const menuList = await waitForElement(webview, By.css('.mynah-detailed-list-items-block'))
93-
await sleep(100)
94-
const menuListItems = await menuList.findElements(By.css('.mynah-detailed-list-item.mynah-ui-clickable-item'))
82+
const items = await webview.findElements(
83+
By.xpath(`//div[contains(@class, 'mynah-detailed-list-item') and contains(@class, 'mynah-ui-clickable-item')]`)
84+
)
9585

96-
if (menuListItems.length === 0) {
86+
if (items.length === 0) {
9787
throw new Error('No sub-menu items found')
9888
}
9989

10090
const labels: string[] = []
101-
for (const item of menuListItems) {
102-
const textWrapper = await item.findElement(
103-
By.css('.mynah-detailed-list-item-text.mynah-detailed-list-item-text-direction-row')
104-
)
105-
const nameElement = await textWrapper.findElement(By.css('.mynah-detailed-list-item-name'))
91+
for (const item of items) {
92+
const nameElement = await item.findElement(By.css('.mynah-detailed-list-item-name'))
10693
const labelText = await nameElement.getText()
10794
labels.push(labelText)
10895
console.log('Menu item found:', labelText)
10996
}
11097

111-
return { items: menuListItems, labels }
98+
return { items, labels }
11299
}
113100
/**
114101
* Clicks a specific item in the Sub-Menu by its label text
@@ -119,22 +106,14 @@ export async function getSubMenuItems(webview: WebviewView): Promise<{ items: We
119106
* NOTE: To find all possible text labels, you can call getPinContextMenuItems
120107
*/
121108
export async function clickSubMenuItem(webview: WebviewView, itemName: string): Promise<void> {
122-
const menuList = await waitForElement(webview, By.css('.mynah-detailed-list-items-block'))
123-
await sleep(100)
124-
const menuListItems = await menuList.findElements(By.css('.mynah-detailed-list-item.mynah-ui-clickable-item'))
125-
for (const item of menuListItems) {
126-
const textWrapper = await item.findElement(
127-
By.css('.mynah-detailed-list-item-text.mynah-detailed-list-item-text-direction-row')
109+
// We require a sleep function of 0 so that the DOM of the SubMenu can load correctly.
110+
await sleep(0)
111+
const item = await waitForElement(
112+
webview,
113+
By.xpath(
114+
`//div[contains(@class, 'mynah-detailed-list-item') and contains(@class, 'mynah-ui-clickable-item')]//div[contains(@class, 'mynah-detailed-list-item-name') and text()='${itemName}']`
128115
)
129-
const nameElement = await textWrapper.findElement(By.css('.mynah-detailed-list-item-name'))
130-
const labelText = await nameElement.getText()
131-
132-
if (labelText === itemName) {
133-
console.log(`Clicking Pin Context menu item: ${itemName}`)
134-
await item.click()
135-
return
136-
}
137-
}
138-
139-
throw new Error(`Pin Context menu item not found: ${itemName}`)
116+
)
117+
console.log(`Clicking Pin Context menu item: ${itemName}`)
118+
await item.click()
140119
}

packages/amazonq/test/e2e_new/amazonq/tests/pinContext.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55
import '../utils/setup'
66
import { WebviewView, By } from 'vscode-extension-tester'
7-
import { closeAllTabs, dismissOverlayIfPresent } from '../utils/cleanupUtils'
7+
import { closeAllTabs } from '../utils/cleanupUtils'
88
import { testContext } from '../utils/testContext'
99
import { clickPinContextButton, clickPinContextMenuItem, clickSubMenuItem } from '../helpers/pinContextHelper'
1010
import { waitForElement } from '../utils/generalUtils'
@@ -19,13 +19,12 @@ describe('Amazon Q Pin Context Functionality', function () {
1919
})
2020

2121
afterEach(async () => {
22-
await dismissOverlayIfPresent(webviewView)
2322
await closeAllTabs(webviewView)
2423
})
2524
it('Allows User to Add File Context', async () => {
2625
await clickPinContextButton(webviewView)
2726
await clickPinContextMenuItem(webviewView, 'Files')
28-
await clickPinContextMenuItem(webviewView, 'Active file')
27+
await clickSubMenuItem(webviewView, 'Active file')
2928
})
3029
it('Allows User to Pin Workspace Context', async () => {
3130
await clickPinContextButton(webviewView)

0 commit comments

Comments
 (0)