Files
azuredatastudio/test/integration/browser/src/index.ts
Charles Gagnon 2bc6a0cd01 VS Code merge to df8fe74bd55313de0dd2303bc47a4aab0ca56b0e (#17979)
* Merge from vscode 504f934659740e9d41501cad9f162b54d7745ad9

* delete unused folders

* distro

* Bump build node version

* update chokidar

* FIx hygiene errors

* distro

* Fix extension lint issues

* Remove strict-vscode

* Add copyright header exemptions

* Bump vscode-extension-telemetry to fix webpacking issue with zone.js

* distro

* Fix failing tests (revert marked.js back to current one until we decide to update)

* Skip searchmodel test

* Fix mac build

* temp debug script loading

* Try disabling coverage

* log error too

* Revert "log error too"

This reverts commit af0183e5d4ab458fdf44b88fbfab9908d090526f.

* Revert "temp debug script loading"

This reverts commit 3d687d541c76db2c5b55626c78ae448d3c25089c.

* Add comments explaining coverage disabling

* Fix ansi_up loading issue

* Merge latest from ads

* Use newer option

* Fix compile

* add debug logging warn

* Always log stack

* log more

* undo debug

* Update to use correct base path (+cleanup)

* distro

* fix compile errors

* Remove strict-vscode

* Fix sql editors not showing

* Show db dropdown input & fix styling

* Fix more info in gallery

* Fix gallery asset requests

* Delete unused workflow

* Fix tapable resolutions for smoke test compile error

* Fix smoke compile

* Disable crash reporting

* Disable interactive

Co-authored-by: ADS Merger <karlb@microsoft.com>
2022-01-06 09:06:56 -08:00

164 lines
6.1 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as path from 'path';
import * as cp from 'child_process';
import * as playwright from 'playwright';
import * as url from 'url';
import * as tmp from 'tmp';
import * as rimraf from 'rimraf';
import { URI } from 'vscode-uri';
import * as kill from 'tree-kill';
import * as optimistLib from 'optimist';
import { StdioOptions } from 'node:child_process';
const optimist = optimistLib
.describe('workspacePath', 'path to the workspace (folder or *.code-workspace file) to open in the test').string('workspacePath')
.describe('extensionDevelopmentPath', 'path to the extension to test').string('extensionDevelopmentPath')
.describe('extensionTestsPath', 'path to the extension tests').string('extensionTestsPath')
.describe('debug', 'do not run browsers headless').boolean('debug')
.describe('browser', 'browser in which integration tests should run').string('browser').default('browser', 'chromium')
.describe('help', 'show the help').alias('help', 'h');
if (optimist.argv.help) {
optimist.showHelp();
process.exit(0);
}
const width = 1200;
const height = 800;
type BrowserType = 'chromium' | 'firefox' | 'webkit';
async function runTestsInBrowser(browserType: BrowserType, endpoint: url.UrlWithStringQuery, server: cp.ChildProcess): Promise<void> {
const browser = await playwright[browserType].launch({ headless: !Boolean(optimist.argv.debug) });
const context = await browser.newContext();
const page = await context.newPage();
await page.setViewportSize({ width, height });
page.on('pageerror', async error => console.error(`Playwright ERROR: page error: ${error}`));
page.on('crash', page => console.error('Playwright ERROR: page crash'));
page.on('response', async response => {
if (response.status() >= 400) {
console.error(`Playwright ERROR: HTTP status ${response.status()} for ${response.url()}`);
}
});
const host = endpoint.host;
const protocol = 'vscode-remote';
const testWorkspaceUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.workspacePath)).path, protocol, host, slashes: true });
const testExtensionUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionDevelopmentPath)).path, protocol, host, slashes: true });
const testFilesUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionTestsPath)).path, protocol, host, slashes: true });
const payloadParam = `[["extensionDevelopmentPath","${testExtensionUri}"],["extensionTestsPath","${testFilesUri}"],["enableProposedApi",""],["webviewExternalEndpointCommit","5319757634f77a050b49c10162939bfe60970c29"],["skipWelcome","true"]]`;
if (path.extname(testWorkspaceUri) === '.code-workspace') {
await page.goto(`${endpoint.href}&workspace=${testWorkspaceUri}&payload=${payloadParam}`);
} else {
await page.goto(`${endpoint.href}&folder=${testWorkspaceUri}&payload=${payloadParam}`);
}
await page.exposeFunction('codeAutomationLog', (type: string, args: any[]) => {
console[type](...args);
});
await page.exposeFunction('codeAutomationExit', async (code: number) => {
try {
await browser.close();
} catch (error) {
console.error(`Error when closing browser: ${error}`);
}
try {
await pkill(server.pid);
} catch (error) {
console.error(`Error when killing server process tree: ${error}`);
}
process.exit(code);
});
}
function pkill(pid: number): Promise<void> {
return new Promise((c, e) => {
kill(pid, error => error ? e(error) : c());
});
}
async function launchServer(browserType: BrowserType): Promise<{ endpoint: url.UrlWithStringQuery, server: cp.ChildProcess }> {
// Ensure a tmp user-data-dir is used for the tests
const tmpDir = tmp.dirSync({ prefix: 't' });
const testDataPath = tmpDir.name;
process.once('exit', () => rimraf.sync(testDataPath));
const userDataDir = path.join(testDataPath, 'd');
const env = {
VSCODE_AGENT_FOLDER: userDataDir,
VSCODE_BROWSER: browserType,
...process.env
};
const root = path.join(__dirname, '..', '..', '..', '..');
const logsPath = path.join(root, '.build', 'logs', 'integration-tests-browser');
const serverArgs = ['--browser', 'none', '--driver', 'web', '--enable-proposed-api', '--disable-telemetry'];
let serverLocation: string;
if (process.env.VSCODE_REMOTE_SERVER_PATH) {
serverLocation = path.join(process.env.VSCODE_REMOTE_SERVER_PATH, `server.${process.platform === 'win32' ? 'cmd' : 'sh'}`);
serverArgs.push(`--logsPath=${logsPath}`);
if (optimist.argv.debug) {
console.log(`Starting built server from '${serverLocation}'`);
console.log(`Storing log files into '${logsPath}'`);
}
} else {
serverLocation = path.join(root, `resources/server/web.${process.platform === 'win32' ? 'bat' : 'sh'}`);
serverArgs.push('--logsPath', logsPath);
process.env.VSCODE_DEV = '1';
if (optimist.argv.debug) {
console.log(`Starting server out of sources from '${serverLocation}'`);
console.log(`Storing log files into '${logsPath}'`);
}
}
const stdio: StdioOptions = optimist.argv.debug ? 'pipe' : ['ignore', 'pipe', 'ignore'];
let serverProcess = cp.spawn(
serverLocation,
serverArgs,
{ env, stdio }
);
if (optimist.argv.debug) {
serverProcess.stderr!.on('data', error => console.log(`Server stderr: ${error}`));
serverProcess.stdout!.on('data', data => console.log(`Server stdout: ${data}`));
}
process.on('exit', () => serverProcess.kill());
process.on('SIGINT', () => serverProcess.kill());
process.on('SIGTERM', () => serverProcess.kill());
return new Promise(c => {
serverProcess.stdout!.on('data', data => {
const matches = data.toString('ascii').match(/Web UI available at (.+)/);
if (matches !== null) {
c({ endpoint: url.parse(matches[1]), server: serverProcess });
}
});
});
}
launchServer(optimist.argv.browser).then(async ({ endpoint, server }) => {
return runTestsInBrowser(optimist.argv.browser, endpoint, server);
}, error => {
console.error(error);
process.exit(1);
});