mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 09:08:48 +01:00
tests - browser tests to go through new log service
This commit is contained in:
@@ -14,7 +14,7 @@ const webviewId = 'myWebview';
|
|||||||
const testDocument = join(vscode.workspace.rootPath || '', './bower.json');
|
const testDocument = join(vscode.workspace.rootPath || '', './bower.json');
|
||||||
|
|
||||||
// TODO: Re-enable after https://github.com/microsoft/vscode/issues/88415
|
// TODO: Re-enable after https://github.com/microsoft/vscode/issues/88415
|
||||||
suite.skip('Webview tests', () => {
|
('electron' in process.versions ? suite.skip : suite)('Webview tests', () => {
|
||||||
const disposables: vscode.Disposable[] = [];
|
const disposables: vscode.Disposable[] = [];
|
||||||
|
|
||||||
function _register<T extends vscode.Disposable>(disposable: T) {
|
function _register<T extends vscode.Disposable>(disposable: T) {
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { ILogService, DEFAULT_LOG_LEVEL, LogLevel, LogServiceAdapter } from 'vs/platform/log/common/log';
|
||||||
|
|
||||||
|
interface IAutomatedWindow {
|
||||||
|
codeAutomationLog(type: string, args: any[]): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A logger that is used when VSCode is running in the web with
|
||||||
|
* an automation such as playwright. We expect a global codeAutomationLog
|
||||||
|
* to be defined that we can use to log to.
|
||||||
|
*/
|
||||||
|
export class ConsoleLogInAutomationService extends LogServiceAdapter implements ILogService {
|
||||||
|
|
||||||
|
declare codeAutomationLog: any;
|
||||||
|
|
||||||
|
_serviceBrand: undefined;
|
||||||
|
|
||||||
|
constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
|
||||||
|
super({ consoleLog: (type, args) => this.consoleLog(type, args) }, logLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private consoleLog(type: string, args: any[]): void {
|
||||||
|
const automatedWindow = window as unknown as IAutomatedWindow;
|
||||||
|
if (typeof automatedWindow.codeAutomationLog === 'function') {
|
||||||
|
automatedWindow.codeAutomationLog(type, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -213,48 +213,48 @@ export class ConsoleLogService extends AbstractLogService implements ILogService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ConsoleLogInMainService extends AbstractLogService implements ILogService {
|
export class LogServiceAdapter extends AbstractLogService implements ILogService {
|
||||||
|
|
||||||
_serviceBrand: undefined;
|
_serviceBrand: undefined;
|
||||||
|
|
||||||
constructor(private readonly client: LoggerChannelClient, logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
|
constructor(private readonly adapter: { consoleLog: (type: string, args: any[]) => void }, logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
|
||||||
super();
|
super();
|
||||||
this.setLevel(logLevel);
|
this.setLevel(logLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
trace(message: string, ...args: any[]): void {
|
trace(message: string, ...args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Trace) {
|
if (this.getLevel() <= LogLevel.Trace) {
|
||||||
this.client.consoleLog('trace', [this.extractMessage(message), ...args]);
|
this.adapter.consoleLog('trace', [this.extractMessage(message), ...args]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug(message: string, ...args: any[]): void {
|
debug(message: string, ...args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Debug) {
|
if (this.getLevel() <= LogLevel.Debug) {
|
||||||
this.client.consoleLog('debug', [this.extractMessage(message), ...args]);
|
this.adapter.consoleLog('debug', [this.extractMessage(message), ...args]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info(message: string, ...args: any[]): void {
|
info(message: string, ...args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Info) {
|
if (this.getLevel() <= LogLevel.Info) {
|
||||||
this.client.consoleLog('info', [this.extractMessage(message), ...args]);
|
this.adapter.consoleLog('info', [this.extractMessage(message), ...args]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
warn(message: string | Error, ...args: any[]): void {
|
warn(message: string | Error, ...args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Warning) {
|
if (this.getLevel() <= LogLevel.Warning) {
|
||||||
this.client.consoleLog('warn', [this.extractMessage(message), ...args]);
|
this.adapter.consoleLog('warn', [this.extractMessage(message), ...args]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error(message: string | Error, ...args: any[]): void {
|
error(message: string | Error, ...args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Error) {
|
if (this.getLevel() <= LogLevel.Error) {
|
||||||
this.client.consoleLog('error', [this.extractMessage(message), ...args]);
|
this.adapter.consoleLog('error', [this.extractMessage(message), ...args]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
critical(message: string | Error, ...args: any[]): void {
|
critical(message: string | Error, ...args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Critical) {
|
if (this.getLevel() <= LogLevel.Critical) {
|
||||||
this.client.consoleLog('critical', [this.extractMessage(message), ...args]);
|
this.adapter.consoleLog('critical', [this.extractMessage(message), ...args]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,6 +275,15 @@ export class ConsoleLogInMainService extends AbstractLogService implements ILogS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ConsoleLogInMainService extends LogServiceAdapter implements ILogService {
|
||||||
|
|
||||||
|
_serviceBrand: undefined;
|
||||||
|
|
||||||
|
constructor(client: LoggerChannelClient, logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
|
||||||
|
super({ consoleLog: (type, args) => client.consoleLog(type, args) }, logLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class MultiplexLogService extends AbstractLogService implements ILogService {
|
export class MultiplexLogService extends AbstractLogService implements ILogService {
|
||||||
_serviceBrand: undefined;
|
_serviceBrand: undefined;
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { mark } from 'vs/base/common/performance';
|
|||||||
import { domContentLoaded, addDisposableListener, EventType, addClass, EventHelper } from 'vs/base/browser/dom';
|
import { domContentLoaded, addDisposableListener, EventType, addClass, EventHelper } from 'vs/base/browser/dom';
|
||||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||||
import { ILogService, ConsoleLogService, MultiplexLogService } from 'vs/platform/log/common/log';
|
import { ILogService, ConsoleLogService, MultiplexLogService } from 'vs/platform/log/common/log';
|
||||||
|
import { ConsoleLogInAutomationService } from 'vs/platform/log/browser/log';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
||||||
import { Workbench } from 'vs/workbench/browser/workbench';
|
import { Workbench } from 'vs/workbench/browser/workbench';
|
||||||
@@ -49,6 +50,7 @@ import { IndexedDBLogProvider } from 'vs/workbench/services/log/browser/indexedD
|
|||||||
import { InMemoryLogProvider } from 'vs/workbench/services/log/common/inMemoryLogProvider';
|
import { InMemoryLogProvider } from 'vs/workbench/services/log/common/inMemoryLogProvider';
|
||||||
import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows';
|
import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows';
|
||||||
import { getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces';
|
import { getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces';
|
||||||
|
import { coalesce } from 'vs/base/common/arrays';
|
||||||
|
|
||||||
class BrowserMain extends Disposable {
|
class BrowserMain extends Disposable {
|
||||||
|
|
||||||
@@ -234,9 +236,12 @@ class BrowserMain extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const consoleLogService = new ConsoleLogService(logService.getLevel());
|
logService.logger = new MultiplexLogService(coalesce([
|
||||||
const fileLogService = new FileLogService('window', environmentService.logFile, logService.getLevel(), fileService);
|
new ConsoleLogService(logService.getLevel()),
|
||||||
logService.logger = new MultiplexLogService([consoleLogService, fileLogService]);
|
new FileLogService('window', environmentService.logFile, logService.getLevel(), fileService),
|
||||||
|
// Extension development test CLI: forward everything to test runner
|
||||||
|
environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI ? new ConsoleLogInAutomationService(logService.getLevel()) : undefined
|
||||||
|
]));
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const connection = remoteAgentService.getConnection();
|
const connection = remoteAgentService.getConnection();
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ export async function launch(userDataDir: string, _workspacePath: string, codeSe
|
|||||||
['--browser', 'none', '--driver', 'web'],
|
['--browser', 'none', '--driver', 'web'],
|
||||||
{ env }
|
{ env }
|
||||||
);
|
);
|
||||||
server.stderr?.on('data', e => console.log('Server stderr: ' + e));
|
server.stderr?.on('data', error => console.log(`Server stderr: ${error}`));
|
||||||
server.stdout?.on('data', e => console.log('Server stdout: ' + e));
|
server.stdout?.on('data', data => console.log(`Server stdout: ${data}`));
|
||||||
process.on('exit', teardown);
|
process.on('exit', teardown);
|
||||||
process.on('SIGINT', teardown);
|
process.on('SIGINT', teardown);
|
||||||
process.on('SIGTERM', teardown);
|
process.on('SIGTERM', teardown);
|
||||||
@@ -148,7 +148,7 @@ export function connect(headless: boolean, engine: 'chromium' | 'webkit' | 'fire
|
|||||||
await page.setViewport({ width, height });
|
await page.setViewport({ width, height });
|
||||||
await page.goto(`${endpoint}&folder=vscode-remote://localhost:9888${URI.file(workspacePath!).path}`);
|
await page.goto(`${endpoint}&folder=vscode-remote://localhost:9888${URI.file(workspacePath!).path}`);
|
||||||
const result = {
|
const result = {
|
||||||
client: { dispose: () => teardown() },
|
client: { dispose: () => browser.close() && teardown() },
|
||||||
driver: buildDriver(browser, page)
|
driver: buildDriver(browser, page)
|
||||||
};
|
};
|
||||||
c(result);
|
c(result);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"@types/mkdirp": "0.5.1",
|
"@types/mkdirp": "0.5.1",
|
||||||
"@types/node": "^12.11.7",
|
"@types/node": "^12.11.7",
|
||||||
"@types/rimraf": "2.0.2",
|
"@types/rimraf": "2.0.2",
|
||||||
|
"@types/tmp": "^0.1.0",
|
||||||
"rimraf": "^2.6.1",
|
"rimraf": "^2.6.1",
|
||||||
"tmp": "0.0.33",
|
"tmp": "0.0.33",
|
||||||
"typescript": "3.7.5"
|
"typescript": "3.7.5"
|
||||||
|
|||||||
@@ -15,18 +15,13 @@ const optimist = require('optimist')
|
|||||||
.describe('browser', 'browser in which integration tests should run').string('browser').default('browser', 'chromium')
|
.describe('browser', 'browser in which integration tests should run').string('browser').default('browser', 'chromium')
|
||||||
.describe('help', 'show the help').alias('help', 'h');
|
.describe('help', 'show the help').alias('help', 'h');
|
||||||
|
|
||||||
let serverProcess: cp.ChildProcess | undefined = undefined;
|
const width = 1200;
|
||||||
|
const height = 800;
|
||||||
function teardownServer() {
|
|
||||||
if (serverProcess) {
|
|
||||||
serverProcess.kill();
|
|
||||||
serverProcess = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function runTestsInBrowser(browserType: string, endpoint: string): Promise<void> {
|
async function runTestsInBrowser(browserType: string, endpoint: string): Promise<void> {
|
||||||
const browser = await playwright[browserType].launch({ headless: !Boolean(optimist.argv.debug) });
|
const browser = await playwright[browserType].launch({ headless: !Boolean(optimist.argv.debug) });
|
||||||
const page = (await browser.defaultContext().pages())[0];
|
const page = (await browser.defaultContext().pages())[0];
|
||||||
|
await page.setViewport({ width, height });
|
||||||
|
|
||||||
const host = url.parse(endpoint).host;
|
const host = url.parse(endpoint).host;
|
||||||
const protocol = 'vscode-remote';
|
const protocol = 'vscode-remote';
|
||||||
@@ -41,24 +36,22 @@ async function runTestsInBrowser(browserType: string, endpoint: string): Promise
|
|||||||
|
|
||||||
await page.goto(`${endpoint}&folder=${folderParam}&payload=${payloadParam}`);
|
await page.goto(`${endpoint}&folder=${folderParam}&payload=${payloadParam}`);
|
||||||
|
|
||||||
// const emitter = new events.EventEmitter();
|
await page.exposeFunction('codeAutomationLog', (type: string, args: any[]) => {
|
||||||
// await page.exposeFunction('mocha_report', (type, data1, data2) => {
|
console[type](...args);
|
||||||
// emitter.emit(type, data1, data2)
|
});
|
||||||
// });
|
|
||||||
|
|
||||||
page.on('console', async (msg: playwright.ConsoleMessage) => {
|
page.on('console', async (msg: playwright.ConsoleMessage) => {
|
||||||
const msgText = msg.text();
|
const msgText = msg.text();
|
||||||
console[msg.type()](msgText, await Promise.all(msg.args().map(async arg => await arg.jsonValue())));
|
|
||||||
|
|
||||||
if (msgText.indexOf('vscode:exit') >= 0) {
|
if (msgText.indexOf('vscode:exit') >= 0) {
|
||||||
browser.close();
|
await browser.close();
|
||||||
teardownServer();
|
process.exit(msgText === 'vscode:exit 0' ? 0 : 1);
|
||||||
setTimeout(() => process.exit(msgText === 'vscode:exit 0' ? 0 : 1), 10);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function launchServer(): Promise<string> {
|
async function launchServer(): Promise<string> {
|
||||||
|
|
||||||
|
// Ensure a tmp user-data-dir is used for the tests
|
||||||
const tmpDir = tmp.dirSync({ prefix: 't' });
|
const tmpDir = tmp.dirSync({ prefix: 't' });
|
||||||
const testDataPath = tmpDir.name;
|
const testDataPath = tmpDir.name;
|
||||||
process.once('exit', () => rimraf.sync(testDataPath));
|
process.once('exit', () => rimraf.sync(testDataPath));
|
||||||
@@ -70,7 +63,7 @@ async function launchServer(): Promise<string> {
|
|||||||
...process.env
|
...process.env
|
||||||
};
|
};
|
||||||
|
|
||||||
let serverLocation;
|
let serverLocation: string;
|
||||||
if (process.env.VSCODE_REMOTE_SERVER_PATH) {
|
if (process.env.VSCODE_REMOTE_SERVER_PATH) {
|
||||||
serverLocation = path.join(process.env.VSCODE_REMOTE_SERVER_PATH, `server.${process.platform === 'win32' ? 'cmd' : 'sh'}`);
|
serverLocation = path.join(process.env.VSCODE_REMOTE_SERVER_PATH, `server.${process.platform === 'win32' ? 'cmd' : 'sh'}`);
|
||||||
} else {
|
} else {
|
||||||
@@ -79,24 +72,33 @@ async function launchServer(): Promise<string> {
|
|||||||
process.env.VSCODE_DEV = '1';
|
process.env.VSCODE_DEV = '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
serverProcess = cp.spawn(
|
let serverProcess = cp.spawn(
|
||||||
serverLocation,
|
serverLocation,
|
||||||
['--browser', 'none', '--driver', 'web'],
|
['--browser', 'none', '--driver', 'web'],
|
||||||
{ env }
|
{ env }
|
||||||
);
|
);
|
||||||
|
|
||||||
serverProcess?.stderr?.on('data', e => console.log(`Server stderr: ${e}`));
|
serverProcess?.stderr?.on('data', error => console.log(`Server stderr: ${error}`));
|
||||||
serverProcess?.stdout?.on('data', e => console.log(`Server stdout: ${e}`));
|
|
||||||
|
if (optimist.argv.debug) {
|
||||||
|
serverProcess?.stdout?.on('data', data => console.log(`Server stdout: ${data}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
function teardownServer() {
|
||||||
|
if (serverProcess) {
|
||||||
|
serverProcess.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
process.on('exit', teardownServer);
|
process.on('exit', teardownServer);
|
||||||
process.on('SIGINT', teardownServer);
|
process.on('SIGINT', teardownServer);
|
||||||
process.on('SIGTERM', teardownServer);
|
process.on('SIGTERM', teardownServer);
|
||||||
|
|
||||||
return new Promise(r => {
|
return new Promise(c => {
|
||||||
serverProcess?.stdout?.on('data', d => {
|
serverProcess?.stdout?.on('data', data => {
|
||||||
const matches = d.toString('ascii').match(/Web UI available at (.+)/);
|
const matches = data.toString('ascii').match(/Web UI available at (.+)/);
|
||||||
if (matches !== null) {
|
if (matches !== null) {
|
||||||
r(matches[1]);
|
c(matches[1]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,6 +46,11 @@
|
|||||||
"@types/glob" "*"
|
"@types/glob" "*"
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/tmp@^0.1.0":
|
||||||
|
version "0.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.1.0.tgz#19cf73a7bcf641965485119726397a096f0049bd"
|
||||||
|
integrity sha512-6IwZ9HzWbCq6XoQWhxLpDjuADodH/MKXRUIDFudvgjcVdjFknvmR+DNsoUeer4XPrEnrZs04Jj+kfV9pFsrhmA==
|
||||||
|
|
||||||
balanced-match@^1.0.0:
|
balanced-match@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||||
|
|||||||
Reference in New Issue
Block a user