diff --git a/src/vs/platform/driver/browser/baseDriver.ts b/src/vs/platform/driver/browser/baseDriver.ts index 832ee351654..40e5e2227ab 100644 --- a/src/vs/platform/driver/browser/baseDriver.ts +++ b/src/vs/platform/driver/browser/baseDriver.ts @@ -57,7 +57,6 @@ export abstract class BaseWindowDriver implements IWindowDriver { async getElements(selector: string, recursive: boolean): Promise { const query = document.querySelectorAll(selector); const result: IElement[] = []; - for (let i = 0; i < query.length; i++) { const element = query.item(i); result.push(this.serializeElement(element, recursive)); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 8d73e0fff9d..8f64411583d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -687,6 +687,7 @@ export class TerminalService implements ITerminalService { } if (source.target !== TerminalLocation.Editor) { + await this._terminalGroupService.showPanel(true); return; } source.target = TerminalLocation.Panel; diff --git a/test/automation/src/terminal.ts b/test/automation/src/terminal.ts index 42afbd78bf7..03ec6d53937 100644 --- a/test/automation/src/terminal.ts +++ b/test/automation/src/terminal.ts @@ -3,90 +3,153 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IElement, QuickInput } from '.'; +import { QuickInput } from '.'; import { Code } from './code'; import { QuickAccess } from './quickaccess'; -const TERMINAL_VIEW_SELECTOR = `#terminal`; -const XTERM_SELECTOR = `${TERMINAL_VIEW_SELECTOR} .terminal-wrapper`; -const CONTRIBUTED_PROFILE_NAME = `JavaScript Debug Terminal`; -const TABS = '.tabs-list .terminal-tabs-entry'; -const XTERM_FOCUSED_SELECTOR = '.terminal.xterm.focus'; +export enum Selector { + TerminalView = `#terminal`, + Xterm = `#terminal .terminal-wrapper`, + TabsEntry = '.terminal-tabs-entry', + XtermFocused = '.terminal.xterm.focus', + PlusButton = '.codicon-plus', + EditorGroups = '.editor .split-view-view', + EditorTab = '.terminal-tab', + EditorTabIcon = '.terminal-tab.codicon-', + SingleTab = '.single-terminal-tab', + Tabs = '.tabs-list .monaco-list-row', + SplitButton = '.editor .codicon-split-horizontal' +} -const enum TerminalCommandId { +export enum TerminalCommandIdWithValue { Rename = 'workbench.action.terminal.rename', ChangeColor = 'workbench.action.terminal.changeColor', ChangeIcon = 'workbench.action.terminal.changeIcon', + NewWithProfile = 'workbench.action.terminal.newWithProfile', + SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell' +} + +export enum TerminalCommandId { Split = 'workbench.action.terminal.split', KillAll = 'workbench.action.terminal.killAll', Unsplit = 'workbench.action.terminal.unsplit', Join = 'workbench.action.terminal.join', Show = 'workbench.action.terminal.toggleTerminal', CreateNew = 'workbench.action.terminal.new', + CreateNewEditor = 'workbench.action.createTerminalEditor', + SplitEditor = 'workbench.action.createTerminalEditorSide', + MoveToPanel = 'workbench.action.terminal.moveToTerminalPanel', + MoveToEditor = 'workbench.action.terminal.moveToEditor', NewWithProfile = 'workbench.action.terminal.newWithProfile', SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell' } +interface TerminalLabel { + name?: string, + icon?: string, + color?: string +} +type TerminalGroup = TerminalLabel[]; export class Terminal { constructor(private code: Code, private quickaccess: QuickAccess, private quickinput: QuickInput) { } - // TODO: Strongly type using non-const enum TerminalCommandId - async runCommand(commandId: string, value?: string): Promise { - await this.quickaccess.runCommand(commandId, !!value || commandId === TerminalCommandId.Join); + async runCommand(commandId: TerminalCommandId): Promise { + await this.quickaccess.runCommand(commandId, commandId === TerminalCommandId.Join); if (commandId === TerminalCommandId.Show || commandId === TerminalCommandId.CreateNew) { return await this._waitForTerminal(); } - if (value) { - await this.code.waitForSetValue(QuickInput.QUICK_INPUT_INPUT, value); - } await this.code.dispatchKeybinding('enter'); await this.quickinput.waitForQuickInputClosed(); } - async runCommandInTerminal(commandText: string): Promise { - await this.code.writeInTerminal(XTERM_SELECTOR, commandText); - // hold your horses - await new Promise(c => setTimeout(c, 500)); - await this.code.dispatchKeybinding('enter'); - } - - // TODO: Return something more robust: - // export interface ITerminalInstance { - // name: string; - // icon: string; - // } - // export type TerminalGroup = ITerminalInstance[]; - // export type TerminalLayout = TerminalGroup[]; - async getTabLabels(expectedCount: number, splits?: boolean, accept?: (result: IElement[]) => boolean): Promise { - const result: string[] = []; - const tabs = await this.code.waitForElements(TABS, true, e => accept ? accept(e) : e.length === expectedCount && (!splits || e.some(e => e.textContent.startsWith('┌'))) && e.every(element => element.textContent.trim().length > 1)); - for (const t of tabs) { - result.push(t.textContent); - } - if (!result[0].startsWith('┌')) { - const first = result[1]; - const second = result[0]; - return [first, second]; - } - return result; - } - - async runProfileCommand(command: string, contributed?: boolean, altKey?: boolean): Promise { - await this.quickaccess.runCommand(command, true); - if (contributed) { - await this.code.waitForSetValue(QuickInput.QUICK_INPUT_INPUT, CONTRIBUTED_PROFILE_NAME); + async runCommandWithValue(commandId: TerminalCommandIdWithValue, value?: string, altKey?: boolean): Promise { + const shouldKeepOpen = !!value || commandId === TerminalCommandIdWithValue.SelectDefaultProfile || commandId === TerminalCommandIdWithValue.NewWithProfile; + await this.quickaccess.runCommand(commandId, shouldKeepOpen); + if (value) { + await this.code.waitForSetValue(QuickInput.QUICK_INPUT_INPUT, value); } await this.code.dispatchKeybinding(altKey ? 'Alt+Enter' : 'enter'); await this.quickinput.waitForQuickInputClosed(); } + async runCommandInTerminal(commandText: string): Promise { + await this.code.writeInTerminal(Selector.Xterm, commandText); + // hold your horses + await new Promise(c => setTimeout(c, 500)); + await this.code.dispatchKeybinding('enter'); + } + + async assertEditorGroupCount(count: number): Promise { + await this.code.waitForElements(Selector.EditorGroups, true, editorGroups => editorGroups && editorGroups.length === count); + } + + async assertSingleTab(label: TerminalLabel, editor?: boolean): Promise { + await this.assertTabExpected(editor ? Selector.EditorTab : Selector.SingleTab, undefined, label.name ? new RegExp(label.name) : undefined, label.icon, label.color); + } + + async assertTerminalGroups(expectedGroups: TerminalGroup[]): Promise { + let expectedCount = 0; + expectedGroups.forEach(g => expectedCount += g.length); + let index = 0; + while (index < expectedCount) { + for (let groupIndex = 0; groupIndex < expectedGroups.length; groupIndex++) { + let terminalsInGroup = expectedGroups[groupIndex].length; + let indexInGroup = 0; + const isSplit = terminalsInGroup > 1; + while (indexInGroup < terminalsInGroup) { + let instance = expectedGroups[groupIndex][indexInGroup]; + const nameRegex = instance.name && isSplit ? new RegExp('\\s*[├┌└]\\s*' + instance.name) : instance.name ? new RegExp(/^\s*/ + instance.name) : undefined; + await this.assertTabExpected(undefined, index, nameRegex, instance.icon, instance.color); + indexInGroup++; + index++; + } + } + } + } + + private async assertTabExpected(selector?: string, listIndex?: number, nameRegex?: RegExp, icon?: string, color?: string): Promise { + if (listIndex) { + if (nameRegex) { + await this.code.waitForElement(`${Selector.Tabs}[data-index="${listIndex}"] ${Selector.TabsEntry}`, entry => !!entry && !!entry?.textContent.match(nameRegex)); + } + if (color) { + await this.code.waitForElement(`${Selector.Tabs}[data-index="${listIndex}"] ${Selector.TabsEntry} .monaco-icon-label.terminal-icon-terminal_ansi${color}`); + } + if (icon) { + await this.code.waitForElement(`${Selector.Tabs}[data-index="${listIndex}"] ${Selector.TabsEntry} .codicon-${icon}`); + } + } else if (selector) { + if (nameRegex) { + await this.code.waitForElement(`${selector}`, singleTab => !!singleTab && !!singleTab?.textContent.match(nameRegex)); + } + if (color) { + await this.code.waitForElement(`${selector}.terminal-icon-terminal_ansi${color}`); + } + if (icon) { + await this.code.waitForElement(selector === Selector.EditorTab ? `${Selector.EditorTabIcon}${icon}` : `${selector} .codicon-${icon}`); + } + } + } + + async clickPlusButton(): Promise { + await this.code.waitAndClick(Selector.PlusButton); + } + + async clickSplitButton(): Promise { + await this.code.waitAndClick(Selector.SplitButton); + } + + async clickSingleTab(): Promise { + await this.code.waitAndClick(Selector.SingleTab); + } + async waitForTerminalText(accept: (buffer: string[]) => boolean, message?: string): Promise { try { - await this.code.waitForTerminalBuffer(XTERM_SELECTOR, accept); + await this.code.waitForTerminalBuffer(Selector.Xterm, accept); } catch (err: any) { if (message) { - throw new Error(`${message}\n\nInner exception:\n${err.message}`); + throw new Error(`${message} \n\nInner exception: \n${err.message} `); } throw err; } @@ -97,7 +160,7 @@ export class Terminal { } private async _waitForTerminal(): Promise { - await this.code.waitForElement(XTERM_FOCUSED_SELECTOR); - await this.code.waitForTerminalBuffer(XTERM_SELECTOR, lines => lines.some(line => line.length > 0)); + await this.code.waitForElement(Selector.XtermFocused); + await this.code.waitForTerminalBuffer(Selector.Xterm, lines => lines.some(line => line.length > 0)); } } diff --git a/test/smoke/src/areas/terminal/terminal-editors.test.ts b/test/smoke/src/areas/terminal/terminal-editors.test.ts new file mode 100644 index 00000000000..747c2cd761c --- /dev/null +++ b/test/smoke/src/areas/terminal/terminal-editors.test.ts @@ -0,0 +1,76 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ParsedArgs } from 'minimist'; +import { Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation/out'; +import { afterSuite, beforeSuite } from '../../utils'; + +export function setup(opts: ParsedArgs) { + describe('Terminal Editors', () => { + let terminal: Terminal; + + beforeSuite(opts); + afterSuite(opts); + + before(function () { + terminal = this.app.workbench.terminal; + }); + + afterEach(async () => { + await terminal.runCommand(TerminalCommandId.KillAll); + }); + + it('should update color of the tab', async () => { + await terminal.runCommand(TerminalCommandId.CreateNewEditor); + const color = 'Cyan'; + await terminal.runCommandWithValue(TerminalCommandIdWithValue.ChangeColor, color); + await terminal.assertSingleTab({ color }, true); + }); + + it('should update icon of the tab', async () => { + await terminal.runCommand(TerminalCommandId.CreateNewEditor); + const icon = 'symbol-method'; + await terminal.runCommandWithValue(TerminalCommandIdWithValue.ChangeIcon, icon); + await terminal.assertSingleTab({ icon }, true); + }); + + it('should rename the tab', async () => { + await terminal.runCommand(TerminalCommandId.CreateNewEditor); + const name = 'my terminal name'; + await terminal.runCommandWithValue(TerminalCommandIdWithValue.Rename, name); + await terminal.assertSingleTab({ name }, true); + }); + + it('should show the panel when the terminal is moved there and close the editor', async () => { + await terminal.runCommand(TerminalCommandId.CreateNewEditor); + await terminal.runCommand(TerminalCommandId.MoveToPanel); + await terminal.assertSingleTab({}); + }); + + it('should open a terminal in a new group for open to the side', async () => { + await terminal.runCommand(TerminalCommandId.CreateNewEditor); + await terminal.runCommand(TerminalCommandId.SplitEditor); + await terminal.assertEditorGroupCount(2); + }); + + it('should open a terminal in a new group when the split button is pressed', async () => { + await terminal.runCommand(TerminalCommandId.CreateNewEditor); + await terminal.clickSplitButton(); + await terminal.assertEditorGroupCount(2); + }); + + it('should create new terminals in the active editor group via command', async () => { + await terminal.runCommand(TerminalCommandId.CreateNewEditor); + await terminal.runCommand(TerminalCommandId.CreateNewEditor); + await terminal.assertEditorGroupCount(1); + }); + + it('should create new terminals in the active editor group via plus button', async () => { + await terminal.runCommand(TerminalCommandId.CreateNewEditor); + await terminal.clickPlusButton(); + await terminal.assertEditorGroupCount(1); + }); + }); +} diff --git a/test/smoke/src/areas/terminal/terminal-profiles.test.ts b/test/smoke/src/areas/terminal/terminal-profiles.test.ts index 0f202d6e40c..0d111333689 100644 --- a/test/smoke/src/areas/terminal/terminal-profiles.test.ts +++ b/test/smoke/src/areas/terminal/terminal-profiles.test.ts @@ -3,31 +3,21 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ok } from 'assert'; import { ParsedArgs } from 'minimist'; -import { Code, Terminal } from '../../../../automation'; +import { Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation'; import { afterSuite, beforeSuite } from '../../utils'; -const ContributedProfileName = `JavaScript Debug Terminal`; +const CONTRIBUTED_PROFILE_NAME = `JavaScript Debug Terminal`; +const ANY_PROFILE_NAME = '^((?!JavaScript Debug Terminal).)*$'; export function setup(opts: ParsedArgs) { - describe('Terminal Profiles', () => { - let code: Code; let terminal: Terminal; - const enum TerminalCommandId { - Split = 'workbench.action.terminal.split', - KillAll = 'workbench.action.terminal.killAll', - Show = 'workbench.action.terminal.toggleTerminal', - CreateNew = 'workbench.action.terminal.new', - NewWithProfile = 'workbench.action.terminal.newWithProfile', - SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell' - } + beforeSuite(opts); afterSuite(opts); before(function () { - code = this.app.code; terminal = this.app.workbench.terminal; }); @@ -37,73 +27,56 @@ export function setup(opts: ParsedArgs) { it('should launch the default profile', async () => { await terminal.runCommand(TerminalCommandId.Show); - // TODO: Use getSingleTabLabel? Share logic with getTabLabel? - await code.waitForElement('.single-terminal-tab', e => e ? !e.textContent.endsWith(ContributedProfileName) : false); + await terminal.assertSingleTab({ name: ANY_PROFILE_NAME }); }); it.skip('should set the default profile to a contributed one', async () => { - await terminal.runProfileCommand(TerminalCommandId.SelectDefaultProfile, true); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SelectDefaultProfile, CONTRIBUTED_PROFILE_NAME); await terminal.runCommand(TerminalCommandId.CreateNew); - await code.waitForElement('.single-terminal-tab', e => e ? e.textContent.endsWith(ContributedProfileName) : false); + await terminal.assertSingleTab({ name: CONTRIBUTED_PROFILE_NAME }); }); it.skip('should use the default contributed profile on panel open and for splitting', async () => { - await terminal.runProfileCommand(TerminalCommandId.SelectDefaultProfile, true); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SelectDefaultProfile, CONTRIBUTED_PROFILE_NAME); await terminal.runCommand(TerminalCommandId.Show); await terminal.runCommand(TerminalCommandId.Split); - const tabs = await terminal.getTabLabels(2); - console.log('DEBUG: tabs', tabs); - ok(tabs[0].startsWith('┌') && tabs[0].endsWith(ContributedProfileName)); - ok(tabs[1].startsWith('└') && tabs[1].endsWith(ContributedProfileName)); + await terminal.assertTerminalGroups([[{ name: CONTRIBUTED_PROFILE_NAME }, { name: CONTRIBUTED_PROFILE_NAME }]]); }); it('should set the default profile', async () => { - await terminal.runProfileCommand(TerminalCommandId.SelectDefaultProfile, undefined); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SelectDefaultProfile); await terminal.runCommand(TerminalCommandId.CreateNew); - await code.waitForElement('.single-terminal-tab', e => e ? !e.textContent.endsWith(ContributedProfileName) : false); + await terminal.assertSingleTab({ name: ANY_PROFILE_NAME }); }); it('should use the default profile on panel open and for splitting', async () => { await terminal.runCommand(TerminalCommandId.Show); - await code.waitForElement('.single-terminal-tab', e => e ? !e.textContent.endsWith(ContributedProfileName) : false); + await terminal.assertSingleTab({ name: ANY_PROFILE_NAME }); await terminal.runCommand(TerminalCommandId.Split); - const tabs = await terminal.getTabLabels(2, true); - ok(tabs[0].startsWith('┌') && !tabs[0].endsWith(ContributedProfileName)); - ok(tabs[1].startsWith('└') && !tabs[1].endsWith(ContributedProfileName)); - }); - - it('clicking the plus button should create a terminal and display the tabs view showing no split decorations', async () => { - await terminal.runCommand(TerminalCommandId.Show); - await code.waitAndClick('li.action-item.monaco-dropdown-with-primary > div.action-container.menu-entry > a'); - const tabLabels = await terminal.getTabLabels(2); - ok(!tabLabels[0].startsWith('┌') && !tabLabels[1].startsWith('└')); + await terminal.assertTerminalGroups([[{}, {}]]); }); it('createWithProfile command should create a terminal with a profile', async () => { - await terminal.runProfileCommand(TerminalCommandId.NewWithProfile); - await code.waitForElement('.single-terminal-tab', e => e ? !e.textContent.endsWith(ContributedProfileName) : false); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.NewWithProfile); + await terminal.assertSingleTab({ name: ANY_PROFILE_NAME }); }); it.skip('createWithProfile command should create a terminal with a contributed profile', async () => { - await terminal.runProfileCommand(TerminalCommandId.NewWithProfile, true); - await code.waitForElement('.single-terminal-tab', e => e ? e.textContent.endsWith(ContributedProfileName) : false); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.NewWithProfile, CONTRIBUTED_PROFILE_NAME); + await terminal.assertSingleTab({ name: CONTRIBUTED_PROFILE_NAME }); }); it('createWithProfile command should create a split terminal with a profile', async () => { await terminal.runCommand(TerminalCommandId.Show); - await terminal.runProfileCommand(TerminalCommandId.NewWithProfile, undefined, true); - const tabs = await terminal.getTabLabels(2, true); - ok(tabs[0].startsWith('┌') && !tabs[0].endsWith(ContributedProfileName)); - ok(tabs[1].startsWith('└') && !tabs[1].endsWith(ContributedProfileName)); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.NewWithProfile, undefined, true); + await terminal.assertTerminalGroups([[{}, {}]]); }); it.skip('createWithProfile command should create a split terminal with a contributed profile', async () => { await terminal.runCommand(TerminalCommandId.Show); - await code.waitForElement('.single-terminal-tab', e => e ? !e.textContent.endsWith(ContributedProfileName) : false); - await terminal.runProfileCommand(TerminalCommandId.NewWithProfile, true, true); - const tabs = await terminal.getTabLabels(2, true); - ok(tabs[0].startsWith('┌') && !tabs[0].endsWith(ContributedProfileName)); - ok(tabs[1].startsWith('└') && tabs[1].endsWith(ContributedProfileName)); + await terminal.assertSingleTab({}); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.NewWithProfile, CONTRIBUTED_PROFILE_NAME, true); + await terminal.assertTerminalGroups([[{ name: ANY_PROFILE_NAME }, { name: CONTRIBUTED_PROFILE_NAME }]]); }); }); } diff --git a/test/smoke/src/areas/terminal/terminal-tabs.test.ts b/test/smoke/src/areas/terminal/terminal-tabs.test.ts index 1a5897eb0fd..161f077eeef 100644 --- a/test/smoke/src/areas/terminal/terminal-tabs.test.ts +++ b/test/smoke/src/areas/terminal/terminal-tabs.test.ts @@ -3,35 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ok } from 'assert'; + import { ParsedArgs } from 'minimist'; -import { Code, Terminal } from '../../../../automation/out'; +import { Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation/out'; import { afterSuite, beforeSuite } from '../../utils'; export function setup(opts: ParsedArgs) { - // TODO: Re-enable when stable - describe.skip('Terminal Tabs', () => { - let code: Code; + describe('Terminal Tabs', () => { let terminal: Terminal; - // TODO: Move into automation/terminal - const enum TerminalCommandId { - Rename = 'workbench.action.terminal.rename', - ChangeColor = 'workbench.action.terminal.changeColor', - ChangeIcon = 'workbench.action.terminal.changeIcon', - Split = 'workbench.action.terminal.split', - KillAll = 'workbench.action.terminal.killAll', - Unsplit = 'workbench.action.terminal.unsplit', - Join = 'workbench.action.terminal.join', - Show = 'workbench.action.terminal.toggleTerminal', - CreateNew = 'workbench.action.terminal.new' - } - beforeSuite(opts); afterSuite(opts); before(function () { - code = this.app.code; terminal = this.app.workbench.terminal; }); @@ -41,99 +25,99 @@ export function setup(opts: ParsedArgs) { it('clicking the plus button should create a terminal and display the tabs view showing no split decorations', async () => { await terminal.runCommand(TerminalCommandId.Show); - await code.waitAndClick('li.action-item.monaco-dropdown-with-primary > div.action-container.menu-entry > a'); - const tabLabels = await terminal.getTabLabels(2); - ok(!tabLabels[0].startsWith('┌') && !tabLabels[1].startsWith('└')); + await terminal.runCommand(TerminalCommandId.CreateNew); + await terminal.clickPlusButton(); + await terminal.assertTerminalGroups([[{}], [{}]]); }); it('should update color of the single tab', async () => { await terminal.runCommand(TerminalCommandId.Show); const color = 'Cyan'; - await terminal.runCommand(TerminalCommandId.ChangeColor, color); - const singleTab = await code.waitForElement('.single-terminal-tab'); - ok(singleTab.className.includes(`terminal-icon-terminal_ansi${color}`)); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.ChangeColor, color); + await terminal.assertSingleTab({ color }); }); it('should update color of the tab in the tabs list', async () => { await terminal.runCommand(TerminalCommandId.Show); await terminal.runCommand(TerminalCommandId.Split); - const tabs = await terminal.getTabLabels(2); - ok(tabs[0].startsWith('┌')); - ok(tabs[1].startsWith('└')); const color = 'Cyan'; - await terminal.runCommand(TerminalCommandId.ChangeColor, color); - await code.waitForElement(`.terminal-tabs-entry .terminal-icon-terminal_ansi${color}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.ChangeColor, color); + await terminal.assertTerminalGroups([[{}, { color }]]); }); it('should update icon of the single tab', async () => { await terminal.runCommand(TerminalCommandId.Show); const icon = 'symbol-method'; - await terminal.runCommand(TerminalCommandId.ChangeIcon, icon); - await code.waitForElement(`.single-terminal-tab .codicon-${icon}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.ChangeIcon, icon); + await terminal.assertSingleTab({ icon }); }); it('should update icon of the tab in the tabs list', async () => { await terminal.runCommand(TerminalCommandId.Show); await terminal.runCommand(TerminalCommandId.Split); - const tabs = await terminal.getTabLabels(2); - ok(tabs[0].startsWith('┌')); - ok(tabs[1].startsWith('└')); const icon = 'symbol-method'; - await terminal.runCommand(TerminalCommandId.ChangeIcon, icon); - await code.waitForElement(`.terminal-tabs-entry .codicon-${icon}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.ChangeIcon, icon); + await terminal.assertTerminalGroups([[{}, { icon }]]); }); it('should rename the single tab', async () => { await terminal.runCommand(TerminalCommandId.Show); const name = 'my terminal name'; - await terminal.runCommand(TerminalCommandId.Rename, name); - await code.waitForElement('.single-terminal-tab', e => e ? e?.textContent.includes(name) : false); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.Rename, name); + await terminal.assertSingleTab({ name }); }); it('should rename the tab in the tabs list', async () => { await terminal.runCommand(TerminalCommandId.Show); await terminal.runCommand(TerminalCommandId.Split); const name = 'my terminal name'; - await terminal.runCommand(TerminalCommandId.Rename, name); - await terminal.getTabLabels(2, true, t => t.some(element => element.textContent.includes(name))); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.Rename, name); + await terminal.assertTerminalGroups([[{}, { name }]]); }); it('should create a split terminal when single tab is alt clicked', async () => { await terminal.runCommand(TerminalCommandId.Show); const page = await terminal.getPage(); page.keyboard.down('Alt'); - await code.waitAndClick('.single-terminal-tab'); + await terminal.clickSingleTab(); page.keyboard.up('Alt'); - await terminal.getTabLabels(2, true); + await terminal.assertTerminalGroups([[{}, {}]]); }); it('should do nothing when join tabs is run with only one terminal', async () => { await terminal.runCommand(TerminalCommandId.Show); await terminal.runCommand(TerminalCommandId.Join); - await code.waitForElement('.single-terminal-tab'); + await terminal.assertSingleTab({}); }); it('should join tabs when more than one terminal', async () => { await terminal.runCommand(TerminalCommandId.Show); await terminal.runCommand(TerminalCommandId.CreateNew); await terminal.runCommand(TerminalCommandId.Join); - await terminal.getTabLabels(2, true); + await terminal.assertTerminalGroups([[{}, {}]]); }); it('should do nothing when unsplit tabs called with no splits', async () => { await terminal.runCommand(TerminalCommandId.Show); await terminal.runCommand(TerminalCommandId.CreateNew); - await terminal.getTabLabels(2, false); + await terminal.assertTerminalGroups([[{}], [{}]]); await terminal.runCommand(TerminalCommandId.Unsplit); - await terminal.getTabLabels(2, false); + await terminal.assertTerminalGroups([[{}], [{}]]); }); it('should unsplit tabs', async () => { await terminal.runCommand(TerminalCommandId.Show); await terminal.runCommand(TerminalCommandId.Split); - await terminal.getTabLabels(2, true); + await terminal.assertTerminalGroups([[{}, {}]]); await terminal.runCommand(TerminalCommandId.Unsplit); - await terminal.getTabLabels(2, false, t => t.every(label => !label.textContent.startsWith('┌') && !label.textContent.startsWith('└'))); + await terminal.assertTerminalGroups([[{}], [{}]]); + }); + + it('should move the terminal to the editor area', async () => { + await terminal.runCommand(TerminalCommandId.Show); + await terminal.assertSingleTab({}); + await terminal.runCommand(TerminalCommandId.MoveToEditor); + await terminal.assertEditorGroupCount(1); }); }); } diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 7f95e942bec..734aef1733d 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -29,6 +29,7 @@ import { setup as setupLocalizationTests } from './areas/workbench/localization. import { setup as setupLaunchTests } from './areas/workbench/launch.test'; import { setup as setupTerminalProfileTests } from './areas/terminal/terminal-profiles.test'; import { setup as setupTerminalTabsTests } from './areas/terminal/terminal-tabs.test'; +import { setup as setupTerminalEditorsTests } from './areas/terminal/terminal-editors.test'; const testDataPath = path.join(os.tmpdir(), 'vscsmoke'); if (fs.existsSync(testDataPath)) { @@ -362,4 +363,5 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { // TODO: Enable terminal tests for non-web if (opts.web) { setupTerminalProfileTests(opts); } if (opts.web) { setupTerminalTabsTests(opts); } + if (opts.web) { setupTerminalEditorsTests(opts); } });