Skip to content

Commit

Permalink
feat: add Watch section support (#1617)
Browse files Browse the repository at this point in the history
  • Loading branch information
pospisilf authored Nov 14, 2024
1 parent a0f44a3 commit c1ceab4
Show file tree
Hide file tree
Showing 11 changed files with 264 additions and 0 deletions.
58 changes: 58 additions & 0 deletions docs/DebugView.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,61 @@ await debugConfiguration.selectLaunchConfiguration("Test Launch");
// start selected launch configuration
await debugView.start();
```

### Sections

It's possible to work with all individual sections.

#### Variables

![Variables Section](./images/debugView-Variables.png)

```typescript
import { DebugVariableSection } from 'vscode-extension-tester';
...
const variableSection = await debugView.getVariablesSection();
...
await variablesSection?.openItem('Local'); // open section
const var = await variablesSection.findItem('variableName'); // get one variable
const items = await variablesSection.getVisibleItems(); // get all variables
...
const name = var.getVariableName(); // get name
const value = var.getVariableValue(); // get current value
await var.setVariableValue('newValue'); // change value
```

#### Watch

![Watch Section](./images/debugView-WatchSection.png)

```typescript
import { WatchSection } from 'vscode-extension-tester';
...
const watchSection = await debugView.getWatchSection();
...
const items = await watchSection.getVisibleItems(); // get all items
await watchSection.removeAllExpressions(); // remove all expressions
...
await watchSection.addItem('name'); // add new expression
const item = await items.at(num); // get expression at position num
const label = await item.getLabel(); // get label of expression
const value = await item.getValu(); // get value of expression
await item.remove(); // remove expression from watch section
```

#### Call Stack

![Call Stack Section](./images/debugView-CallStack.png)

```typescript
import { CallStackSection } from 'vscode-extension-tester';
...
const callStack = await debugView.getCallStackSection();
...
const items = await callStack.getVisibleItems(); // get all items
...
const item = await items.at(num); // get item at position num
const label = await item.getLabel(); // get label of item
const text = await item.getText(); // get text of item
const btns = await item.getActionButtons(); // get available action buttons
```
Binary file added docs/images/debugView-CallStack.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/debugView-Variables.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/debugView-WatchSection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions packages/locators/lib/1.37.0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,19 @@ const sideBar = {
label: By.className('monaco-highlighted-label'),
text: By.className('state label monaco-count-badge long'),
},
WatchSection: {
predicate: async (section: ViewSection) => (await section.getTitle()).toLowerCase() === 'watch',
input: By.css('input'),
addExpression: 'Add Expression',
refresh: 'Refresh',
removeAll: 'Remove All Expressions',
collapseAll: 'Collapse All',
},
WatchSectionItem: {
label: By.className('monaco-highlighted-label'),
value: By.xpath(`.//*[contains(@class, 'value ') and starts-with(@class, 'value ')]`),
remove: 'Remove Expression',
},
ExtensionsViewSection: {
items: By.className('monaco-list-rows'),
itemRow: By.className('monaco-list-row'),
Expand Down
10 changes: 10 additions & 0 deletions packages/page-objects/src/components/sidebar/debug/DebugView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { SideBarView } from '../SideBarView';
import { DebugBreakpointSection } from '../tree/debug/DebugBreakpointSection';
import { DebugCallStackSection } from '../tree/debug/DebugCallStackSection';
import { DebugVariableSection } from '../tree/debug/DebugVariablesSection';
import { WatchSection } from '../tree/debug/WatchSection';

/**
* Page object representing the Run/Debug view in the side bar
Expand Down Expand Up @@ -100,4 +101,13 @@ export class DebugView extends SideBarView {
const content = this.getContent();
return content.getSection(DebugCallStackSection.locators.DebugCallStackSection.predicate, DebugCallStackSection);
}

/**
* Get Watch section
* @returns WatchSection page object
*/
async getWatchSection(): Promise<WatchSection> {
const content = this.getContent();
return content.getSection(WatchSection.locators.WatchSection.predicate, WatchSection);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License", destination); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Key, WebElement } from 'selenium-webdriver';
import { ViewContent } from '../../ViewContent';
import { GenericCustomTreeSection } from '../custom/CustomTreeSection';
import { WatchSectionItem } from './WatchSectionItem';

export class WatchSection extends GenericCustomTreeSection<WatchSectionItem> {
constructor(panel: WebElement, viewContent: ViewContent) {
super(panel, viewContent, WatchSectionItem);
}

/**
* Add item to Watch section.
* @param name
*/
async addItem(name: string): Promise<void> {
await (await this.getAction(WatchSection.locators.WatchSection.addExpression))?.click();
await new Promise((res) => setTimeout(res, 1000));
const textInput = await this.findElement(WatchSection.locators.WatchSection.input);
await textInput.clear();
await textInput.sendKeys(name + Key.ENTER);
}

/**
* Click on 'Refresh' button.
*/
async refresh(): Promise<void> {
await (await this.getAction(WatchSection.locators.WatchSection.refresh))?.click();
}

/**
* Remove all items in Watch seection by using 'Remove All Expression' button.
*/
async removeAllExpressions(): Promise<void> {
await (await this.getAction(WatchSection.locators.WatchSection.removeAll))?.click();
}

/**
* Collapse all items in Watch section by using 'Collapse All' button.
*/
async collapseAll(): Promise<void> {
await (await this.getAction(WatchSection.locators.WatchSection.collapseAll))?.click();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License", destination); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { WebElement } from 'selenium-webdriver';
import { TreeSection } from '../TreeSection';
import { CustomTreeItem } from '../custom/CustomTreeItem';

export class WatchSectionItem extends CustomTreeItem {
constructor(element: WebElement, viewPart: TreeSection) {
super(element, viewPart);
}

/**
* Get label of the Watch section item.
* @returns a promise resolving to Watch section item label string
*/
async getLabel(): Promise<string> {
const name = await this.findElement(WatchSectionItem.locators.WatchSectionItem.label);
return await name?.getAttribute('textContent');
}

/**
* Get value of the Watch section item.
* @returns a promise resolving to Watch section value label string
*/
async getValue(): Promise<string> {
const value = await this.findElement(WatchSectionItem.locators.WatchSectionItem.value);
return await value.getText();
}

/**
* Remove item from Watch section.
*/
async remove(): Promise<void> {
const button = await this.getActionButton(WatchSectionItem.locators.WatchSectionItem.remove);
await button?.click();
}
}
2 changes: 2 additions & 0 deletions packages/page-objects/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export * from './components/sidebar/tree/debug/DebugVariablesSection';
export * from './components/sidebar/tree/debug/VariableSectionItem';
export * from './components/sidebar/tree/debug/CallStackItem';
export * from './components/sidebar/tree/debug/DebugCallStackSection';
export * from './components/sidebar/tree/debug/WatchSection';
export * from './components/sidebar/tree/debug/WatchSectionItem';
export * from './components/sidebar/extensions/ExtensionsViewSection';
export * from './components/sidebar/extensions/ExtensionsViewItem';
export { ScmView, ScmProvider, ScmChange } from './components/sidebar/scm/ScmView';
Expand Down
13 changes: 13 additions & 0 deletions packages/page-objects/src/locators/locators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,19 @@ export interface Locators {
label: By;
text: By;
};
WatchSection: {
predicate: WebElementFunction<ViewSection, boolean>;
input: By;
addExpression: string;
refresh: string;
removeAll: string;
collapseAll: string;
};
WatchSectionItem: {
label: By;
value: By;
remove: string;
};
ExtensionsViewSection: {
items: By;
itemRow: By;
Expand Down
56 changes: 56 additions & 0 deletions tests/test-project/src/test/debug/debug.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
TextEditor,
until,
VSBrowser,
WatchSection,
WebDriver,
Workbench,
} from 'vscode-extension-tester';
Expand Down Expand Up @@ -98,6 +99,7 @@ describe('Debugging', function () {
let driver: WebDriver;
let breakpoint!: Breakpoint;
let callStack: DebugCallStackSection;
let watchSection: WatchSection;

before(async function () {
editor = (await new EditorView().openEditor('test.js')) as TextEditor;
Expand Down Expand Up @@ -291,6 +293,60 @@ describe('Debugging', function () {
await item?.setVariableValue('42');
item = await getNumVariable(view, this.timeout() - 2000);
expect(await item?.getVariableValue()).equals('42');
await item
?.getDriver()
.actions()
.move({ x: Math.ceil(0), y: Math.ceil(0) })
.click()
.perform(); // dismiss hover to prevent errors in next tests
});

it('WatchSection.getWatchSection', async function () {
watchSection = await view.getWatchSection();
expect(watchSection).not.undefined;
});

it('WatchSection.getVisibleItems', async function () {
const items = await watchSection.getVisibleItems();
expect(items.length).equals(0);
});

it('WatchSection.addItem', async function () {
await watchSection.addItem('num');
await watchSection.addItem('bool');
await watchSection.addItem('line');

const items = await watchSection.getVisibleItems();
expect(items.length).equals(3);
});

it('WatchSectionItem.getLabel', async function () {
const items = await watchSection.getVisibleItems();
expect(await items.at(0)?.getLabel()).to.contain('num');
expect(await items.at(1)?.getLabel()).to.contain('bool');
expect(await items.at(2)?.getLabel()).to.contain('line');
});

it('WatchSectionItem.getValue', async function () {
const items = await watchSection.getVisibleItems();
expect(await items.at(0)?.getValue()).to.contain('42');
expect(await items.at(1)?.getValue()).to.contain('false');
expect(await items.at(2)?.getValue()).to.contain("'line'");
});

it('WatchSectionItem.remove', async function () {
let items = await watchSection.getVisibleItems();
await items.at(0)?.remove();
items = await watchSection.getVisibleItems();
expect(items.length).equals(2);
expect(await items.at(0)?.getLabel()).to.contain('bool');
expect(await items.at(1)?.getLabel()).to.contain('line');
});

it('WatchSection.removeAllExpressions', async function () {
await watchSection.removeAllExpressions();
const items = await watchSection.getVisibleItems();
expect(items.length).equals(0);
});

it('CallStack: getCallStackSection', async function () {
Expand Down

0 comments on commit c1ceab4

Please sign in to comment.