extract driver

This commit is contained in:
Joao Moreno
2018-04-05 23:35:44 +02:00
parent 5be3af25dc
commit 3fe4ed9dbb
35 changed files with 174 additions and 168 deletions
@@ -6,13 +6,14 @@
import { Application, SpectronClient as WebClient } from 'spectron';
import { test as testPort } from 'portastic';
import { API } from './client';
import { ScreenCapturer } from '../helpers/screenshot';
import { Workbench } from '../areas/workbench/workbench';
import { ScreenCapturer } from './helpers/screenshot';
import { Workbench } from './areas/workbench/workbench';
import * as fs from 'fs';
import * as cp from 'child_process';
import * as path from 'path';
import * as mkdirp from 'mkdirp';
import { sanitize } from '../helpers/utilities';
import { sanitize } from './helpers/utilities';
import { SpectronDriver } from './driver';
// Just hope random helps us here, cross your fingers!
export async function findFreePort(): Promise<number> {
@@ -271,7 +272,9 @@ export class SpectronApplication {
}
this._screenCapturer = new ScreenCapturer(this.spectron, this._suiteName, screenshotsDirPath);
this._api = new API(this.spectron.client, this.screenCapturer, this.options.waitTime, this.options.verbose);
const driver = new SpectronDriver(this.spectron.client, this.options.verbose);
this._api = new API(driver, this.screenCapturer, this.options.waitTime);
this._workbench = new Workbench(this._api, this.keybindings, this.userDataPath);
}
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { API } from '../../spectron/client';
import { API } from '../../client';
export enum ActivityBarPosition {
LEFT = 0,
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SpectronApplication } from '../../spectron/application';
import { SpectronApplication } from '../../application';
import { ProblemSeverity, Problems } from '../problems/problems';
export function setup() {
+1 -1
View File
@@ -8,7 +8,7 @@ import * as http from 'http';
import * as path from 'path';
import * as fs from 'fs';
import * as stripJsonComments from 'strip-json-comments';
import { SpectronApplication } from '../../spectron/application';
import { SpectronApplication } from '../../application';
export function setup() {
describe('Debug', () => {
+1 -1
View File
@@ -5,7 +5,7 @@
import { Viewlet } from '../workbench/viewlet';
import { Commands } from '../workbench/workbench';
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Editors } from '../editor/editors';
import { Editor } from '../editor/editor';
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SpectronApplication } from '../../spectron/application';
import { SpectronApplication } from '../../application';
export function setup() {
describe('Editor', () => {
+1 -1
View File
@@ -5,7 +5,7 @@
import { References } from './peek';
import { Commands } from '../workbench/workbench';
import { API } from '../../spectron/client';
import { API } from '../../client';
const RENAME_BOX = '.monaco-editor .monaco-editor.rename-box';
const RENAME_INPUT = `${RENAME_BOX} .rename-input`;
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Commands } from '../workbench/workbench';
export class Editors {
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { API } from '../../spectron/client';
import { API } from '../../client';
export class References {
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SpectronApplication } from '../../spectron/application';
import { SpectronApplication } from '../../application';
export function setup() {
describe('Explorer', () => {
+1 -1
View File
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Viewlet } from '../workbench/viewlet';
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Editors } from '../editor/editors';
import { Commands } from '../workbench/workbench';
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { SpectronApplication, Quality } from '../../spectron/application';
import { SpectronApplication, Quality } from '../../application';
export function setup() {
describe('Extensions', () => {
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Viewlet } from '../workbench/viewlet';
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Commands } from '../workbench/workbench';
const SEARCH_BOX = 'div.extensions-viewlet[id="workbench.view.extensions"] input.search-box';
+1 -1
View File
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as cp from 'child_process';
import { SpectronApplication } from '../../spectron/application';
import { SpectronApplication } from '../../application';
const DIFF_EDITOR_LINE_INSERT = '.monaco-diff-editor .editor.modified .line-insert';
const SYNC_STATUSBAR = 'div[id="workbench.parts.statusbar"] .statusbar-entry a[title$="Synchronize Changes"]';
+1 -1
View File
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Viewlet } from '../workbench/viewlet';
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Commands } from '../workbench/workbench';
const VIEWLET = 'div[id="workbench.view.scm"]';
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { SpectronApplication } from '../../spectron/application';
import { SpectronApplication } from '../../application';
export function setup() {
describe('Multiroot', () => {
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Commands } from '../workbench/workbench';
const SEARCH_INPUT = '.settings-search-input input';
@@ -5,7 +5,7 @@
import * as assert from 'assert';
import { SpectronApplication } from '../../spectron/application';
import { SpectronApplication } from '../../application';
import { ActivityBarPosition } from '../activitybar/activityBar';
export function setup() {
+1 -1
View File
@@ -5,7 +5,7 @@
import * as fs from 'fs';
import * as path from 'path';
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Commands } from '../workbench/workbench';
import { Editor } from '../editor/editor';
import { Editors } from '../editor/editors';
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Commands } from '../workbench/workbench';
export enum ProblemSeverity {
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Editors } from '../editor/editors';
import { Commands } from '../workbench/workbench';
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SpectronApplication } from '../../spectron/application';
import { SpectronApplication } from '../../application';
export function setup() {
describe('Search', () => {
+1 -1
View File
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Viewlet } from '../workbench/viewlet';
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Commands } from '../workbench/workbench';
const VIEWLET = 'div[id="workbench.view.search"] .search-view';
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SpectronApplication, Quality } from '../../spectron/application';
import { SpectronApplication, Quality } from '../../application';
import { StatusBarElement } from './statusbar';
export function setup() {
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { API } from '../../spectron/client';
import { API } from '../../client';
export enum StatusBarElement {
BRANCH_STATUS = 0,
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// import { SpectronApplication } from '../../spectron/application';
// import { SpectronApplication } from '../../application';
describe('Terminal', () => {
// let app: SpectronApplication;
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Commands } from '../workbench/workbench';
const PANEL_SELECTOR = 'div[id="workbench.panel.terminal"]';
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SpectronApplication } from '../../spectron/application';
import { SpectronApplication } from '../../application';
export function setup() {
describe('Dataloss', () => {
@@ -5,7 +5,7 @@
import * as assert from 'assert';
import { SpectronApplication, Quality } from '../../spectron/application';
import { SpectronApplication, Quality } from '../../application';
import * as rimraf from 'rimraf';
export interface ICreateAppFn {
@@ -5,7 +5,7 @@
import * as assert from 'assert';
import { SpectronApplication, Quality } from '../../spectron/application';
import { SpectronApplication, Quality } from '../../application';
export function setup() {
describe('Localization', () => {
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { API } from '../../spectron/client';
import { API } from '../../client';
export abstract class Viewlet {
+1 -1
View File
@@ -16,7 +16,7 @@ import { Problems } from '../problems/problems';
import { SettingsEditor } from '../preferences/settings';
import { KeybindingsEditor } from '../preferences/keybindings';
import { Terminal } from '../terminal/terminal';
import { API } from '../../spectron/client';
import { API } from '../../client';
import { Editors } from '../editor/editors';
export interface Commands {
@@ -3,131 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SpectronClient } from 'spectron';
import { ScreenCapturer } from '../helpers/screenshot';
export interface APIElement {
tagName: string;
className: string;
textContent: string;
}
export interface Driver {
keys(keys: string[]): Promise<void>;
click(selector: string, xoffset?: number, yoffset?: number): Promise<any>;
doubleClick(selector: string): Promise<any>;
move(selector: string): Promise<any>;
setValue(selector: string, text: string): Promise<void>;
getTitle(): Promise<string>;
isActiveElement(selector: string): Promise<boolean>;
getElements(selector: string): Promise<APIElement[]>;
selectorExecute<P>(selector: string, script: (elements: HTMLElement[], ...args: any[]) => P, ...args: any[]): Promise<P>;
}
export class SpectronDriver implements Driver {
constructor(
private spectronClient: SpectronClient,
private verbose: boolean
) { }
keys(keys: string[]): Promise<void> {
if (this.verbose) {
console.log('- keys:', keys);
}
this.spectronClient.keys(keys);
return Promise.resolve();
}
async click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise<void> {
if (this.verbose) {
console.log('- click:', selector, xoffset, yoffset);
}
await this.spectronClient.leftClick(selector, xoffset, yoffset);
if (this.verbose) {
console.log('- click DONE');
}
}
async doubleClick(selector: string): Promise<void> {
if (this.verbose) {
console.log('- doubleClick:', selector);
}
await this.spectronClient.doubleClick(selector);
}
async move(selector: string): Promise<void> {
if (this.verbose) {
console.log('- move:', selector);
}
await this.spectronClient.moveToObject(selector);
}
async setValue(selector: string, text: string): Promise<void> {
if (this.verbose) {
console.log('- setValue:', selector, text);
}
await this.spectronClient.setValue(selector, text);
}
async getTitle(): Promise<string> {
if (this.verbose) {
console.log('- getTitle');
}
return await this.spectronClient.getTitle();
}
async isActiveElement(selector: string): Promise<boolean> {
if (this.verbose) {
console.log('- isActiveElement:', selector);
}
const result = await (this.spectronClient.execute(s => document.activeElement.matches(s), selector) as any as Promise<{ value: boolean; }>);
return result.value;
}
async getElements(selector: string): Promise<APIElement[]> {
if (this.verbose) {
console.log('- getElements:', selector);
}
const result = await (this.spectronClient.execute(selector => {
const query = document.querySelectorAll(selector);
const result: APIElement[] = [];
for (let i = 0; i < query.length; i++) {
const element: HTMLElement = query.item(i);
result.push({
tagName: element.tagName,
className: element.className,
textContent: element.textContent || ''
});
}
return result;
}, selector) as any as Promise<{ value: APIElement[]; }>);
return result.value;
}
async selectorExecute<P>(selector: string, script: (elements: HTMLElement[], ...args: any[]) => P, ...args: any[]): Promise<P> {
if (this.verbose) {
console.log('- selectorExecute:', selector);
}
let _script = (element, script, ...args) => script(Array.isArray(element) ? element : [element], ...args);
return this.spectronClient.selectorExecute(selector, _script, script, ...args);
}
}
import { ScreenCapturer } from './helpers/screenshot';
import { Driver, Element } from './driver';
export class API {
@@ -135,15 +12,12 @@ export class API {
// the time it takes for the actual retry call to complete
private retryCount: number;
private readonly retryDuration = 100; // in milliseconds
private driver: Driver;
constructor(
spectronClient: SpectronClient,
private driver: Driver,
private screenCapturer: ScreenCapturer,
waitTime: number,
verbose: boolean
waitTime: number
) {
this.driver = new SpectronDriver(spectronClient, verbose);
this.retryCount = (waitTime * 1000) / this.retryDuration;
}
@@ -186,11 +60,11 @@ export class API {
return elements.length;
}
waitForElements(selector: string, accept: (result: APIElement[]) => boolean = result => result.length > 0): Promise<APIElement[]> {
waitForElements(selector: string, accept: (result: Element[]) => boolean = result => result.length > 0): Promise<Element[]> {
return this.waitFor(() => this.driver.getElements(selector), accept, `elements with selector ${selector}`) as Promise<any>;
}
waitForElement(selector: string, accept: (result: APIElement | undefined) => boolean = result => !!result): Promise<void> {
waitForElement(selector: string, accept: (result: Element | undefined) => boolean = result => !!result): Promise<void> {
return this.waitFor(() => this.driver.getElements(selector).then(els => els[0]), accept, `element with selector ${selector}`) as Promise<any>;
}
+129
View File
@@ -0,0 +1,129 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SpectronClient } from 'spectron';
export interface Element {
tagName: string;
className: string;
textContent: string;
}
export interface Driver {
keys(keys: string[]): Promise<void>;
click(selector: string, xoffset?: number, yoffset?: number): Promise<any>;
doubleClick(selector: string): Promise<any>;
move(selector: string): Promise<any>;
setValue(selector: string, text: string): Promise<void>;
getTitle(): Promise<string>;
isActiveElement(selector: string): Promise<boolean>;
getElements(selector: string): Promise<Element[]>;
selectorExecute<P>(selector: string, script: (elements: HTMLElement[], ...args: any[]) => P, ...args: any[]): Promise<P>;
}
export class SpectronDriver implements Driver {
constructor(
private spectronClient: SpectronClient,
private verbose: boolean
) { }
keys(keys: string[]): Promise<void> {
if (this.verbose) {
console.log('- keys:', keys);
}
this.spectronClient.keys(keys);
return Promise.resolve();
}
async click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise<void> {
if (this.verbose) {
console.log('- click:', selector, xoffset, yoffset);
}
await this.spectronClient.leftClick(selector, xoffset, yoffset);
if (this.verbose) {
console.log('- click DONE');
}
}
async doubleClick(selector: string): Promise<void> {
if (this.verbose) {
console.log('- doubleClick:', selector);
}
await this.spectronClient.doubleClick(selector);
}
async move(selector: string): Promise<void> {
if (this.verbose) {
console.log('- move:', selector);
}
await this.spectronClient.moveToObject(selector);
}
async setValue(selector: string, text: string): Promise<void> {
if (this.verbose) {
console.log('- setValue:', selector, text);
}
await this.spectronClient.setValue(selector, text);
}
async getTitle(): Promise<string> {
if (this.verbose) {
console.log('- getTitle');
}
return await this.spectronClient.getTitle();
}
async isActiveElement(selector: string): Promise<boolean> {
if (this.verbose) {
console.log('- isActiveElement:', selector);
}
const result = await (this.spectronClient.execute(s => document.activeElement.matches(s), selector) as any as Promise<{ value: boolean; }>);
return result.value;
}
async getElements(selector: string): Promise<Element[]> {
if (this.verbose) {
console.log('- getElements:', selector);
}
const result = await (this.spectronClient.execute(selector => {
const query = document.querySelectorAll(selector);
const result: Element[] = [];
for (let i = 0; i < query.length; i++) {
const element: HTMLElement = query.item(i);
result.push({
tagName: element.tagName,
className: element.className,
textContent: element.textContent || ''
});
}
return result;
}, selector) as any as Promise<{ value: Element[]; }>);
return result.value;
}
async selectorExecute<P>(selector: string, script: (elements: HTMLElement[], ...args: any[]) => P, ...args: any[]): Promise<P> {
if (this.verbose) {
console.log('- selectorExecute:', selector);
}
let _script = (element, script, ...args) => script(Array.isArray(element) ? element : [element], ...args);
return this.spectronClient.selectorExecute(selector, _script, script, ...args);
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ import * as minimist from 'minimist';
import * as tmp from 'tmp';
import * as rimraf from 'rimraf';
import * as mkdirp from 'mkdirp';
import { SpectronApplication, Quality } from './spectron/application';
import { SpectronApplication, Quality } from './application';
import { setup as setupDataMigrationTests } from './areas/workbench/data-migration.test';
import { setup as setupDataLossTests } from './areas/workbench/data-loss.test';