diff --git a/test/smoke/src/areas/debug/debug.ts b/test/smoke/src/areas/debug/debug.ts index 8ee59bb86755b31d8ab5690b290dfa6dc0cd324c..bf92dd930ff5a12b492bfcc4b77206e09a83f206 100644 --- a/test/smoke/src/areas/debug/debug.ts +++ b/test/smoke/src/areas/debug/debug.ts @@ -122,7 +122,7 @@ export class Debug extends Viewlet { async waitForReplCommand(text: string, accept: (result: string) => boolean): Promise { await this.commands.runCommand('Debug: Focus Debug Console'); await this.code.waitForActiveElement(REPL_FOCUSED); - await this.code.setValue(REPL_FOCUSED, text); + await this.code.waitForSetValue(REPL_FOCUSED, text); // Wait for the keys to be picked up by the editor model such that repl evalutes what just got typed await this.editor.waitForEditorContents('debug:input', s => s.indexOf(text) >= 0); diff --git a/test/smoke/src/areas/editor/editor.ts b/test/smoke/src/areas/editor/editor.ts index 8bc52eaeaf54c8123808c3806afd2f02a8d2096b..41a04d85412f14dae0afc0cd825fab71d2e301c6 100644 --- a/test/smoke/src/areas/editor/editor.ts +++ b/test/smoke/src/areas/editor/editor.ts @@ -33,7 +33,7 @@ export class Editor { await this.commands.runCommand('Rename Symbol'); await this.code.waitForActiveElement(RENAME_INPUT); - await this.code.setValue(RENAME_INPUT, to); + await this.code.waitForSetValue(RENAME_INPUT, to); await this.code.dispatchKeybinding('enter'); } @@ -95,14 +95,13 @@ export class Editor { const textarea = `${editor} textarea`; await this.code.waitForActiveElement(textarea); - await this.code.typeInEditor(textarea, text); + await this.code.waitForTypeInEditor(textarea, text); await this.waitForEditorContents(filename, c => c.indexOf(text) > -1, selectorPrefix); } async waitForEditorContents(filename: string, accept: (contents: string) => boolean, selectorPrefix = ''): Promise { const selector = [selectorPrefix || '', `${EDITOR(filename)} .view-lines`].join(' '); - return this.code.waitForTextContent(selector, undefined, c => accept(c.replace(/\u00a0/g, ' '))); } diff --git a/test/smoke/src/areas/extensions/extensions.ts b/test/smoke/src/areas/extensions/extensions.ts index 017c39d742068376dc0b7322af10112341e6d527..64bfb07dd3d85e0d2bdfcfa5d52562a41e0f0f8d 100644 --- a/test/smoke/src/areas/extensions/extensions.ts +++ b/test/smoke/src/areas/extensions/extensions.ts @@ -27,7 +27,7 @@ export class Extensions extends Viewlet { async searchForExtension(name: string): Promise { await this.code.waitAndClick(SEARCH_BOX); await this.code.waitForActiveElement(SEARCH_BOX); - await this.code.setValue(SEARCH_BOX, name); + await this.code.waitForSetValue(SEARCH_BOX, name); } async installExtension(name: string): Promise { diff --git a/test/smoke/src/areas/git/scm.ts b/test/smoke/src/areas/git/scm.ts index 4543c6fc689ceeb50d1df55407e610ed50b84759..9c2a6f3e871c29d214345d58bdbad140133bd0a9 100644 --- a/test/smoke/src/areas/git/scm.ts +++ b/test/smoke/src/areas/git/scm.ts @@ -78,7 +78,7 @@ export class SCM extends Viewlet { async commit(message: string): Promise { await this.code.waitAndClick(SCM_INPUT); await this.code.waitForActiveElement(SCM_INPUT); - await this.code.setValue(SCM_INPUT, message); + await this.code.waitForSetValue(SCM_INPUT, message); await this.code.waitAndClick(COMMIT_COMMAND); } } \ No newline at end of file diff --git a/test/smoke/src/areas/preferences/keybindings.ts b/test/smoke/src/areas/preferences/keybindings.ts index 98865e492c42adf3f15f9b673defa498d1aeb5c9..807a971891eb06508167b2ceacad8c65f072410d 100644 --- a/test/smoke/src/areas/preferences/keybindings.ts +++ b/test/smoke/src/areas/preferences/keybindings.ts @@ -15,7 +15,7 @@ export class KeybindingsEditor { async updateKeybinding(command: string, keybinding: string, ariaLabel: string): Promise { await this.commands.runCommand('workbench.action.openGlobalKeybindings'); await this.code.waitForActiveElement(SEARCH_INPUT); - await this.code.setValue(SEARCH_INPUT, command); + await this.code.waitForSetValue(SEARCH_INPUT, command); await this.code.waitAndClick('div[aria-label="Keybindings"] .monaco-list-row.keybinding-item'); await this.code.waitForElement('div[aria-label="Keybindings"] .monaco-list-row.keybinding-item.focused.selected'); diff --git a/test/smoke/src/areas/preferences/settings.ts b/test/smoke/src/areas/preferences/settings.ts index 2c64ae89b129ab10837a28c013bf1603284ef09d..3ac980596297779176c698e293e4bce25407c69a 100644 --- a/test/smoke/src/areas/preferences/settings.ts +++ b/test/smoke/src/areas/preferences/settings.ts @@ -39,6 +39,7 @@ export class SettingsEditor { const settingsPath = path.join(this.userDataPath, 'User', 'settings.json'); await new Promise((c, e) => fs.writeFile(settingsPath, '{}', 'utf8', err => err ? e(err) : c())); - await this.editor.waitForEditorContents('settings.json', c => c.length === 0, '.editable-preferences-editor-container'); + await this.commands.runCommand('workbench.action.openGlobalSettings'); + await this.editor.waitForEditorContents('settings.json', c => c === '{}', '.editable-preferences-editor-container'); } } \ No newline at end of file diff --git a/test/smoke/src/areas/problems/problems.ts b/test/smoke/src/areas/problems/problems.ts index b5c671a9e703b01bfe25ddf1a2aca6336546c1dc..0b82fa6914ecc976f9d5d3bc8d5ad1d92f050676 100644 --- a/test/smoke/src/areas/problems/problems.ts +++ b/test/smoke/src/areas/problems/problems.ts @@ -15,26 +15,16 @@ export class Problems { static PROBLEMS_VIEW_SELECTOR = '.panel.markers-panel'; - constructor(private code: Code, private commands: Commands) { - // noop - } + constructor(private code: Code, private commands: Commands) { } public async showProblemsView(): Promise { - if (!await this.isVisible()) { - await this.commands.runCommand('workbench.actions.view.problems'); - await this.waitForProblemsView(); - } + await this.commands.runCommand('workbench.actions.view.problems'); + await this.waitForProblemsView(); } public async hideProblemsView(): Promise { - if (await this.isVisible()) { - await this.commands.runCommand('workbench.actions.view.problems'); - await this.code.waitForElement(Problems.PROBLEMS_VIEW_SELECTOR, el => !el); - } - } - - isVisible(): Promise { - return this.code.doesElementExist(Problems.PROBLEMS_VIEW_SELECTOR); + await this.commands.runCommand('workbench.actions.view.problems'); + await this.code.waitForElement(Problems.PROBLEMS_VIEW_SELECTOR, el => !el); } public async waitForProblemsView(): Promise { diff --git a/test/smoke/src/areas/quickopen/quickopen.ts b/test/smoke/src/areas/quickopen/quickopen.ts index c580efdf69d22e9dbebed0420456861cb13840f6..35cc55464ff0a70985a80ec3d15d5a6a252cce30 100644 --- a/test/smoke/src/areas/quickopen/quickopen.ts +++ b/test/smoke/src/areas/quickopen/quickopen.ts @@ -23,7 +23,7 @@ export class QuickOpen { await this.waitForQuickOpenOpened(); if (value) { - await this.code.setValue(QuickOpen.QUICK_OPEN_INPUT, value); + await this.code.waitForSetValue(QuickOpen.QUICK_OPEN_INPUT, value); } } @@ -50,7 +50,7 @@ export class QuickOpen { } async submit(text: string): Promise { - await this.code.setValue(QuickOpen.QUICK_OPEN_INPUT, text); + await this.code.waitForSetValue(QuickOpen.QUICK_OPEN_INPUT, text); await this.code.dispatchKeybinding('enter'); await this.waitForQuickOpenClosed(); } diff --git a/test/smoke/src/areas/search/search.ts b/test/smoke/src/areas/search/search.ts index 8c3514ae1f35fb2eb90269898aa7a539a180933c..632707e1bf943f99a59eec982f81b2edf13a5a4d 100644 --- a/test/smoke/src/areas/search/search.ts +++ b/test/smoke/src/areas/search/search.ts @@ -25,7 +25,7 @@ export class Search extends Viewlet { async searchFor(text: string): Promise { await this.code.waitAndClick(INPUT); await this.code.waitForActiveElement(INPUT); - await this.code.setValue(INPUT, text); + await this.code.waitForSetValue(INPUT, text); await this.submitSearch(); } @@ -40,23 +40,15 @@ export class Search extends Viewlet { async setFilesToIncludeText(text: string): Promise { await this.code.waitAndClick(INCLUDE_INPUT); await this.code.waitForActiveElement(INCLUDE_INPUT); - await this.code.setValue(INCLUDE_INPUT, text || ''); + await this.code.waitForSetValue(INCLUDE_INPUT, text || ''); } async showQueryDetails(): Promise { - if (!await this.areDetailsVisible()) { - await this.code.waitAndClick(`${VIEWLET} .query-details .more`); - } + await this.code.waitAndClick(`${VIEWLET} .query-details .more`); } async hideQueryDetails(): Promise { - if (await this.areDetailsVisible()) { - await this.code.waitAndClick(`${VIEWLET} .query-details.more .more`); - } - } - - areDetailsVisible(): Promise { - return this.code.doesElementExist(`${VIEWLET} .query-details.more`); + await this.code.waitAndClick(`${VIEWLET} .query-details.more .more`); } async removeFileMatch(index: number): Promise { @@ -73,7 +65,7 @@ export class Search extends Viewlet { async setReplaceText(text: string): Promise { await this.code.waitAndClick(`${VIEWLET} .search-widget .replace-container .monaco-inputbox input[title="Replace"]`); await this.code.waitForElement(`${VIEWLET} .search-widget .replace-container .monaco-inputbox.synthetic-focus input[title="Replace"]`); - await this.code.setValue(`${VIEWLET} .search-widget .replace-container .monaco-inputbox.synthetic-focus input[title="Replace"]`, text); + await this.code.waitForSetValue(`${VIEWLET} .search-widget .replace-container .monaco-inputbox.synthetic-focus input[title="Replace"]`, text); } async replaceFileMatch(index: number): Promise { diff --git a/test/smoke/src/areas/workbench/data-migration.test.ts b/test/smoke/src/areas/workbench/data-migration.test.ts index 8fa282fd06133f5ba19accc6a33bedf26988a1d1..f4084ca624bebf4a6e0964cadff38f2eca3e8e72 100644 --- a/test/smoke/src/areas/workbench/data-migration.test.ts +++ b/test/smoke/src/areas/workbench/data-migration.test.ts @@ -13,98 +13,99 @@ export interface ICreateAppFn { export function setup(userDataDir: string, createApp: ICreateAppFn) { describe('Data Migration', () => { + afterEach(async function () { await new Promise((c, e) => rimraf(userDataDir, { maxBusyTries: 10 }, err => err ? e(err) : c())); }); - it('checks if the Untitled file is restored migrating from stable to latest', async function () { - const stableApp = createApp(Quality.Stable); + // it('checks if the Untitled file is restored migrating from stable to latest', async function () { + // const stableApp = createApp(Quality.Stable); - if (!stableApp) { - this.skip(); - return; - } + // if (!stableApp) { + // this.skip(); + // return; + // } - await stableApp.start(); + // await stableApp.start(); - const textToType = 'Very dirty file'; + // const textToType = 'Very dirty file'; - await stableApp.workbench.editors.newUntitledFile(); - await stableApp.workbench.editor.waitForTypeInEditor('Untitled-1', textToType); + // await stableApp.workbench.editors.newUntitledFile(); + // await stableApp.workbench.editor.waitForTypeInEditor('Untitled-1', textToType); - await stableApp.stop(); - await new Promise(c => setTimeout(c, 500)); // wait until all resources are released (e.g. locked local storage) + // await stableApp.stop(); + // await new Promise(c => setTimeout(c, 500)); // wait until all resources are released (e.g. locked local storage) - // Checking latest version for the restored state - const app = createApp(Quality.Insiders); + // // Checking latest version for the restored state + // const app = createApp(Quality.Insiders); - await app.start(false); + // await app.start(false); - await app.workbench.editors.waitForActiveTab('Untitled-1', true); - await app.workbench.editor.waitForEditorContents('Untitled-1', c => c.indexOf(textToType) > -1); + // await app.workbench.editors.waitForActiveTab('Untitled-1', true); + // await app.workbench.editor.waitForEditorContents('Untitled-1', c => c.indexOf(textToType) > -1); - await app.stop(); - }); + // await app.stop(); + // }); - it('checks if the newly created dirty file is restored migrating from stable to latest', async function () { - const stableApp = createApp(Quality.Stable); + // it('checks if the newly created dirty file is restored migrating from stable to latest', async function () { + // const stableApp = createApp(Quality.Stable); - if (!stableApp) { - this.skip(); - return; - } + // if (!stableApp) { + // this.skip(); + // return; + // } - await stableApp.start(); + // await stableApp.start(); - const fileName = 'app.js'; - const textPart = 'This is going to be an unsaved file'; + // const fileName = 'app.js'; + // const textPart = 'This is going to be an unsaved file'; - await stableApp.workbench.quickopen.openFile(fileName); + // await stableApp.workbench.quickopen.openFile(fileName); - await stableApp.workbench.editor.waitForTypeInEditor(fileName, textPart); + // await stableApp.workbench.editor.waitForTypeInEditor(fileName, textPart); - await stableApp.stop(); - await new Promise(c => setTimeout(c, 500)); // wait until all resources are released (e.g. locked local storage) + // await stableApp.stop(); + // await new Promise(c => setTimeout(c, 500)); // wait until all resources are released (e.g. locked local storage) - // Checking latest version for the restored state - const app = createApp(Quality.Insiders); + // // Checking latest version for the restored state + // const app = createApp(Quality.Insiders); - await app.start(false); + // await app.start(false); - await app.workbench.editors.waitForActiveTab(fileName); - await app.workbench.editor.waitForEditorContents(fileName, c => c.indexOf(textPart) > -1); + // await app.workbench.editors.waitForActiveTab(fileName); + // await app.workbench.editor.waitForEditorContents(fileName, c => c.indexOf(textPart) > -1); - await app.stop(); - }); + // await app.stop(); + // }); - it('checks if opened tabs are restored migrating from stable to latest', async function () { - const stableApp = createApp(Quality.Stable); + // it('checks if opened tabs are restored migrating from stable to latest', async function () { + // const stableApp = createApp(Quality.Stable); - if (!stableApp) { - this.skip(); - return; - } + // if (!stableApp) { + // this.skip(); + // return; + // } - await stableApp.start(); + // await stableApp.start(); - const fileName1 = 'app.js', fileName2 = 'jsconfig.json', fileName3 = 'readme.md'; + // const fileName1 = 'app.js', fileName2 = 'jsconfig.json', fileName3 = 'readme.md'; - await stableApp.workbench.quickopen.openFile(fileName1); - await stableApp.workbench.runCommand('View: Keep Editor'); - await stableApp.workbench.quickopen.openFile(fileName2); - await stableApp.workbench.runCommand('View: Keep Editor'); - await stableApp.workbench.quickopen.openFile(fileName3); - await stableApp.stop(); + // await stableApp.workbench.quickopen.openFile(fileName1); + // await stableApp.workbench.runCommand('View: Keep Editor'); + // await stableApp.workbench.quickopen.openFile(fileName2); + // await stableApp.workbench.runCommand('View: Keep Editor'); + // await stableApp.workbench.quickopen.openFile(fileName3); + // await stableApp.stop(); - const app = createApp(Quality.Insiders); + // const app = createApp(Quality.Insiders); - await app.start(false); + // await app.start(false); - await app.workbench.editors.waitForTab(fileName1); - await app.workbench.editors.waitForTab(fileName2); - await app.workbench.editors.waitForTab(fileName3); + // await app.workbench.editors.waitForTab(fileName1); + // await app.workbench.editors.waitForTab(fileName2); + // await app.workbench.editors.waitForTab(fileName3); - await app.stop(); - }); + // await app.stop(); + // }); }); } \ No newline at end of file diff --git a/test/smoke/src/vscode/code.ts b/test/smoke/src/vscode/code.ts index 2821a060e7b70de0ebee9016df525ea3c4671e2d..2563850858995f5f0e7fda6ab1a833eaffc6cc3d 100644 --- a/test/smoke/src/vscode/code.ts +++ b/test/smoke/src/vscode/code.ts @@ -132,146 +132,87 @@ export async function spawn(options: SpawnOptions): Promise { export class Code { private _activeWindowId: number | undefined = undefined; + private driver: IDriver; constructor( private process: cp.ChildProcess, private client: IDisposable, - private driver: IDriver, - private verbose: boolean - ) { } - - async dispatchKeybinding(keybinding: string): Promise { - if (this.verbose) { - console.log('- dispatchKeybinding:', keybinding); + driver: IDriver, + verbose: boolean + ) { + if (verbose) { + this.driver = new Proxy(driver, { + get(target, prop, receiver) { + if (typeof target[prop] !== 'function') { + return target[prop]; + } + + return function (...args) { + console.log('** ', prop, ...args.filter(a => typeof a === 'string')); + return target[prop].apply(this, args); + }; + } + }); + } else { + this.driver = driver; } + } + async dispatchKeybinding(keybinding: string): Promise { const windowId = await this.getActiveWindowId(); await this.driver.dispatchKeybinding(windowId, keybinding); } async waitForTextContent(selector: string, textContent?: string, accept?: (result: string) => boolean): Promise { - if (this.verbose) { - console.log('- waitForTextContent:', selector); - } - const windowId = await this.getActiveWindowId(); accept = accept || (result => textContent !== void 0 ? textContent === result : !!result); - return await this.waitFor(() => this.driver.getElements(windowId, selector).then(els => els[0].textContent), s => accept!(typeof s === 'string' ? s : ''), `getTextContent with selector ${selector}`); + return await this.poll(() => this.driver.getElements(windowId, selector).then(els => els[0].textContent), s => accept!(typeof s === 'string' ? s : ''), `getTextContent with selector ${selector}`); } async waitAndClick(selector: string, xoffset?: number, yoffset?: number): Promise { - if (this.verbose) { - console.log('- waitAndClick:', selector); - } - const windowId = await this.getActiveWindowId(); - - // TODO should waitForClick - await this.waitForElement(selector); - await this.driver.click(windowId, selector, xoffset, yoffset); + await this.poll(() => this.driver.click(windowId, selector, xoffset, yoffset), () => true); } async waitAndDoubleClick(selector: string): Promise { - if (this.verbose) { - console.log('- waitAndDoubleClick:', selector); - } - const windowId = await this.getActiveWindowId(); - - // TODO should waitForDoubleClick - await this.waitForElement(selector); - await this.driver.doubleClick(windowId, selector); + await this.poll(() => this.driver.doubleClick(windowId, selector), () => true); } async waitAndMove(selector: string): Promise { - if (this.verbose) { - console.log('- waitAndMove:', selector); - } - const windowId = await this.getActiveWindowId(); - // TODO should waitForMove - await this.waitForElement(selector); - await this.driver.move(windowId, selector); + await this.poll(() => this.driver.move(windowId, selector), () => true); } - // TODO should be waitForSetValue - async setValue(selector: string, text: string): Promise { - if (this.verbose) { - console.log('- setValue:', selector); - } - + async waitForSetValue(selector: string, value: string): Promise { const windowId = await this.getActiveWindowId(); - // TODO should waitForSetValue - await this.waitForElement(selector); - await this.driver.setValue(windowId, selector, text); - } - - // TODO merge with getElements - async doesElementExist(selector: string): Promise { - if (this.verbose) { - console.log('- doesElementExist:', selector); - } - - const windowId = await this.getActiveWindowId(); - const elements = await this.driver.getElements(windowId, selector); - return elements.length > 0; - } - - // TODO merge with getElements - async getElementCount(selector: string): Promise { - if (this.verbose) { - console.log('- getElementCount:', selector); - } - - const windowId = await this.getActiveWindowId(); - const elements = await this.driver.getElements(windowId, selector); - return elements.length; + await this.poll(() => this.driver.setValue(windowId, selector, value), () => true); } async waitForElements(selector: string, recursive: boolean, accept: (result: IElement[]) => boolean = result => result.length > 0): Promise { - if (this.verbose) { - console.log('- waitForElements:', selector); - } - const windowId = await this.getActiveWindowId(); - return await this.waitFor(() => this.driver.getElements(windowId, selector, recursive), accept, `elements with selector ${selector}`); + return await this.poll(() => this.driver.getElements(windowId, selector, recursive), accept, `elements with selector ${selector}`); } async waitForElement(selector: string, accept: (result: IElement | undefined) => boolean = result => !!result): Promise { - if (this.verbose) { - console.log('- waitForElement:', selector); - } - const windowId = await this.getActiveWindowId(); - return await this.waitFor(() => this.driver.getElements(windowId, selector).then(els => els[0]), accept, `element with selector ${selector}`); + return await this.poll(() => this.driver.getElements(windowId, selector).then(els => els[0]), accept, `element with selector ${selector}`); } async waitForActiveElement(selector: string): Promise { - if (this.verbose) { - console.log('- waitForActiveElement:', selector); - } - const windowId = await this.getActiveWindowId(); - await this.waitFor(() => this.driver.isActiveElement(windowId, selector), undefined, `wait for active element: ${selector}`); + await this.poll(() => this.driver.isActiveElement(windowId, selector), undefined, `wait for active element: ${selector}`); } async waitForTitle(fn: (title: string) => boolean): Promise { - if (this.verbose) { - console.log('- getTitle'); - } - const windowId = await this.getActiveWindowId(); - await this.waitFor(() => this.driver.getTitle(windowId), fn, 'wait for title: ${}'); + await this.poll(() => this.driver.getTitle(windowId), fn, 'wait for title: ${}'); } // TODO make into waitForTypeInEditor - async typeInEditor(selector: string, text: string): Promise { - if (this.verbose) { - console.log('- typeInEditor', selector, text); - } - + async waitForTypeInEditor(selector: string, text: string): Promise { const windowId = await this.getActiveWindowId(); - await this.driver.typeInEditor(windowId, selector, text); + await this.poll(() => this.driver.typeInEditor(windowId, selector, text), () => true, 'wait for title: ${}'); } // waitFor calls should not take more than 200 * 100 = 20 seconds to complete, excluding @@ -280,8 +221,9 @@ export class Code { private readonly retryDuration = 100; // in milliseconds // TODO: clean function interface - private async waitFor(func: () => T | Promise, accept?: (result: T) => boolean | Promise, timeoutMessage?: string, retryCount?: number): Promise; - private async waitFor(func: () => T | Promise, accept: (result: T) => boolean | Promise = result => !!result, timeoutMessage?: string, retryCount?: number): Promise { + // TODO: if accept function is missing, just dont use one, rely on exceptions + private async poll(func: () => T | Promise, accept?: (result: T) => boolean | Promise, timeoutMessage?: string, retryCount?: number): Promise; + private async poll(func: () => T | Promise, accept: (result: T) => boolean | Promise = result => !!result, timeoutMessage?: string, retryCount?: number): Promise { let trial = 1; retryCount = typeof retryCount === 'number' ? retryCount : this.retryCount; @@ -293,6 +235,10 @@ export class Code { let result; try { result = await func(); + + if (accept(result)) { + return result; + } } catch (e) { // console.warn(e); @@ -301,10 +247,6 @@ export class Code { } } - if (accept(result)) { - return result; - } - await new Promise(resolve => setTimeout(resolve, this.retryDuration)); trial++; }