Skip to content
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

Fixes #76 broken selector in TitleBar.getItem() #77

Merged
merged 2 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 5 additions & 2 deletions src/locators/1.37.0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,13 @@ export const ContextMenu = {
}
export const TitleBar = {
elem: 'div[id="workbench.parts.titlebar"]',
itemConstructor: (label: string) => `.//div[@aria-label="${label}"]`,
topLevelItemConstructor: (label: string) => `.//div[@aria-label="${label}"]`,
overflowItemConstructor: (label: string) => `.//li[a/span/@aria-label="${label}"]`,
itemElement: '.menubar-menu-button',
itemLabel: 'aria-label',
title: '.window-title'
itemNesting: '.submenu-indicator',
title: '.window-title',
menubar: '.menubar'
}
export const WindowControls = {
elem: '.window-controls-container',
Expand Down
7 changes: 5 additions & 2 deletions src/pageobjects/menu/ContextMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,13 @@ export class ContextMenuItem extends MenuItem<typeof ContextMenuLocators> {
}

async select () {
const nesting = await this.isNesting()
await this.elem.click()
await sleep(500)
if (await this.isNesting()) {
await new ContextMenu(this.locatorMap, this.elem).wait()
if (nesting) {
const menu = new ContextMenu(this.locatorMap, this.elem)
await menu.wait()
return menu
}
return undefined
}
Expand Down
85 changes: 59 additions & 26 deletions src/pageobjects/menu/TitleBar.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { PageDecorator, IPageDecorator, VSCodeLocatorMap } from '../utils.js'
import {
PageDecorator, IPageDecorator, VSCodeLocatorMap, sleep
} from '../utils.js'
import { WindowControls, ContextMenu } from '../index.js'
import { Menu } from './Menu.js'
import { MenuItem } from './MenuItem.js'
Expand All @@ -23,40 +25,70 @@ export class TitleBar extends Menu<typeof TitleBarLocators> {
* @returns Promise resolving to TitleBarItem object
*/
async getItem (name: string): Promise<TitleBarItem | undefined> {
try {
const titleBar = new TitleBarItem(
this.locatorMap,
this.locators.itemConstructor(name),
this
)
await titleBar.wait()
return titleBar
} catch (err) {
return undefined
const all = await this.getItems()
for (const item of all) {
if (item.label === name) {
return item
}
}
return undefined
}

/**
* Get all title bar items
* @returns Promise resolving to array of TitleBarItem objects
*/
async getItems (): Promise<TitleBarItem[]> {
const items: TitleBarItem[] = []
const elements = await this.itemElement$$
// can't search in this. because in web version the overflow menu is in activity bar
const menubar = await browser.$(this.locators.menubar)
if (!(await menubar.isExisting())) {
throw new Error(
'Menubar not found in TitleBar, this probably means you are using "native" Title Bar Style. '
+ 'Title Items can only be found when using "custom" style.'
)
}

for (const element of elements) {
const items: TitleBarItem[] = []
for (const element of await menubar.$$(this.locators.itemElement)) {
const isDisplayed = await element.isDisplayed()
if (!isDisplayed) {
continue
}

const item = new TitleBarItem(
this.locatorMap,
await element.getAttribute(this.locators.itemLabel),
this
)
await item.wait()
items.push(item)
const label = await element.getAttribute(this.locators.itemLabel)
if (
label === 'More' // electron
|| label === 'Application Menu' // web
) {
await element.click()
const overflow = await new ContextMenu(this.locatorMap).wait()
for (const overflowItem of await overflow.getItems()) {
const item = new TitleBarItem(
this.locatorMap,
(this.locators.overflowItemConstructor as Function),
async (self) => {
await element.click() // make sure the overflow menu is open
await self.elem.click()
},
await overflowItem.getLabel(),
this
)
await item.wait()
items.push(item)
}
await browser.keys('Escape')
} else {
const item = new TitleBarItem(
this.locatorMap,
(this.locators.topLevelItemConstructor as Function),
async (self) => {
await self.elem.click()
},
label,
this
)
await item.wait()
items.push(item)
}
}
return items
}
Expand Down Expand Up @@ -103,20 +135,21 @@ export class TitleBarItem extends MenuItem<typeof TitleBarLocators> {

constructor (
locators: VSCodeLocatorMap,
ctor: Function,
private openMenu: (self: TitleBarItem) => Promise<void>,
public label: string,
public parentMenu: Menu<typeof TitleBarLocators>
) {
super(locators, (locators.TitleBar.itemConstructor as Function)(label) as string)
this.parentMenu = parentMenu
this.label = label
super(locators, ctor(label) as string)
}

async select () {
const openMenus = await browser.$$(this.locatorMap.ContextMenu.elem as string)
if (openMenus.length > 0 && await openMenus[0].isDisplayed()) {
await browser.keys('Escape')
}
await this.elem.click()
await this.openMenu(this)
await sleep(500)

const menu = new ContextMenu(this.locatorMap, this.elem)
await menu.wait()
Expand Down
5 changes: 5 additions & 0 deletions test/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@
"when": "view == testExtensionTreeview",
"group": "inline"
}
],
"menuBar/edit/copy": [
{
"command": "test-extension.callme"
}
]
}
},
Expand Down
60 changes: 59 additions & 1 deletion test/specs/basic.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import {
PageDecorator, IPageDecorator, BasePage, BottomBarPanel,
StatusBar, SettingsEditor, TextEditor, FindWidget, MarkerType,
ProblemsView, EditorView, WebView, SideBarView, CustomTreeItem,
DefaultTreeItem, ViewSection, TreeItem, sleep
DefaultTreeItem, ViewSection, TreeItem, sleep, TitleBar
} from '../../dist/index.js'
import { Workbench } from '../../dist/locators/1.37.0.js'

const isWebTest = Boolean(parseInt(process.env.VSCODE_WEB_TESTS || '', 10))

Expand Down Expand Up @@ -249,6 +250,63 @@ describe('WDIO VSCode Service', () => {
})
})

describe('titlebar', () => {
let titleBar: TitleBar

before(async () => {
const workbench = await browser.getWorkbench()
titleBar = workbench.getTitleBar()
})

skip('darwin')('can find all items', async () => {
const items = await titleBar.getItems()
expect(await items[0].getLabel()).toBe('File')
expect(await items[1].getLabel()).toBe('Edit')
expect(await items[items.length - 1].getLabel()).toBe('Help')
})

skip('darwin')('can select item by name', async () => {
const item = await titleBar.getItem('Help')
expect(await item?.getLabel()).toBe('Help')
})

// skipped because it changes editor content which breaks other tests
skipCI('can click top level item', async () => {
const workbench = await browser.getWorkbench()
const itemHelp = await titleBar.getItem('Help')
const menuHelp = await itemHelp?.select()
const itemWelcome = await menuHelp?.getItem('Welcome')
await itemWelcome?.select()

const activeTab = await workbench.getEditorView().getActiveTab()
expect(await activeTab?.getTitle()).toEqual('Welcome')
})

skip('darwin')('can click nested item', async () => {
const workbench = await browser.getWorkbench()

const itemEdit = await titleBar.getItem('Edit')
const menuEdit = await itemEdit?.select()
const itemCopyAs = await menuEdit?.getItem('Copy As')
const menuCopyAs = await itemCopyAs?.select()
const itemCallMe = await menuCopyAs?.getItem('Call Me!')
await itemCallMe?.select()

await browser.waitUntil(async () => {
const notifs = await workbench.getNotifications()
for (const n of notifs) {
if ((await n.getMessage()).includes('I got called!')) {
await n.dismiss()
return true
}
}
return false
}, {
timeoutMsg: 'Could not find notification as reaction to action item click'
})
})
})

describe('statusbar', () => {
let statusBar: StatusBar

Expand Down