From 5dec5256d75ee178ed4d648b402b00dc3896fcbe Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 19 Nov 2021 10:33:43 -0800 Subject: [PATCH] Add some detach/attach tests --- src/vs/platform/driver/browser/baseDriver.ts | 2 +- .../terminal/browser/xterm-private.d.ts | 2 +- test/automation/src/terminal.ts | 31 ++++++- .../terminal/terminal-persistence.test.ts | 82 +++++++++++++++++++ .../terminal/terminal-reconnection.test.ts | 20 ----- test/smoke/src/main.ts | 2 + 6 files changed, 115 insertions(+), 24 deletions(-) create mode 100644 test/smoke/src/areas/terminal/terminal-persistence.test.ts delete mode 100644 test/smoke/src/areas/terminal/terminal-reconnection.test.ts diff --git a/src/vs/platform/driver/browser/baseDriver.ts b/src/vs/platform/driver/browser/baseDriver.ts index 40e5e2227ab..184ff5d1935 100644 --- a/src/vs/platform/driver/browser/baseDriver.ts +++ b/src/vs/platform/driver/browser/baseDriver.ts @@ -158,7 +158,7 @@ export abstract class BaseWindowDriver implements IWindowDriver { throw new Error(`Xterm not found: ${selector}`); } - xterm._core._coreService.triggerDataEvent(text); + xterm._core.coreService.triggerDataEvent(text); } getLocaleInfo(): Promise { diff --git a/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts b/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts index b700ee167fa..cf8f8c46cdd 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts @@ -20,7 +20,7 @@ export interface IXtermCore { height: number; }; - _coreService: { + coreService: { triggerDataEvent(data: string, wasUserInput?: boolean): void; }; diff --git a/test/automation/src/terminal.ts b/test/automation/src/terminal.ts index 03ec6d53937..f1e8d9399aa 100644 --- a/test/automation/src/terminal.ts +++ b/test/automation/src/terminal.ts @@ -26,7 +26,8 @@ export enum TerminalCommandIdWithValue { ChangeColor = 'workbench.action.terminal.changeColor', ChangeIcon = 'workbench.action.terminal.changeIcon', NewWithProfile = 'workbench.action.terminal.newWithProfile', - SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell' + SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell', + AttachToSession = 'workbench.action.terminal.attachToSession', } export enum TerminalCommandId { @@ -41,7 +42,8 @@ export enum TerminalCommandId { MoveToPanel = 'workbench.action.terminal.moveToTerminalPanel', MoveToEditor = 'workbench.action.terminal.moveToEditor', NewWithProfile = 'workbench.action.terminal.newWithProfile', - SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell' + SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell', + DetachSession = 'workbench.action.terminal.detachSession', } interface TerminalLabel { name?: string, @@ -108,6 +110,27 @@ export class Terminal { } } + async getTerminalGroups(): Promise { + const tabCount = (await this.code.waitForElements(Selector.Tabs, true)).length; + console.log('tabCount', tabCount); + const groups: TerminalGroup[] = []; + for (let i = 0; i < tabCount; i++) { + const instance = await this.code.waitForElement(`${Selector.Tabs}[data-index="${i}"] ${Selector.TabsEntry}`); + console.log('instance', instance); + const label: TerminalLabel = { + name: instance.textContent.replace(/^[├┌└]\s*/, '') + }; + // It's a new group if the the tab does not start with ├ or └ + if (instance.textContent.match(/^[├└]/)) { + groups[groups.length - 1].push(label); + } else { + groups.push([label]); + } + } + console.log('groups', groups); + return groups; + } + private async assertTabExpected(selector?: string, listIndex?: number, nameRegex?: RegExp, icon?: string, color?: string): Promise { if (listIndex) { if (nameRegex) { @@ -132,6 +155,10 @@ export class Terminal { } } + async assertTerminalViewHidden(): Promise { + await this.code.waitForElement(Selector.TerminalView, result => result === undefined); + } + async clickPlusButton(): Promise { await this.code.waitAndClick(Selector.PlusButton); } diff --git a/test/smoke/src/areas/terminal/terminal-persistence.test.ts b/test/smoke/src/areas/terminal/terminal-persistence.test.ts new file mode 100644 index 00000000000..6c7f5ce99de --- /dev/null +++ b/test/smoke/src/areas/terminal/terminal-persistence.test.ts @@ -0,0 +1,82 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ok, strictEqual } from 'assert'; +import { ParsedArgs } from 'minimist'; +import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation/out'; +import { afterSuite, beforeSuite } from '../../utils'; + +export function setup(opts: ParsedArgs) { + describe.only('Terminal Persistence', () => { + let terminal: Terminal; + + beforeSuite(opts); + afterSuite(opts); + + before(async function () { + const app = this.app as Application; + terminal = app.workbench.terminal; + + // Always show tabs to make getting terminal groups easier + await app.workbench.settingsEditor.addUserSetting('terminal.integrated.tabs.hideCondition', '"never"'); + await app.workbench.quickaccess.runCommand('workbench.action.closeAllEditors'); + }); + + afterEach(async () => { + await terminal.runCommand(TerminalCommandId.KillAll); + }); + + describe('detach/attach', () => { + it('should support basic reconnection', async () => { + await terminal.runCommand(TerminalCommandId.CreateNew); + // TODO: Handle passing in an actual regex, not string + await terminal.assertTerminalGroups([ + [{ name: '.*' }] + ]); + + const groups = await terminal.getTerminalGroups(); + strictEqual(groups.length, 1); + strictEqual(groups[0].length, 1); + ok(groups[0][0].name!.length > 0); + const detachedName = groups[0][0].name!; + console.log('detached name', detachedName); + + await terminal.runCommand(TerminalCommandId.DetachSession); + await terminal.assertTerminalViewHidden(); + + await terminal.runCommandWithValue(TerminalCommandIdWithValue.AttachToSession, detachedName); + await terminal.assertTerminalGroups([ + [{ name: detachedName }] + ]); + }); + + it('should persist buffer content', async () => { + await terminal.runCommand(TerminalCommandId.CreateNew); + // TODO: Handle passing in an actual regex, not string + await terminal.assertTerminalGroups([ + [{ name: '.*' }] + ]); + + const groups = await terminal.getTerminalGroups(); + strictEqual(groups.length, 1); + strictEqual(groups[0].length, 1); + ok(groups[0][0].name!.length > 0); + const detachedName = groups[0][0].name!; + + await terminal.runCommandInTerminal('echo terminal_test_content'); + await terminal.waitForTerminalText(buffer => buffer.some(e => e.includes('terminal_test_content'))); + + await terminal.runCommand(TerminalCommandId.DetachSession); + await terminal.assertTerminalViewHidden(); + + await terminal.runCommandWithValue(TerminalCommandIdWithValue.AttachToSession, detachedName); + await terminal.assertTerminalGroups([ + [{ name: detachedName }] + ]); + await terminal.waitForTerminalText(buffer => buffer.some(e => e.includes('terminal_test_content'))); + }); + }); + }); +} diff --git a/test/smoke/src/areas/terminal/terminal-reconnection.test.ts b/test/smoke/src/areas/terminal/terminal-reconnection.test.ts deleted file mode 100644 index 6a6db40a623..00000000000 --- a/test/smoke/src/areas/terminal/terminal-reconnection.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { Application } from '../../../../automation'; -import { afterSuite, beforeSuite } from '../../utils'; - -export function setup(opts: ParsedArgs) { - describe('Terminal Reconnection', () => { - beforeSuite(opts); - afterSuite(opts); - - it.skip('should reconnect to a single terminal on reload', async () => { - const app = this.app as Application; - console.log(app); - }); - }); -} diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 734aef1733d..ab1deeb64c2 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -30,6 +30,7 @@ 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'; +import { setup as setupTerminalPersistenceTests } from './areas/terminal/terminal-persistence.test'; const testDataPath = path.join(os.tmpdir(), 'vscsmoke'); if (fs.existsSync(testDataPath)) { @@ -364,4 +365,5 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { if (opts.web) { setupTerminalProfileTests(opts); } if (opts.web) { setupTerminalTabsTests(opts); } if (opts.web) { setupTerminalEditorsTests(opts); } + if (opts.web) { setupTerminalPersistenceTests(opts); } });