add terminal editor and tab smoke tests (#137393)

* Add a bunch of tests

* tweak tests

* add profile tests, now breaking (no profiles showing up)

* uncomment tests

* update expected

* fix test

* merge

* all passing

* bunch of improvements

* improve readability

* all should be passing and cleaned up

* all passing

* fix #137243 and clean-up

* remove .only

* fix #137247

* get rid of enum

* see if this fixes timing issue

* use keybinding for show terminal instead

* remove delay, implement better accept function

* get rid of unneeded index

* try something else

* wait for empty editor to be active

* remove .only

* decrease redundancy in names

* re-add xterm selector

* try something else

* undo change that broke things worse

* add terminal-tabs test

* all tabs tests passing locally

* kill all

* await before running each

* fix tests

* remove .only

* try waiting for focused xterm

* remove .only

* clean up

* 🧹

* fix profiles tests by using this.app.props

* revert to use default shell

* re-add conditional

* Get tests passing on WebKit

On WebKit the smoke tests were failing because the quick pick was
triggering a focus event on the terminal after the blur event had
already happened, this caused the view service to think the terminal
was still focused when it wasn't. The fix was to reset the context key
also in IViewsService.closeView.

* Safari -> WebKit

* Prefer arrow functions

* remove beforeEach timeout

* add timeouts to contributed profile tests

* add terminal editor tests, fix #137377

* add a bunch of tests

* refactor

* get rid of profile specific command

* more polish

* refactor getTabs -> assertTerminalGroups

* fix failing test

* more polish

* remove .only

* add assertSingleTab

* remove unused import

* fix error

* fix more failures

* more changes

* fix almost all except for plus button

* fix failing plus button test

* all passing

* modify error that gets thrown

* modify error message again

* remove unused wildcard/ ANY_NAME, fix icon code

* fix icon code

* large refactor, improvements

* finish polish

* 1 failing

* get test to pass

Co-authored-by: Daniel Imms <2193314+Tyriar@users.noreply.github.com>
This commit is contained in:
Megan Rogge 2021-11-18 15:11:40 -08:00 committed by GitHub
parent 15f1721061
commit f66bc86da8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 246 additions and 148 deletions

View file

@ -57,7 +57,6 @@ export abstract class BaseWindowDriver implements IWindowDriver {
async getElements(selector: string, recursive: boolean): Promise<IElement[]> {
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));

View file

@ -687,6 +687,7 @@ export class TerminalService implements ITerminalService {
}
if (source.target !== TerminalLocation.Editor) {
await this._terminalGroupService.showPanel(true);
return;
}
source.target = TerminalLocation.Panel;

View file

@ -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<void> {
await this.quickaccess.runCommand(commandId, !!value || commandId === TerminalCommandId.Join);
async runCommand(commandId: TerminalCommandId): Promise<void> {
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<void> {
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<string[]> {
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<void> {
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<void> {
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<void> {
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<void> {
await this.code.waitForElements(Selector.EditorGroups, true, editorGroups => editorGroups && editorGroups.length === count);
}
async assertSingleTab(label: TerminalLabel, editor?: boolean): Promise<void> {
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<void> {
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<void> {
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<void> {
await this.code.waitAndClick(Selector.PlusButton);
}
async clickSplitButton(): Promise<void> {
await this.code.waitAndClick(Selector.SplitButton);
}
async clickSingleTab(): Promise<void> {
await this.code.waitAndClick(Selector.SingleTab);
}
async waitForTerminalText(accept: (buffer: string[]) => boolean, message?: string): Promise<void> {
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<void> {
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));
}
}

View file

@ -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);
});
});
}

View file

@ -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 }]]);
});
});
}

View file

@ -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);
});
});
}

View file

@ -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); }
});