Merge from vscode merge-base (#22780)

* Revert "Revert "Merge from vscode merge-base (#22769)" (#22779)"

This reverts commit 47a1745180.

* Fix notebook download task

* Remove done call from extensions-ci
This commit is contained in:
Karl Burtram
2023-04-19 21:48:46 -07:00
committed by GitHub
parent decbe8dded
commit e7d3d047ec
2389 changed files with 92155 additions and 42602 deletions

View File

@@ -46,14 +46,14 @@ export function setup(logger: Logger) {
await app.workbench.search.removeFileMatch('app.js', '2 results in 2 files');
});
it.skip('replaces first search result with a replace term', async function () { // TODo@roblourens https://github.com/microsoft/vscode/issues/137195
it.skip('replaces first search result with a replace term', async function () { // TODO@roblourens https://github.com/microsoft/vscode/issues/137195
const app = this.app as Application;
await app.workbench.search.searchFor('body');
await app.workbench.search.waitForResultText('6 results in 3 files');
await app.workbench.search.expandReplace();
await app.workbench.search.setReplaceText('ydob');
await app.workbench.search.replaceFileMatch('app.js', '12 results in 4 files');
await app.workbench.search.replaceFileMatch('app.js', '2 results in 2 files');
await app.workbench.search.searchFor('ydob');
await app.workbench.search.waitForResultText('4 results in 1 file');

View File

@@ -16,7 +16,7 @@ export function setup(logger: Logger) {
it('verifies presence of all default status bar elements', async function () {
const app = this.app as Application;
await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.BRANCH_STATUS);
if (app.quality !== Quality.Dev) {
if (app.quality !== Quality.Dev && app.quality !== Quality.OSS) {
await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.FEEDBACK_ICON);
}
await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.SYNC_STATUS);
@@ -69,7 +69,7 @@ export function setup(logger: Logger) {
it(`verifies that 'Tweet us feedback' pop-up appears when clicking on 'Feedback' icon`, async function () {
const app = this.app as Application;
if (app.quality === Quality.Dev) {
if (app.quality === Quality.Dev || app.quality === Quality.OSS) {
return this.skip();
}

View File

@@ -0,0 +1,71 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Application, Task, Terminal, TerminalCommandId } from '../../../../automation/';
export function setup() {
describe('Task Quick Pick', () => {
let app: Application;
let task: Task;
let terminal: Terminal;
// Acquire automation API
before(async function () {
app = this.app as Application;
task = app.workbench.task;
terminal = app.workbench.terminal;
});
afterEach(async () => {
// Kill all terminals between every test for a consistent testing environment
await terminal.runCommand(TerminalCommandId.KillAll);
});
describe('Tasks: Run Task', () => {
const label = "name";
const type = "shell";
const command = "echo 'test'";
it('hide property - true', async () => {
await task.configureTask({ type, command, label, hide: true });
await task.assertTasks(label, [], 'run');
});
it('hide property - false', async () => {
await task.configureTask({ type, command, label, hide: false });
await task.assertTasks(label, [{ label }], 'run');
});
it('hide property - undefined', async () => {
await task.configureTask({ type, command, label });
await task.assertTasks(label, [{ label }], 'run');
});
it('icon - icon only', async () => {
const config = { label, type, command, icon: { id: "lightbulb" } };
await task.configureTask(config);
await task.assertTasks(label, [config], 'run');
});
it('icon - color only', async () => {
const config = { label, type, command, icon: { color: "terminal.ansiRed" } };
await task.configureTask(config);
await task.assertTasks(label, [{ label, type, command, icon: { color: "Red" } }], 'run');
});
it('icon - icon & color', async () => {
const config = { label, type, command, icon: { id: "lightbulb", color: "terminal.ansiRed" } };
await task.configureTask(config);
await task.assertTasks(label, [{ label, type, command, icon: { id: "lightbulb", color: "Red" } }], 'run');
});
});
//TODO: why won't this command run
describe.skip('Tasks: Configure Task', () => {
const label = "name";
const type = "shell";
const command = "echo 'test'";
describe('hide', () => {
it('true should still show the task', async () => {
await task.configureTask({ type, command, label, hide: true });
await task.assertTasks(label, [{ label }], 'configure');
});
});
});
});
}

View File

@@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Logger } from '../../../../automation';
import { installAllHandlers } from '../../utils';
import { setup as setupTaskQuickPickTests } from './task-quick-pick.test';
export function setup(logger: Logger) {
describe('Task', function () {
// Retry tests 3 times to minimize build failures due to any flakiness
this.retries(3);
// Shared before/after handling
installAllHandlers(logger);
setupTaskQuickPickTests();
});
}

View File

@@ -3,16 +3,25 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation';
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue, SettingsEditor } from '../../../../automation';
import { setTerminalTestSettings } from './terminal-helpers';
export function setup() {
describe('Terminal Editors', () => {
let terminal: Terminal;
let app: Application;
let terminal: Terminal;
let settingsEditor: SettingsEditor;
// Acquire automation API
before(async function () {
app = this.app as Application;
terminal = app.workbench.terminal;
settingsEditor = app.workbench.settingsEditor;
await setTerminalTestSettings(app);
});
after(async function () {
await settingsEditor.clearUserSettings();
});
it('should update color of the tab', async () => {
@@ -66,13 +75,14 @@ export function setup() {
await terminal.assertEditorGroupCount(1);
});
it.skip('should create a terminal in the editor area by default', async () => {
it('should create a terminal in the editor area by default', async () => {
await app.workbench.settingsEditor.addUserSetting('terminal.integrated.defaultLocation', '"editor"');
// Close the settings editor
await app.workbench.quickaccess.runCommand('workbench.action.closeAllEditors');
await terminal.createTerminal('editor');
await terminal.assertEditorGroupCount(1);
await terminal.assertTerminalViewHidden();
await app.workbench.settingsEditor.clearUserSettings();
});
});
}

View File

@@ -0,0 +1,23 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Application } from '../../../../automation';
export async function setTerminalTestSettings(app: Application, additionalSettings: [key: string, value: string][] = []) {
await app.workbench.settingsEditor.addUserSettings([
// Work wrap is required when calling settingsEditor.addUserSetting multiple times or the
// click to focus will fail
['editor.wordWrap', '"on"'],
// Always show tabs to make getting terminal groups easier
['terminal.integrated.tabs.hideCondition', '"never"'],
// Use the DOM renderer for smoke tests so they can be inspected in the playwright trace
// viewer
['terminal.integrated.gpuAcceleration', '"off"'],
...additionalSettings
]);
// Close the settings editor
await app.workbench.quickaccess.runCommand('workbench.action.closeAllEditors');
}

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Application, Terminal, SettingsEditor } from '../../../../automation';
import { setTerminalTestSettings } from './terminal-helpers';
export function setup() {
describe('Terminal Input', () => {
@@ -15,6 +16,11 @@ export function setup() {
const app = this.app as Application;
terminal = app.workbench.terminal;
settingsEditor = app.workbench.settingsEditor;
await setTerminalTestSettings(app);
});
after(async function () {
await settingsEditor.clearUserSettings();
});
describe('Auto replies', function () {
@@ -31,12 +37,6 @@ export function setup() {
await terminal.runCommandInTerminal(`"\r${text}`, true);
}
it.skip('should automatically reply to default "Terminate batch job (Y/N)"', async () => { // TODO: #139076
await terminal.createTerminal();
await writeTextForAutoReply('Terminate batch job (Y/N)?');
await terminal.waitForTerminalText(buffer => buffer.some(line => line.match(/\?.*Y/)));
});
it('should automatically reply to a custom entry', async () => {
await settingsEditor.addUserSetting('terminal.integrated.autoReplies', '{ "foo": "bar" }');
await terminal.createTerminal();

View File

@@ -3,20 +3,29 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation';
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue, SettingsEditor } from '../../../../automation';
import { setTerminalTestSettings } from './terminal-helpers';
export function setup() {
describe('Terminal Persistence', () => {
// Acquire automation API
let terminal: Terminal;
before(function () {
let settingsEditor: SettingsEditor;
before(async function () {
const app = this.app as Application;
terminal = app.workbench.terminal;
settingsEditor = app.workbench.settingsEditor;
await setTerminalTestSettings(app);
});
after(async function () {
await settingsEditor.clearUserSettings();
});
describe('detach/attach', () => {
// https://github.com/microsoft/vscode/issues/137799
it.skip('should support basic reconnection', async () => {
it('should support basic reconnection', async () => {
await terminal.createTerminal();
// TODO: Handle passing in an actual regex, not string
await terminal.assertTerminalGroups([
@@ -40,7 +49,7 @@ export function setup() {
]);
});
it.skip('should persist buffer content', async () => {
it('should persist buffer content', async () => {
await terminal.createTerminal();
// TODO: Handle passing in an actual regex, not string
await terminal.assertTerminalGroups([
@@ -68,34 +77,6 @@ export function setup() {
]);
await terminal.waitForTerminalText(buffer => buffer.some(e => e.includes('terminal_test_content')));
});
// TODO: This is currently flaky because it takes time to send over the new icon to the backend
it.skip('should persist terminal icon', async () => {
await terminal.createTerminal();
// TODO: Handle passing in an actual regex, not string
await terminal.assertTerminalGroups([
[{ name: '.*' }]
]);
// Get the terminal name
const name = (await terminal.getTerminalGroups())[0][0].name!;
// Set the icon
await terminal.runCommandWithValue(TerminalCommandIdWithValue.ChangeIcon, 'symbol-method');
await terminal.assertSingleTab({ icon: 'symbol-method' });
// Detach
await terminal.runCommand(TerminalCommandId.DetachSession);
await terminal.assertTerminalViewHidden();
// Attach
await terminal.runCommandWithValue(TerminalCommandIdWithValue.AttachToSession, name);
await terminal.assertTerminalGroups([
[{ name }]
]);
// TODO: This fails due to a bug
await terminal.assertSingleTab({ icon: 'symbol-method' });
});
});
});
}

View File

@@ -3,7 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation';
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue, SettingsEditor } from '../../../../automation';
import { setTerminalTestSettings } from './terminal-helpers';
const CONTRIBUTED_PROFILE_NAME = `JavaScript Debug Terminal`;
const ANY_PROFILE_NAME = '^((?!JavaScript Debug Terminal).)*$';
@@ -12,9 +13,17 @@ export function setup() {
describe('Terminal Profiles', () => {
// Acquire automation API
let terminal: Terminal;
before(function () {
let settingsEditor: SettingsEditor;
before(async function () {
const app = this.app as Application;
terminal = app.workbench.terminal;
settingsEditor = app.workbench.settingsEditor;
await setTerminalTestSettings(app);
});
after(async function () {
await settingsEditor.clearUserSettings();
});
it('should launch the default profile', async () => {
@@ -22,13 +31,13 @@ export function setup() {
await terminal.assertSingleTab({ name: ANY_PROFILE_NAME });
});
it.skip('should set the default profile to a contributed one', async () => {
it('should set the default profile to a contributed one', async () => {
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SelectDefaultProfile, CONTRIBUTED_PROFILE_NAME);
await terminal.createTerminal();
await terminal.assertSingleTab({ name: CONTRIBUTED_PROFILE_NAME });
});
it.skip('should use the default contributed profile on panel open and for splitting', async () => {
it('should use the default contributed profile on panel open and for splitting', async () => {
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SelectDefaultProfile, CONTRIBUTED_PROFILE_NAME);
await terminal.runCommand(TerminalCommandId.Show);
await terminal.runCommand(TerminalCommandId.Split);
@@ -53,7 +62,7 @@ export function setup() {
await terminal.assertSingleTab({ name: ANY_PROFILE_NAME });
});
it.skip('createWithProfile command should create a terminal with a contributed profile', async () => {
it('createWithProfile command should create a terminal with a contributed profile', async () => {
await terminal.runCommandWithValue(TerminalCommandIdWithValue.NewWithProfile, CONTRIBUTED_PROFILE_NAME);
await terminal.assertSingleTab({ name: CONTRIBUTED_PROFILE_NAME });
});
@@ -64,7 +73,7 @@ export function setup() {
await terminal.assertTerminalGroups([[{}, {}]]);
});
it.skip('createWithProfile command should create a split terminal with a contributed profile', async () => {
it('createWithProfile command should create a split terminal with a contributed profile', async () => {
await terminal.runCommand(TerminalCommandId.Show);
await terminal.assertSingleTab({});
await terminal.runCommandWithValue(TerminalCommandIdWithValue.NewWithProfile, CONTRIBUTED_PROFILE_NAME, true);

View File

@@ -3,7 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Application, Terminal, SettingsEditor } from '../../../../automation';
import { Application, Terminal, SettingsEditor, TerminalCommandIdWithValue, TerminalCommandId } from '../../../../automation';
import { setTerminalTestSettings } from './terminal-helpers';
export function setup() {
describe('Terminal Shell Integration', () => {
@@ -15,50 +16,151 @@ export function setup() {
app = this.app as Application;
terminal = app.workbench.terminal;
settingsEditor = app.workbench.settingsEditor;
await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.enabled', 'true');
});
describe('Shell integration', function () {
describe('Activation', function () {
it('should activate shell integration on creation of a terminal', async () => {
await terminal.createTerminal();
await terminal.assertShellIntegrationActivated();
});
afterEach(async function () {
await app.workbench.terminal.runCommand(TerminalCommandId.KillAll);
});
async function createShellIntegrationProfile() {
await terminal.runCommandWithValue(TerminalCommandIdWithValue.NewWithProfile, process.platform === 'win32' ? 'PowerShell' : 'bash');
}
// TODO: Some agents may not have pwsh installed?
(process.platform === 'win32' ? describe.skip : describe)(`Process-based tests`, function () {
before(async function () {
await setTerminalTestSettings(app, [['terminal.integrated.shellIntegration.enabled', 'true']]);
});
(process.platform === 'win32' ? describe.skip : describe)('Decorations', function () {
after(async function () {
await settingsEditor.clearUserSettings();
});
describe('Decorations', function () {
describe('Should show default icons', function () {
it('Placeholder', async () => {
await terminal.createTerminal();
await terminal.assertShellIntegrationActivated();
await createShellIntegrationProfile();
await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 });
});
it('Success', async () => {
await terminal.createTerminal();
await terminal.assertShellIntegrationActivated();
await terminal.runCommandInTerminal(`ls`);
await createShellIntegrationProfile();
await terminal.runCommandInTerminal(`echo "success"`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 0 });
});
it('Error', async () => {
await terminal.createTerminal();
await terminal.assertShellIntegrationActivated();
await terminal.runCommandInTerminal(`fsdkfsjdlfksjdkf`);
await createShellIntegrationProfile();
await terminal.runCommandInTerminal(`false`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 1 });
});
});
describe('Custom configuration', function () {
it('Should update and show custom icons', async () => {
await terminal.createTerminal();
await terminal.assertShellIntegrationActivated();
await createShellIntegrationProfile();
await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 });
await terminal.runCommandInTerminal(`ls`);
await terminal.runCommandInTerminal(`fsdkfsjdlfksjdkf`);
await terminal.runCommandInTerminal(`echo "foo"`);
await terminal.runCommandInTerminal(`bar`);
await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationIcon', '"zap"');
await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationIconSuccess', '"zap"');
await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationIconError', '"zap"');
await terminal.assertCommandDecorations(undefined, { updatedIcon: "zap", count: 3 });
});
});
describe('terminal.integrated.shellIntegration.decorationsEnabled should determine gutter and overview ruler decoration visibility', function () {
beforeEach(async () => {
await settingsEditor.clearUserSettings();
await setTerminalTestSettings(app, [['terminal.integrated.shellIntegration.enabled', 'true']]);
await createShellIntegrationProfile();
await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 });
await terminal.runCommandInTerminal(`echo "foo"`);
await terminal.runCommandInTerminal(`bar`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 });
});
afterEach(async () => {
await app.workbench.terminal.runCommand(TerminalCommandId.KillAll);
});
it('never', async () => {
await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationsEnabled', '"never"');
await terminal.assertCommandDecorations({ placeholder: 0, success: 0, error: 0 }, undefined, 'never');
});
it('both', async () => {
await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationsEnabled', '"both"');
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 }, undefined, 'both');
});
it('gutter', async () => {
await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationsEnabled', '"gutter"');
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 }, undefined, 'gutter');
});
it('overviewRuler', async () => {
await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationsEnabled', '"overviewRuler"');
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 }, undefined, 'overviewRuler');
});
});
});
});
// These are integration tests that only test the UI side by simulating process writes.
// Because of this, they do not test the shell integration scripts, only what the scripts
// are expected to write.
describe('Write data-based tests', () => {
before(async function () {
await setTerminalTestSettings(app);
});
after(async function () {
await settingsEditor.clearUserSettings();
});
beforeEach(async function () {
// Create the simplest system profile to get as little process interaction as possible
await terminal.createTerminal();
// Erase all content and reset cursor to top
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${csi('2J')}${csi('H')}`);
});
describe('VS Code sequences', () => {
it('should handle the simple case', async () => {
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}exitcode 0`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${vsc('C')}Success\\r\\n${vsc('D;0')}`);
await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}exitcode 1`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${vsc('C')}Failure\\r\\n${vsc('D;1')}`);
await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 1 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 });
});
});
// TODO: This depends on https://github.com/microsoft/vscode/issues/146587
describe.skip('Final Term sequences', () => {
it('should handle the simple case', async () => {
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 0`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${ft('C')}Success\\r\\n${ft('D;0')}`);
await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 1`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${ft('C')}Failure\\r\\n${ft('D;1')}`);
await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 1 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 1`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 });
});
});
});
});
}
function ft(data: string) {
return setTextParams(`133;${data}`);
}
function vsc(data: string) {
return setTextParams(`633;${data}`);
}
function setTextParams(data: string) {
return osc(`${data}\\x07`);
}
function osc(data: string) {
return `\\x1b]${data}`;
}
function csi(data: string) {
return `\\x1b[${data}`;
}

View File

@@ -3,17 +3,25 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Application, Terminal } from '../../../../automation';
import { Application, Terminal, SettingsEditor } from '../../../../automation';
import { setTerminalTestSettings } from './terminal-helpers';
export function setup() {
describe('Terminal splitCwd', () => {
// Acquire automation API
let terminal: Terminal;
let settingsEditor: SettingsEditor;
before(async function () {
const app = this.app as Application;
terminal = app.workbench.terminal;
await app.workbench.settingsEditor.addUserSetting('terminal.integrated.splitCwd', '"inherited"');
await app.workbench.quickaccess.runCommand('workbench.action.closeAllEditors');
settingsEditor = app.workbench.settingsEditor;
await setTerminalTestSettings(app, [
['terminal.integrated.splitCwd', '"inherited"']
]);
});
after(async function () {
await settingsEditor.clearUserSettings();
});
it('should inherit cwd when split and update the tab description - alt click', async () => {

View File

@@ -3,15 +3,24 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation';
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue, SettingsEditor } from '../../../../automation';
import { setTerminalTestSettings } from './terminal-helpers';
export function setup() {
describe('Terminal Tabs', () => {
// Acquire automation API
let terminal: Terminal;
before(function () {
let settingsEditor: SettingsEditor;
before(async function () {
const app = this.app as Application;
terminal = app.workbench.terminal;
settingsEditor = app.workbench.settingsEditor;
await setTerminalTestSettings(app);
});
after(async function () {
await settingsEditor.clearUserSettings();
});
it('clicking the plus button should create a terminal and display the tabs view showing no split decorations', async () => {
@@ -46,6 +55,7 @@ export function setup() {
it('should update icon of the tab in the tabs list', async () => {
await terminal.createTerminal();
await terminal.runCommand(TerminalCommandId.Split);
await terminal.waitForTerminalText(lines => lines.some(line => line.length > 0), undefined, 1);
const icon = 'symbol-method';
await terminal.runCommandWithValue(TerminalCommandIdWithValue.ChangeIcon, icon);
await terminal.assertTerminalGroups([[{}, { icon }]]);
@@ -58,7 +68,7 @@ export function setup() {
await terminal.assertSingleTab({ name });
});
it.skip('should reset the tab name to the default value when no name is provided', async () => { // https://github.com/microsoft/vscode/issues/146796
it('should reset the tab name to the default value when no name is provided', async () => {
await terminal.createTerminal();
const defaultName = await terminal.getSingleTabName();
const name = 'my terminal name';

View File

@@ -22,20 +22,12 @@ export function setup(logger: Logger) {
// Shared before/after handling
installAllHandlers(logger);
let app: Application;
let terminal: Terminal;
before(async function () {
// Fetch terminal automation API
const app = this.app as Application;
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"');
// Use the DOM renderer for smoke tests so they can be inspected in the playwright trace
// viewer
await app.workbench.settingsEditor.addUserSetting('terminal.integrated.gpuAcceleration', '"off"');
// Close the settings editor
await app.workbench.quickaccess.runCommand('workbench.action.closeAllEditors');
});
afterEach(async () => {

View File

@@ -5,7 +5,7 @@
import { join } from 'path';
import { Application, ApplicationOptions, Logger, Quality } from '../../../../automation';
import { createApp, timeout, installDiagnosticsHandler, installAppAfterHandler, getRandomUserDataDir, suiteLogsPath } from '../../utils';
import { createApp, timeout, installDiagnosticsHandler, installAppAfterHandler, getRandomUserDataDir, suiteLogsPath, suiteCrashPath } from '../../utils';
export function setup(ensureStableCode: () => string | undefined, logger: Logger) {
describe('Data Loss (insiders -> insiders)', () => {
@@ -19,7 +19,8 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger
it('verifies opened editors are restored', async function () {
app = createApp({
...this.defaultOptions,
logsPath: suiteLogsPath(this.defaultOptions, 'test_verifies_opened_editors_are_restored')
logsPath: suiteLogsPath(this.defaultOptions, 'test_verifies_opened_editors_are_restored'),
crashesPath: suiteCrashPath(this.defaultOptions, 'test_verifies_opened_editors_are_restored')
});
await app.start();
@@ -44,7 +45,8 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger
it('verifies editors can save and restore', async function () {
app = createApp({
...this.defaultOptions,
logsPath: suiteLogsPath(this.defaultOptions, 'test_verifies_editors_can_save_and_restore')
logsPath: suiteLogsPath(this.defaultOptions, 'test_verifies_editors_can_save_and_restore'),
crashesPath: suiteCrashPath(this.defaultOptions, 'test_verifies_editors_can_save_and_restore')
});
await app.start();
@@ -84,7 +86,8 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger
async function testHotExit(title: string, restartDelay: number | undefined, autoSave: boolean | undefined) {
app = createApp({
...this.defaultOptions,
logsPath: suiteLogsPath(this.defaultOptions, title)
logsPath: suiteLogsPath(this.defaultOptions, title),
crashesPath: suiteCrashPath(this.defaultOptions, title)
});
await app.start();
@@ -127,7 +130,7 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger
}
});
describe.skip('Data Loss (stable -> insiders)', () => { //TODO@bpasero enable again once we shipped 1.67.x
describe('Data Loss (stable -> insiders)', () => {
let insidersApp: Application | undefined = undefined;
let stableApp: Application | undefined = undefined;
@@ -153,12 +156,14 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger
const userDataDir = getRandomUserDataDir(this.defaultOptions);
const logsPath = suiteLogsPath(this.defaultOptions, 'test_verifies_opened_editors_are_restored_from_stable');
const crashesPath = suiteCrashPath(this.defaultOptions, 'test_verifies_opened_editors_are_restored_from_stable');
const stableOptions: ApplicationOptions = Object.assign({}, this.defaultOptions);
stableOptions.codePath = stableCodePath;
stableOptions.userDataDir = userDataDir;
stableOptions.quality = Quality.Stable;
stableOptions.logsPath = logsPath;
stableOptions.crashesPath = crashesPath;
stableApp = new Application(stableOptions);
await stableApp.start();
@@ -176,6 +181,7 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger
const insiderOptions: ApplicationOptions = Object.assign({}, this.defaultOptions);
insiderOptions.userDataDir = userDataDir;
insiderOptions.logsPath = logsPath;
insiderOptions.crashesPath = crashesPath;
insidersApp = new Application(insiderOptions);
await insidersApp.start();
@@ -205,12 +211,14 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger
const userDataDir = getRandomUserDataDir(this.defaultOptions);
const logsPath = suiteLogsPath(this.defaultOptions, title);
const crashesPath = suiteCrashPath(this.defaultOptions, title);
const stableOptions: ApplicationOptions = Object.assign({}, this.defaultOptions);
stableOptions.codePath = stableCodePath;
stableOptions.userDataDir = userDataDir;
stableOptions.quality = Quality.Stable;
stableOptions.logsPath = logsPath;
stableOptions.crashesPath = crashesPath;
stableApp = new Application(stableOptions);
await stableApp.start();
@@ -240,6 +248,7 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger
const insiderOptions: ApplicationOptions = Object.assign({}, this.defaultOptions);
insiderOptions.userDataDir = userDataDir;
insiderOptions.logsPath = logsPath;
insiderOptions.crashesPath = crashesPath;
insidersApp = new Application(insiderOptions);
await insidersApp.start();

View File

@@ -9,7 +9,6 @@ import { installAllHandlers } from '../../utils';
export function setup(logger: Logger) {
describe('Localization', () => {
// Shared before/after handling
installAllHandlers(logger);

View File

@@ -27,20 +27,8 @@ import { setup as setupDataStatusbarTests } from './areas/statusbar/statusbar.te
import { setup as setupDataExtensionTests } from './areas/extensions/extensions.test';
import { setup as setupDataMultirootTests } from './areas/multiroot/multiroot.test';
import { setup as setupDataLocalizationTests } from './areas/workbench/localization.test';
import { setup as setupLaunchTests } from './areas/workbench/launch.test';*/
const testDataPath = path.join(os.tmpdir(), 'vscsmoke');
if (fs.existsSync(testDataPath)) {
rimraf.sync(testDataPath);
}
fs.mkdirSync(testDataPath);
process.once('exit', () => {
try {
rimraf.sync(testDataPath);
} catch {
// noop
}
});
import { setup as setupLaunchTests } from './areas/workbench/launch.test';
import { setup as setupTaskTests } from './areas/task/task.test';*/
const [, , ...args] = process.argv;
const opts = minimist(args, {
@@ -64,6 +52,85 @@ const opts = minimist(args, {
default: {
verbose: false
}
}) as {
verbose?: boolean;
remote?: boolean;
headless?: boolean;
web?: boolean;
tracing?: boolean;
build?: string;
'stable-build'?: string;
browser?: string;
electronArgs?: string;
};
const logsRootPath = (() => {
const logsParentPath = path.join(rootPath, '.build', 'logs');
let logsName: string;
if (opts.web) {
logsName = 'smoke-tests-browser';
} else if (opts.remote) {
logsName = 'smoke-tests-remote';
} else {
logsName = 'smoke-tests-electron';
}
return path.join(logsParentPath, logsName);
})();
const crashesRootPath = (() => {
const crashesParentPath = path.join(rootPath, '.build', 'crashes');
let crashesName: string;
if (opts.web) {
crashesName = 'smoke-tests-browser';
} else if (opts.remote) {
crashesName = 'smoke-tests-remote';
} else {
crashesName = 'smoke-tests-electron';
}
return path.join(crashesParentPath, crashesName);
})();
const logger = createLogger();
function createLogger(): Logger {
const loggers: Logger[] = [];
// Log to console if verbose
if (opts.verbose) {
loggers.push(new ConsoleLogger());
}
// Prepare logs rot path
fs.rmSync(logsRootPath, { recursive: true, force: true, maxRetries: 3 });
mkdirp.sync(logsRootPath);
// Always log to log file
loggers.push(new FileLogger(path.join(logsRootPath, 'smoke-test-runner.log')));
return new MultiLogger(loggers);
}
try {
gracefulify(fs);
} catch (error) {
logger.log(`Error enabling graceful-fs: ${error}`);
}
const testDataPath = path.join(os.tmpdir(), 'vscsmoke');
if (fs.existsSync(testDataPath)) {
rimraf.sync(testDataPath);
}
mkdirp.sync(testDataPath);
process.once('exit', () => {
try {
rimraf.sync(testDataPath);
} catch {
// noop
}
});
const testRepoUrl = 'https://github.com/Microsoft/azuredatastudio-smoke-test-repo.git';
@@ -88,7 +155,10 @@ if (logPath) {
}
function fail(errorMessage): void {
console.error(errorMessage);
logger.log(errorMessage);
if (!opts.verbose) {
console.error(errorMessage);
}
process.exit(1);
}
@@ -102,6 +172,27 @@ function parseVersion(version: string): { major: number, minor: number, patch: n
return { major: parseInt(major), minor: parseInt(minor), patch: parseInt(patch) };
}
function parseQuality(): Quality {
if (process.env.VSCODE_DEV === '1') {
return Quality.Dev;
}
const quality = process.env.VSCODE_QUALITY ?? '';
switch (quality) {
case 'stable':
return Quality.Stable;
case 'insider':
return Quality.Insiders;
case 'exploration':
return Quality.Exploration;
case 'oss':
return Quality.OSS;
default:
return Quality.Dev;
}
}
//
// #### Electron Smoke Tests ####
//
@@ -167,13 +258,7 @@ if (!opts.web) {
fail(`Can't find VSCode at ${electronPath}.`);
}
if (process.env.VSCODE_DEV === '1') {
quality = Quality.Dev;
} else if (electronPath.indexOf('Code - Insiders') >= 0 /* macOS/Windows */ || electronPath.indexOf('code-insiders') /* Linux */ >= 0) {
quality = Quality.Insiders;
} else {
quality = Quality.Stable;
}
quality = parseQuality();
console.log(`Running desktop smoke tests against ${electronPath}`);
}
@@ -200,13 +285,11 @@ else {
console.log(`Running web smoke out of sources`);
}
if (process.env.VSCODE_DEV === '1') {
quality = Quality.Dev;
} else {
quality = Quality.Insiders;
}
quality = parseQuality();
}
logger.log(`VS Code product quality: ${quality}.`);
const userDataDir = path.join(testDataPath, 'd');
async function setupRepository(): Promise<void> {
@@ -317,11 +400,10 @@ function createOptions(): ApplicationOptions {
workspacePath,
userDataDir,
extensionsPath,
waitTime: parseInt(opts['wait-time'] || '0') || 20,
logger: new MultiLogger(loggers),
logger,
logsPath: path.join(logsRootPath, 'suite_unknown'),
crashesPath: path.join(crashesRootPath, 'suite_unknown'),
verbose: opts.verbose,
log,
screenshotsPath,
remote: opts.remote,
web: opts.web,
headless: opts.headless,
@@ -378,9 +460,9 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => {
setupDataLanguagesTests(opts);
setupDataEditorTests(opts);
setupDataStatusbarTests(opts);
setupDataExtensionTests(opts);
if (quality !== Quality.Dev) { setupExtensionTests(logger); }
if (!opts.web) { setupDataMultirootTests(opts); }
if (!opts.web) { setupDataLocalizationTests(opts); }
if (!opts.web && !opts.remote && quality !== Quality.Dev) { setupLocalizationTests(logger); }
if (!opts.web) { setupLaunchTests(); }
*/
});

View File

@@ -88,18 +88,24 @@ export function installDiagnosticsHandler(logger: Logger, appFn?: () => Applicat
}
let logsCounter = 1;
let crashCounter = 1;
export function suiteLogsPath(options: ApplicationOptions, suiteName: string): string {
return join(dirname(options.logsPath), `${logsCounter++}_suite_${suiteName.replace(/[^a-z0-9\-]/ig, '_')}`);
}
export function suiteCrashPath(options: ApplicationOptions, suiteName: string): string {
return join(dirname(options.crashesPath), `${crashCounter++}_suite_${suiteName.replace(/[^a-z0-9\-]/ig, '_')}`);
}
function installAppBeforeHandler(optionsTransform?: (opts: ApplicationOptions) => ApplicationOptions) {
before(async function () {
const suiteName = this.test?.parent?.title ?? 'unknown';
this.app = createApp({
...this.defaultOptions,
logsPath: suiteLogsPath(this.defaultOptions, suiteName)
logsPath: suiteLogsPath(this.defaultOptions, suiteName),
crashesPath: suiteCrashPath(this.defaultOptions, suiteName)
}, optionsTransform);
await this.app.start();
});