提交 3df5480a 编写于 作者: J Joao Moreno

green tests, more cleanup

上级 68e36ecb
......@@ -122,7 +122,7 @@ export class Debug extends Viewlet {
async waitForReplCommand(text: string, accept: (result: string) => boolean): Promise<void> {
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);
......
......@@ -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<any> {
const selector = [selectorPrefix || '', `${EDITOR(filename)} .view-lines`].join(' ');
return this.code.waitForTextContent(selector, undefined, c => accept(c.replace(/\u00a0/g, ' ')));
}
......
......@@ -27,7 +27,7 @@ export class Extensions extends Viewlet {
async searchForExtension(name: string): Promise<any> {
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<void> {
......
......@@ -78,7 +78,7 @@ export class SCM extends Viewlet {
async commit(message: string): Promise<void> {
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
......@@ -15,7 +15,7 @@ export class KeybindingsEditor {
async updateKeybinding(command: string, keybinding: string, ariaLabel: string): Promise<any> {
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');
......
......@@ -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
......@@ -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<any> {
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<any> {
if (await this.isVisible()) {
await this.commands.runCommand('workbench.actions.view.problems');
await this.code.waitForElement(Problems.PROBLEMS_VIEW_SELECTOR, el => !el);
}
}
isVisible(): Promise<boolean> {
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<void> {
......
......@@ -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<void> {
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();
}
......
......@@ -25,7 +25,7 @@ export class Search extends Viewlet {
async searchFor(text: string): Promise<void> {
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<void> {
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<void> {
if (!await this.areDetailsVisible()) {
await this.code.waitAndClick(`${VIEWLET} .query-details .more`);
}
await this.code.waitAndClick(`${VIEWLET} .query-details .more`);
}
async hideQueryDetails(): Promise<void> {
if (await this.areDetailsVisible()) {
await this.code.waitAndClick(`${VIEWLET} .query-details.more .more`);
}
}
areDetailsVisible(): Promise<boolean> {
return this.code.doesElementExist(`${VIEWLET} .query-details.more`);
await this.code.waitAndClick(`${VIEWLET} .query-details.more .more`);
}
async removeFileMatch(index: number): Promise<void> {
......@@ -73,7 +65,7 @@ export class Search extends Viewlet {
async setReplaceText(text: string): Promise<void> {
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<void> {
......
......@@ -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
......@@ -132,146 +132,87 @@ export async function spawn(options: SpawnOptions): Promise<Code> {
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<void> {
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<void> {
const windowId = await this.getActiveWindowId();
await this.driver.dispatchKeybinding(windowId, keybinding);
}
async waitForTextContent(selector: string, textContent?: string, accept?: (result: string) => boolean): Promise<string> {
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<void> {
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<void> {
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<void> {
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<void> {
if (this.verbose) {
console.log('- setValue:', selector);
}
async waitForSetValue(selector: string, value: string): Promise<void> {
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<boolean> {
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<number> {
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<IElement[]> {
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<IElement> {
if (this.verbose) {
console.log('- waitForElement:', selector);
}
const windowId = await this.getActiveWindowId();
return await this.waitFor<IElement>(() => this.driver.getElements(windowId, selector).then(els => els[0]), accept, `element with selector ${selector}`);
return await this.poll<IElement>(() => this.driver.getElements(windowId, selector).then(els => els[0]), accept, `element with selector ${selector}`);
}
async waitForActiveElement(selector: string): Promise<void> {
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<void> {
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<void> {
if (this.verbose) {
console.log('- typeInEditor', selector, text);
}
async waitForTypeInEditor(selector: string, text: string): Promise<void> {
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<T>(func: () => T | Promise<T | undefined>, accept?: (result: T) => boolean | Promise<boolean>, timeoutMessage?: string, retryCount?: number): Promise<T>;
private async waitFor<T>(func: () => T | Promise<T>, accept: (result: T) => boolean | Promise<boolean> = result => !!result, timeoutMessage?: string, retryCount?: number): Promise<T> {
// TODO: if accept function is missing, just dont use one, rely on exceptions
private async poll<T>(func: () => T | Promise<T | undefined>, accept?: (result: T) => boolean | Promise<boolean>, timeoutMessage?: string, retryCount?: number): Promise<T>;
private async poll<T>(func: () => T | Promise<T>, accept: (result: T) => boolean | Promise<boolean> = result => !!result, timeoutMessage?: string, retryCount?: number): Promise<T> {
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++;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册