From 7bd69c0c86dc78329eec3a98366f3f137b558828 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 10 Apr 2018 12:34:46 +0200 Subject: [PATCH] attributes, children on IElement instances --- src/vs/platform/driver/common/driver.ts | 22 ++++++------ .../driver/electron-browser/driver.ts | 34 +++++++++++++++---- .../platform/driver/electron-main/driver.ts | 4 +-- test/smoke/src/api.ts | 4 +-- test/smoke/src/areas/debug/debug.ts | 2 +- test/smoke/src/areas/editor/editor.ts | 4 +-- test/smoke/src/areas/editor/peek.ts | 2 +- .../src/areas/preferences/preferences.test.ts | 4 +-- test/smoke/src/areas/quickopen/quickopen.ts | 2 +- test/smoke/src/driver.ts | 10 +++--- 10 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/vs/platform/driver/common/driver.ts b/src/vs/platform/driver/common/driver.ts index 4adbbd20009..0fdcc5d46c5 100644 --- a/src/vs/platform/driver/common/driver.ts +++ b/src/vs/platform/driver/common/driver.ts @@ -17,6 +17,8 @@ export interface IElement { tagName: string; className: string; textContent: string; + attributes: { [name: string]: string; }; + children: IElement[]; } export interface IDriver { @@ -30,7 +32,7 @@ export interface IDriver { setValue(windowId: number, selector: string, text: string): TPromise; getTitle(windowId: number): TPromise; isActiveElement(windowId: number, selector: string): TPromise; - getElements(windowId: number, selector: string): TPromise; + getElements(windowId: number, selector: string, recursive: boolean): TPromise; selectorExecute

(windowId: number, selector: string, script: (elements: HTMLElement[], ...args: any[]) => P, ...args: any[]): TPromise

; } //*END @@ -44,7 +46,7 @@ export interface IDriverChannel extends IChannel { call(command: 'setValue', arg: [number, string, string]): TPromise; call(command: 'getTitle', arg: [number]): TPromise; call(command: 'isActiveElement', arg: [number, string]): TPromise; - call(command: 'getElements', arg: [number, string]): TPromise; + call(command: 'getElements', arg: [number, string, boolean]): TPromise; call(command: 'selectorExecute', arg: [number, string, string, any[]]): TPromise; call(command: string, arg: any): TPromise; } @@ -63,7 +65,7 @@ export class DriverChannel implements IDriverChannel { case 'setValue': return this.driver.setValue(arg[0], arg[1], arg[2]); case 'getTitle': return this.driver.getTitle(arg[0]); case 'isActiveElement': return this.driver.isActiveElement(arg[0], arg[1]); - case 'getElements': return this.driver.getElements(arg[0], arg[1]); + case 'getElements': return this.driver.getElements(arg[0], arg[1], arg[2]); // TODO@joao case 'selectorExecute': return this.driver.selectorExecute(arg[0], arg[1], arg[1], ...arg[2]); @@ -111,8 +113,8 @@ export class DriverChannelClient implements IDriver { return this.channel.call('isActiveElement', [windowId, selector]); } - getElements(windowId: number, selector: string): TPromise { - return this.channel.call('getElements', [windowId, selector]); + getElements(windowId: number, selector: string, recursive: boolean): TPromise { + return this.channel.call('getElements', [windowId, selector, recursive]); } selectorExecute

(windowId: number, selector: string, script: (elements: HTMLElement[], ...args: any[]) => P, ...args: any[]): TPromise

{ @@ -161,7 +163,7 @@ export interface IWindowDriver { setValue(selector: string, text: string): TPromise; getTitle(): TPromise; isActiveElement(selector: string): TPromise; - getElements(selector: string): TPromise; + getElements(selector: string, recursive: boolean): TPromise; selectorExecute

(selector: string, script: (elements: HTMLElement[], ...args: any[]) => P, ...args: any[]): TPromise

; } @@ -172,7 +174,7 @@ export interface IWindowDriverChannel extends IChannel { call(command: 'setValue', arg: [string, string]): TPromise; call(command: 'getTitle'): TPromise; call(command: 'isActiveElement', arg: string): TPromise; - call(command: 'getElements', arg: string): TPromise; + call(command: 'getElements', arg: [string, boolean]): TPromise; call(command: 'selectorExecute', arg: [string, string, any[]]): TPromise; call(command: string, arg: any): TPromise; } @@ -189,7 +191,7 @@ export class WindowDriverChannel implements IWindowDriverChannel { case 'setValue': return this.driver.setValue(arg[0], arg[1]); case 'getTitle': return this.driver.getTitle(); case 'isActiveElement': return this.driver.isActiveElement(arg); - case 'getElements': return this.driver.getElements(arg); + case 'getElements': return this.driver.getElements(arg[0], arg[1]); // TODO@joao case 'selectorExecute': return this.driver.selectorExecute(arg[0], arg[1], ...arg[2]); } @@ -228,8 +230,8 @@ export class WindowDriverChannelClient implements IWindowDriver { return this.channel.call('isActiveElement', selector); } - getElements(selector: string): TPromise { - return this.channel.call('getElements', selector); + getElements(selector: string, recursive: boolean): TPromise { + return this.channel.call('getElements', [selector, recursive]); } selectorExecute

(selector: string, script: (elements: HTMLElement[], ...args: any[]) => P, ...args: any[]): TPromise

{ diff --git a/src/vs/platform/driver/electron-browser/driver.ts b/src/vs/platform/driver/electron-browser/driver.ts index 99f7a7e5cd0..44100426f4f 100644 --- a/src/vs/platform/driver/electron-browser/driver.ts +++ b/src/vs/platform/driver/electron-browser/driver.ts @@ -11,6 +11,31 @@ import { IWindowDriver, IElement, WindowDriverChannel, WindowDriverRegistryChann import { IPCClient } from 'vs/base/parts/ipc/common/ipc'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +function serializeElement(element: Element, recursive: boolean): IElement { + const attributes = Object.create(null); + + for (let j = 0; j < element.attributes.length; j++) { + const attr = element.attributes.item(j); + attributes[attr.name] = attr.value; + } + + const children = []; + + if (recursive) { + for (let i = 0; i < element.children.length; i++) { + children.push(serializeElement(element.children.item(i), true)); + } + } + + return { + tagName: element.tagName, + className: element.className, + textContent: element.textContent || '', + attributes, + children + }; +} + class WindowDriver implements IWindowDriver { constructor() { } @@ -50,18 +75,13 @@ class WindowDriver implements IWindowDriver { return element === document.activeElement; } - async getElements(selector: string): TPromise { + async getElements(selector: string, recursive: boolean): TPromise { const query = document.querySelectorAll(selector); const result: IElement[] = []; for (let i = 0; i < query.length; i++) { const element = query.item(i); - - result.push({ - tagName: element.tagName, - className: element.className, - textContent: element.textContent || '' - }); + result.push(serializeElement(element, recursive)); } return result; diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index 0b971ac2632..1676316a3a5 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -127,9 +127,9 @@ export class Driver implements IDriver, IWindowDriverRegistry { return windowDriver.isActiveElement(selector); } - getElements(windowId: number, selector: string): TPromise { + getElements(windowId: number, selector: string, recursive: boolean): TPromise { const windowDriver = this.getWindowDriver(windowId); - return windowDriver.getElements(selector); + return windowDriver.getElements(selector, recursive); } selectorExecute

(windowId: number, selector: string, script: (elements: HTMLElement[], ...args: any[]) => P, ...args: any[]): TPromise

{ diff --git a/test/smoke/src/api.ts b/test/smoke/src/api.ts index a2f8b5ce21d..d93d19ff05f 100644 --- a/test/smoke/src/api.ts +++ b/test/smoke/src/api.ts @@ -60,8 +60,8 @@ export class API { return elements.length; } - waitForElements(selector: string, accept: (result: Element[]) => boolean = result => result.length > 0): Promise { - return this.waitFor(() => this.driver.getElements(selector), accept, `elements with selector ${selector}`) as Promise; + waitForElements(selector: string, recursive: boolean, accept: (result: Element[]) => boolean = result => result.length > 0): Promise { + return this.waitFor(() => this.driver.getElements(selector, recursive), accept, `elements with selector ${selector}`) as Promise; } waitForElement(selector: string, accept: (result: Element | undefined) => boolean = result => !!result): Promise { diff --git a/test/smoke/src/areas/debug/debug.ts b/test/smoke/src/areas/debug/debug.ts index b346f7395c9..630c5c95340 100644 --- a/test/smoke/src/areas/debug/debug.ts +++ b/test/smoke/src/areas/debug/debug.ts @@ -105,7 +105,7 @@ export class Debug extends Viewlet { } async waitForStackFrameLength(length: number): Promise { - await this.api.waitForElements(STACK_FRAME, result => result.length === length); + await this.api.waitForElements(STACK_FRAME, false, result => result.length === length); } async focusStackFrame(name: string, message: string): Promise { diff --git a/test/smoke/src/areas/editor/editor.ts b/test/smoke/src/areas/editor/editor.ts index 74486d947b3..552a4fc743b 100644 --- a/test/smoke/src/areas/editor/editor.ts +++ b/test/smoke/src/areas/editor/editor.ts @@ -125,13 +125,13 @@ export class Editor { } private async getClassSelectors(term: string, viewline: number): Promise { - const elements = await this.api.waitForElements(`${Editor.VIEW_LINES}>:nth-child(${viewline}) span span`, els => els.some(el => el.textContent === term)); + const elements = await this.api.waitForElements(`${Editor.VIEW_LINES}>:nth-child(${viewline}) span span`, false, els => els.some(el => el.textContent === term)); const { className } = elements.filter(r => r.textContent === term)[0]; return className.split(/\s/g); } private async getViewLineIndex(line: number): Promise { - const elements = await this.api.waitForElements(Editor.LINE_NUMBERS, els => { + const elements = await this.api.waitForElements(Editor.LINE_NUMBERS, false, els => { return els.some(el => el.textContent === `${line}`); }); diff --git a/test/smoke/src/areas/editor/peek.ts b/test/smoke/src/areas/editor/peek.ts index fe094cdb683..4f0bd9170b2 100644 --- a/test/smoke/src/areas/editor/peek.ts +++ b/test/smoke/src/areas/editor/peek.ts @@ -26,7 +26,7 @@ export class References { } async waitForReferencesCount(count: number): Promise { - await this.api.waitForElements(References.REFERENCES, result => result && result.length === count); + await this.api.waitForElements(References.REFERENCES, false, result => result && result.length === count); } async waitForFile(file: string): Promise { diff --git a/test/smoke/src/areas/preferences/preferences.test.ts b/test/smoke/src/areas/preferences/preferences.test.ts index fc1dccb8d6d..e0d0e8223ab 100644 --- a/test/smoke/src/areas/preferences/preferences.test.ts +++ b/test/smoke/src/areas/preferences/preferences.test.ts @@ -18,12 +18,12 @@ export function setup() { const app = this.app as SpectronApplication; await app.workbench.explorer.openFile('app.js'); - await app.api.waitForElements('.line-numbers', elements => !!elements.length); + await app.api.waitForElements('.line-numbers', false, elements => !!elements.length); await app.screenCapturer.capture('app.js has line numbers'); await app.workbench.settingsEditor.addUserSetting('editor.lineNumbers', '"off"'); await app.workbench.editors.selectTab('app.js'); - await app.api.waitForElements('.line-numbers', result => !result || result.length === 0); + await app.api.waitForElements('.line-numbers', false, result => !result || result.length === 0); await app.screenCapturer.capture('line numbers hidden'); }); diff --git a/test/smoke/src/areas/quickopen/quickopen.ts b/test/smoke/src/areas/quickopen/quickopen.ts index a4a14ee2cf3..9d411f60d77 100644 --- a/test/smoke/src/areas/quickopen/quickopen.ts +++ b/test/smoke/src/areas/quickopen/quickopen.ts @@ -65,7 +65,7 @@ export class QuickOpen { } async waitForQuickOpenElements(accept: (names: string[]) => boolean): Promise { - await this.api.waitForElements(QuickOpen.QUICK_OPEN_ENTRY_LABEL_SELECTOR, els => accept(els.map(e => e.textContent))); + await this.api.waitForElements(QuickOpen.QUICK_OPEN_ENTRY_LABEL_SELECTOR, false, els => accept(els.map(e => e.textContent))); } async runCommand(command: string): Promise { diff --git a/test/smoke/src/driver.ts b/test/smoke/src/driver.ts index e3163c6cfe1..bc7d4edb503 100644 --- a/test/smoke/src/driver.ts +++ b/test/smoke/src/driver.ts @@ -10,6 +10,7 @@ export interface Element { tagName: string; className: string; textContent: string; + attributes: { [name: string]: string }; } export interface Driver { @@ -21,7 +22,7 @@ export interface Driver { getTitle(): Promise; isActiveElement(selector: string): Promise; - getElements(selector: string): Promise; + getElements(selector: string, recursive?: boolean): Promise; selectorExecute

(selector: string, script: (elements: HTMLElement[], ...args: any[]) => P, ...args: any[]): Promise

; } @@ -104,7 +105,8 @@ export class SpectronDriver implements Driver { result.push({ tagName: element.tagName, className: element.className, - textContent: element.textContent || '' + textContent: element.textContent || '', + attributes: {} }); } @@ -196,13 +198,13 @@ export class CodeDriver implements Driver { return await this.driver.isActiveElement(windowId, selector); } - async getElements(selector: string): Promise { + async getElements(selector: string, recursive = false): Promise { if (this.verbose) { console.log('- getElements:', selector); } const windowId = await this.getWindowId(); - const result = await this.driver.getElements(windowId, selector); + const result = await this.driver.getElements(windowId, selector, recursive); return result; } -- GitLab