Files
azuredatastudio/test/smoke/src/areas/editor/editor.ts
Karl Burtram 251ae01c3e Initial VS Code 1.19 source merge (#571)
* Initial 1.19 xcopy

* Fix yarn build

* Fix numerous build breaks

* Next batch of build break fixes

* More build break fixes

* Runtime breaks

* Additional post merge fixes

* Fix windows setup file

* Fix test failures.

* Update license header blocks to refer to source eula
2018-01-28 23:37:17 -08:00

194 lines
7.9 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SpectronApplication } from '../../spectron/application';
import { QuickOutline } from './quickoutline';
import { References } from './peek';
const RENAME_BOX = '.monaco-editor .monaco-editor.rename-box';
const RENAME_INPUT = `${RENAME_BOX} .rename-input`;
export class Editor {
private static readonly VIEW_LINES = '.monaco-editor .view-lines';
private static readonly LINE_NUMBERS = '.monaco-editor .margin .margin-view-overlays .line-numbers';
private static readonly FOLDING_EXPANDED = '.monaco-editor .margin .margin-view-overlays>:nth-child(${INDEX}) .folding';
private static readonly FOLDING_COLLAPSED = `${Editor.FOLDING_EXPANDED}.collapsed`;
constructor(private spectron: SpectronApplication) {
}
async openOutline(): Promise<QuickOutline> {
const outline = new QuickOutline(this.spectron);
await outline.open();
return outline;
}
async findReferences(term: string, line: number): Promise<References> {
await this.clickOnTerm(term, line);
await this.spectron.workbench.quickopen.runCommand('Find All References');
const references = new References(this.spectron);
await references.waitUntilOpen();
return references;
}
async rename(filename: string, line: number, from: string, to: string): Promise<void> {
await this.clickOnTerm(from, line);
await this.spectron.workbench.quickopen.runCommand('Rename Symbol');
await this.spectron.client.waitForActiveElement(RENAME_INPUT);
await this.spectron.client.setValue(RENAME_INPUT, to);
await this.spectron.client.keys(['Enter', 'NULL']);
}
async gotoDefinition(term: string, line: number): Promise<void> {
await this.clickOnTerm(term, line);
await this.spectron.workbench.quickopen.runCommand('Go to Definition');
}
async peekDefinition(term: string, line: number): Promise<References> {
await this.clickOnTerm(term, line);
await this.spectron.workbench.quickopen.runCommand('Peek Definition');
const peek = new References(this.spectron);
await peek.waitUntilOpen();
return peek;
}
async waitForHighlightingLine(line: number): Promise<void> {
const currentLineIndex = await this.getViewLineIndex(line);
if (currentLineIndex) {
await this.spectron.client.waitForElement(`.monaco-editor .view-overlays>:nth-child(${currentLineIndex}) .current-line`);
return;
}
throw new Error('Cannot find line ' + line);
}
async getSelector(term: string, line: number): Promise<string> {
const lineIndex = await this.getViewLineIndex(line);
const classNames = await this.spectron.client.waitFor(() => this.getClassSelectors(term, lineIndex), classNames => classNames && !!classNames.length, 'Getting class names for editor lines');
return `${Editor.VIEW_LINES}>:nth-child(${lineIndex}) span span.${classNames[0]}`;
}
async foldAtLine(line: number): Promise<any> {
const lineIndex = await this.getViewLineIndex(line);
await this.spectron.client.waitAndClick(Editor.FOLDING_EXPANDED.replace('${INDEX}', '' + lineIndex));
await this.spectron.client.waitForElement(Editor.FOLDING_COLLAPSED.replace('${INDEX}', '' + lineIndex));
}
async unfoldAtLine(line: number): Promise<any> {
const lineIndex = await this.getViewLineIndex(line);
await this.spectron.client.waitAndClick(Editor.FOLDING_COLLAPSED.replace('${INDEX}', '' + lineIndex));
await this.spectron.client.waitForElement(Editor.FOLDING_EXPANDED.replace('${INDEX}', '' + lineIndex));
}
async waitUntilHidden(line: number): Promise<void> {
await this.spectron.client.waitFor<number>(() => this.getViewLineIndexWithoutWait(line), lineNumber => lineNumber === undefined, 'Waiting until line number is hidden');
}
async waitUntilShown(line: number): Promise<void> {
await this.getViewLineIndex(line);
}
async clickOnTerm(term: string, line: number): Promise<void> {
const selector = await this.getSelector(term, line);
await this.spectron.client.waitAndClick(selector);
}
async waitForTypeInEditor(filename: string, text: string, selectorPrefix = ''): Promise<any> {
const editor = [
selectorPrefix || '',
`.monaco-editor[data-uri$="${filename}"]`
].join(' ');
await this.spectron.client.element(editor);
const textarea = `${editor} textarea`;
await this.spectron.client.waitForActiveElement(textarea);
// https://github.com/Microsoft/vscode/issues/34203#issuecomment-334441786
await this.spectron.client.spectron.client.selectorExecute(textarea, (elements, text) => {
const textarea = (Array.isArray(elements) ? elements : [elements])[0] as HTMLTextAreaElement;
const start = textarea.selectionStart;
const newStart = start + text.length;
const value = textarea.value;
const newValue = value.substr(0, start) + text + value.substr(start);
textarea.value = newValue;
textarea.setSelectionRange(newStart, newStart);
const event = new Event('input', { 'bubbles': true, 'cancelable': true });
textarea.dispatchEvent(event);
}, 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 || '',
`.monaco-editor[data-uri$="${filename}"] .view-lines`
].join(' ');
return this.spectron.client.waitForTextContent(selector, undefined, c => accept(c.replace(/\u00a0/g, ' ')));
}
async waitForActiveEditor(filename: string): Promise<any> {
const selector = `.editor-container .monaco-editor[data-uri$="${filename}"] textarea`;
return this.spectron.client.waitForActiveElement(selector);
}
// async waitForActiveEditorFirstLineText(filename: string): Promise<string> {
// const selector = `.editor-container .monaco-editor[data-uri$="${filename}"] textarea`;
// const result = await this.spectron.client.waitFor(
// () => this.spectron.client.spectron.client.execute(s => {
// if (!document.activeElement.matches(s)) {
// return undefined;
// }
// let element: Element | null = document.activeElement;
// while (element && !/monaco-editor/.test(element.className) && element !== document.body) {
// element = element.parentElement;
// }
// if (element && /monaco-editor/.test(element.className)) {
// const firstLine = element.querySelector('.view-lines span span:nth-child(1)');
// if (firstLine) {
// return (firstLine.textContent || '').replace(/\u00a0/g, ' '); // DAMN
// }
// }
// return undefined;
// }, selector),
// r => typeof r.value === 'string',
// `wait for active editor first line: ${selector}`
// );
// return result.value;
// }
private async getClassSelectors(term: string, viewline: number): Promise<string[]> {
const result: { text: string, className: string }[] = await this.spectron.webclient.selectorExecute(`${Editor.VIEW_LINES}>:nth-child(${viewline}) span span`,
elements => (Array.isArray(elements) ? elements : [elements])
.map(element => ({ text: element.textContent, className: element.className })));
return result.filter(r => r.text === term).map(({ className }) => className);
}
private async getViewLineIndex(line: number): Promise<number> {
return await this.spectron.client.waitFor<number>(() => this.getViewLineIndexWithoutWait(line), void 0, 'Getting line index');
}
private async getViewLineIndexWithoutWait(line: number): Promise<number | undefined> {
const lineNumbers = await this.spectron.webclient.selectorExecute(Editor.LINE_NUMBERS,
elements => (Array.isArray(elements) ? elements : [elements]).map(element => element.textContent));
for (let index = 0; index < lineNumbers.length; index++) {
if (lineNumbers[index] === `${line}`) {
return index + 1;
}
}
return undefined;
}
}