Skip to content

Commit b69589c

Browse files
authored
Smoke test failure - changing selectors depending on app quality (microsoft#234181)
* changing selector depending on app quality smoke test * using correct selector * resetting to just insiders * focusing if not focused after event * removing dom node focus
1 parent 9a6ef1f commit b69589c

File tree

11 files changed

+85
-41
lines changed

11 files changed

+85
-41
lines changed

src/typings/editContext.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ interface EditContextEventHandlersEventMap {
5858

5959
type EventHandler<TEvent extends Event = Event> = (event: TEvent) => void;
6060

61-
interface TextUpdateEvent extends Event {
62-
new(type: DOMString, options?: TextUpdateEventInit): TextUpdateEvent;
61+
declare class TextUpdateEvent extends Event {
62+
constructor(type: DOMString, options?: TextUpdateEventInit);
6363

6464
readonly updateRangeStart: number;
6565
readonly updateRangeEnd: number;

src/vs/editor/common/config/editorOptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5750,7 +5750,7 @@ export const EditorOptions = {
57505750
emptySelectionClipboard: register(new EditorEmptySelectionClipboard()),
57515751
dropIntoEditor: register(new EditorDropIntoEditor()),
57525752
experimentalEditContextEnabled: register(new EditorBooleanOption(
5753-
EditorOption.experimentalEditContextEnabled, 'experimentalEditContextEnabled', false,
5753+
EditorOption.experimentalEditContextEnabled, 'experimentalEditContextEnabled', product.quality !== 'stable',
57545754
{
57555755
description: nls.localize('experimentalEditContextEnabled', "Sets whether the new experimental edit context should be used instead of the text area."),
57565756
included: platform.isChrome || platform.isEdge || platform.isNative

src/vs/workbench/services/driver/browser/driver.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { getClientArea, getTopLeftOffset } from '../../../../base/browser/dom.js';
6+
import { getClientArea, getTopLeftOffset, isHTMLDivElement, isHTMLTextAreaElement } from '../../../../base/browser/dom.js';
77
import { mainWindow } from '../../../../base/browser/window.js';
88
import { coalesce } from '../../../../base/common/arrays.js';
99
import { language, locale } from '../../../../base/common/platform.js';
@@ -133,18 +133,36 @@ export class BrowserWindowDriver implements IWindowDriver {
133133
if (!element) {
134134
throw new Error(`Editor not found: ${selector}`);
135135
}
136-
137-
const textarea = element as HTMLTextAreaElement;
138-
const start = textarea.selectionStart;
139-
const newStart = start + text.length;
140-
const value = textarea.value;
141-
const newValue = value.substr(0, start) + text + value.substr(start);
142-
143-
textarea.value = newValue;
144-
textarea.setSelectionRange(newStart, newStart);
145-
146-
const event = new Event('input', { 'bubbles': true, 'cancelable': true });
147-
textarea.dispatchEvent(event);
136+
if (isHTMLDivElement(element)) {
137+
// Edit context is enabled
138+
const editContext = element.editContext;
139+
if (!editContext) {
140+
throw new Error(`Edit context not found: ${selector}`);
141+
}
142+
const selectionStart = editContext.selectionStart;
143+
const selectionEnd = editContext.selectionEnd;
144+
const event = new TextUpdateEvent('textupdate', {
145+
updateRangeStart: selectionStart,
146+
updateRangeEnd: selectionEnd,
147+
text,
148+
selectionStart: selectionStart + text.length,
149+
selectionEnd: selectionStart + text.length,
150+
compositionStart: 0,
151+
compositionEnd: 0
152+
});
153+
editContext.dispatchEvent(event);
154+
} else if (isHTMLTextAreaElement(element)) {
155+
const start = element.selectionStart;
156+
const newStart = start + text.length;
157+
const value = element.value;
158+
const newValue = value.substr(0, start) + text + value.substr(start);
159+
160+
element.value = newValue;
161+
element.setSelectionRange(newStart, newStart);
162+
163+
const event = new Event('input', { 'bubbles': true, 'cancelable': true });
164+
element.dispatchEvent(event);
165+
}
148166
}
149167

150168
async getTerminalBuffer(selector: string): Promise<string[]> {

test/automation/src/code.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { launch as launchPlaywrightBrowser } from './playwrightBrowser';
1212
import { PlaywrightDriver } from './playwrightDriver';
1313
import { launch as launchPlaywrightElectron } from './playwrightElectron';
1414
import { teardown } from './processes';
15+
import { Quality } from './application';
1516

1617
export interface LaunchOptions {
1718
codePath?: string;
@@ -28,6 +29,7 @@ export interface LaunchOptions {
2829
readonly tracing?: boolean;
2930
readonly headless?: boolean;
3031
readonly browser?: 'chromium' | 'webkit' | 'firefox';
32+
readonly quality: Quality;
3133
}
3234

3335
interface ICodeInstance {
@@ -77,15 +79,15 @@ export async function launch(options: LaunchOptions): Promise<Code> {
7779
const { serverProcess, driver } = await measureAndLog(() => launchPlaywrightBrowser(options), 'launch playwright (browser)', options.logger);
7880
registerInstance(serverProcess, options.logger, 'server');
7981

80-
return new Code(driver, options.logger, serverProcess);
82+
return new Code(driver, options.logger, serverProcess, options.quality);
8183
}
8284

8385
// Electron smoke tests (playwright)
8486
else {
8587
const { electronProcess, driver } = await measureAndLog(() => launchPlaywrightElectron(options), 'launch playwright (electron)', options.logger);
8688
registerInstance(electronProcess, options.logger, 'electron');
8789

88-
return new Code(driver, options.logger, electronProcess);
90+
return new Code(driver, options.logger, electronProcess, options.quality);
8991
}
9092
}
9193

@@ -96,7 +98,8 @@ export class Code {
9698
constructor(
9799
driver: PlaywrightDriver,
98100
readonly logger: Logger,
99-
private readonly mainProcess: cp.ChildProcess
101+
private readonly mainProcess: cp.ChildProcess,
102+
readonly quality: Quality
100103
) {
101104
this.driver = new Proxy(driver, {
102105
get(target, prop) {

test/automation/src/debug.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Code, findElement } from './code';
99
import { Editors } from './editors';
1010
import { Editor } from './editor';
1111
import { IElement } from './driver';
12+
import { Quality } from './application';
1213

1314
const VIEWLET = 'div[id="workbench.view.debug"]';
1415
const DEBUG_VIEW = `${VIEWLET}`;
@@ -31,7 +32,8 @@ const CONSOLE_OUTPUT = `.repl .output.expression .value`;
3132
const CONSOLE_EVALUATION_RESULT = `.repl .evaluation-result.expression .value`;
3233
const CONSOLE_LINK = `.repl .value a.link`;
3334

34-
const REPL_FOCUSED = '.repl-input-wrapper .monaco-editor textarea';
35+
const REPL_FOCUSED_NATIVE_EDIT_CONTEXT = '.repl-input-wrapper .monaco-editor .native-edit-context';
36+
const REPL_FOCUSED_TEXTAREA = '.repl-input-wrapper .monaco-editor textarea';
3537

3638
export interface IStackFrame {
3739
name: string;
@@ -127,8 +129,9 @@ export class Debug extends Viewlet {
127129

128130
async waitForReplCommand(text: string, accept: (result: string) => boolean): Promise<void> {
129131
await this.commands.runCommand('Debug: Focus on Debug Console View');
130-
await this.code.waitForActiveElement(REPL_FOCUSED);
131-
await this.code.waitForSetValue(REPL_FOCUSED, text);
132+
const selector = this.code.quality === Quality.Stable ? REPL_FOCUSED_TEXTAREA : REPL_FOCUSED_NATIVE_EDIT_CONTEXT;
133+
await this.code.waitForActiveElement(selector);
134+
await this.code.waitForSetValue(selector, text);
132135

133136
// Wait for the keys to be picked up by the editor model such that repl evaluates what just got typed
134137
await this.editor.waitForEditorContents('debug:replinput', s => s.indexOf(text) >= 0);

test/automation/src/editor.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import { References } from './peek';
77
import { Commands } from './workbench';
88
import { Code } from './code';
9+
import { Quality } from './application';
910

1011
const RENAME_BOX = '.monaco-editor .monaco-editor.rename-box';
1112
const RENAME_INPUT = `${RENAME_BOX} .rename-input`;
@@ -78,10 +79,10 @@ export class Editor {
7879
async waitForEditorFocus(filename: string, lineNumber: number, selectorPrefix = ''): Promise<void> {
7980
const editor = [selectorPrefix || '', EDITOR(filename)].join(' ');
8081
const line = `${editor} .view-lines > .view-line:nth-child(${lineNumber})`;
81-
const textarea = `${editor} textarea`;
82+
const editContext = `${editor} ${this._editContextSelector()}`;
8283

8384
await this.code.waitAndClick(line, 1, 1);
84-
await this.code.waitForActiveElement(textarea);
85+
await this.code.waitForActiveElement(editContext);
8586
}
8687

8788
async waitForTypeInEditor(filename: string, text: string, selectorPrefix = ''): Promise<any> {
@@ -92,14 +93,18 @@ export class Editor {
9293

9394
await this.code.waitForElement(editor);
9495

95-
const textarea = `${editor} textarea`;
96-
await this.code.waitForActiveElement(textarea);
96+
const editContext = `${editor} ${this._editContextSelector()}`;
97+
await this.code.waitForActiveElement(editContext);
9798

98-
await this.code.waitForTypeInEditor(textarea, text);
99+
await this.code.waitForTypeInEditor(editContext, text);
99100

100101
await this.waitForEditorContents(filename, c => c.indexOf(text) > -1, selectorPrefix);
101102
}
102103

104+
private _editContextSelector() {
105+
return this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context';
106+
}
107+
103108
async waitForEditorContents(filename: string, accept: (contents: string) => boolean, selectorPrefix = ''): Promise<any> {
104109
const selector = [selectorPrefix || '', `${EDITOR(filename)} .view-lines`].join(' ');
105110
return this.code.waitForTextContent(selector, undefined, c => accept(c.replace(/\u00a0/g, ' ')));

test/automation/src/editors.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { Quality } from './application';
67
import { Code } from './code';
78

89
export class Editors {
@@ -53,7 +54,7 @@ export class Editors {
5354
}
5455

5556
async waitForActiveEditor(fileName: string, retryCount?: number): Promise<any> {
56-
const selector = `.editor-instance .monaco-editor[data-uri$="${fileName}"] textarea`;
57+
const selector = `.editor-instance .monaco-editor[data-uri$="${fileName}"] ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`;
5758
return this.code.waitForActiveElement(selector, retryCount);
5859
}
5960

test/automation/src/extensions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Code } from './code';
88
import { ncp } from 'ncp';
99
import { promisify } from 'util';
1010
import { Commands } from './workbench';
11+
import { Quality } from './application';
1112
import path = require('path');
1213
import fs = require('fs');
1314

@@ -20,7 +21,7 @@ export class Extensions extends Viewlet {
2021

2122
async searchForExtension(id: string): Promise<any> {
2223
await this.commands.runCommand('Extensions: Focus on Extensions View', { exactLabelMatch: true });
23-
await this.code.waitForTypeInEditor('div.extensions-viewlet[id="workbench.view.extensions"] .monaco-editor textarea', `@id:${id}`);
24+
await this.code.waitForTypeInEditor(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-editor ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`, `@id:${id}`);
2425
await this.code.waitForTextContent(`div.part.sidebar div.composite.title h2`, 'Extensions: Marketplace');
2526

2627
let retrials = 1;

test/automation/src/notebook.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { Quality } from './application';
67
import { Code } from './code';
78
import { QuickAccess } from './quickaccess';
89
import { QuickInput } from './quickinput';
@@ -46,10 +47,10 @@ export class Notebook {
4647

4748
await this.code.waitForElement(editor);
4849

49-
const textarea = `${editor} textarea`;
50-
await this.code.waitForActiveElement(textarea);
50+
const editContext = `${editor} ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`;
51+
await this.code.waitForActiveElement(editContext);
5152

52-
await this.code.waitForTypeInEditor(textarea, text);
53+
await this.code.waitForTypeInEditor(editContext, text);
5354

5455
await this._waitForActiveCellEditorContents(c => c.indexOf(text) > -1);
5556
}

test/automation/src/scm.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
import { Viewlet } from './viewlet';
77
import { IElement } from './driver';
88
import { findElement, findElements, Code } from './code';
9+
import { Quality } from './application';
910

1011
const VIEWLET = 'div[id="workbench.view.scm"]';
11-
const SCM_INPUT = `${VIEWLET} .scm-editor textarea`;
12+
const SCM_INPUT_NATIVE_EDIT_CONTEXT = `${VIEWLET} .scm-editor .native-edit-context`;
13+
const SCM_INPUT_TEXTAREA = `${VIEWLET} .scm-editor textarea`;
1214
const SCM_RESOURCE = `${VIEWLET} .monaco-list-row .resource`;
1315
const REFRESH_COMMAND = `div[id="workbench.parts.sidebar"] .actions-container a.action-label[aria-label="Refresh"]`;
1416
const COMMIT_COMMAND = `div[id="workbench.parts.sidebar"] .actions-container a.action-label[aria-label="Commit"]`;
@@ -44,7 +46,7 @@ export class SCM extends Viewlet {
4446

4547
async openSCMViewlet(): Promise<any> {
4648
await this.code.dispatchKeybinding('ctrl+shift+g');
47-
await this.code.waitForElement(SCM_INPUT);
49+
await this.code.waitForElement(this._editContextSelector());
4850
}
4951

5052
async waitForChange(name: string, type?: string): Promise<void> {
@@ -71,9 +73,13 @@ export class SCM extends Viewlet {
7173
}
7274

7375
async commit(message: string): Promise<void> {
74-
await this.code.waitAndClick(SCM_INPUT);
75-
await this.code.waitForActiveElement(SCM_INPUT);
76-
await this.code.waitForSetValue(SCM_INPUT, message);
76+
await this.code.waitAndClick(this._editContextSelector());
77+
await this.code.waitForActiveElement(this._editContextSelector());
78+
await this.code.waitForSetValue(this._editContextSelector(), message);
7779
await this.code.waitAndClick(COMMIT_COMMAND);
7880
}
81+
82+
private _editContextSelector(): string {
83+
return this.code.quality === Quality.Stable ? SCM_INPUT_TEXTAREA : SCM_INPUT_NATIVE_EDIT_CONTEXT;
84+
}
7985
}

0 commit comments

Comments
 (0)