index.ts 3.9 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

6 7 8 9 10 11
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';
12 13 14 15 16 17

const optimist = require('optimist')
	.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');

18
let serverProcess: cp.ChildProcess | undefined = undefined;
19 20 21 22 23 24 25 26

function teardownServer() {
	if (serverProcess) {
		serverProcess.kill();
		serverProcess = undefined;
	}
}

27 28
async function runTestsInBrowser(browserType: string, endpoint: string): Promise<void> {
	const browser = await playwright[browserType].launch({ headless: !Boolean(optimist.argv.debug) });
29 30
	const page = (await browser.defaultContext().pages())[0];

31 32 33 34 35 36 37
	const host = url.parse(endpoint).host;
	const protocol = 'vscode-remote';

	const integrationTestsPath = path.join(__dirname, '..', '..', '..', '..', 'extensions', 'vscode-api-tests');
	const testWorkspaceUri = url.format({ pathname: path.join(integrationTestsPath, 'testWorkspace'), protocol, host, slashes: true });
	const testExtensionUri = url.format({ pathname: path.join(integrationTestsPath), protocol, host, slashes: true });
	const testFilesUri = url.format({ pathname: path.join(integrationTestsPath, 'out', 'singlefolder-tests'), protocol, host, slashes: true });
38 39 40 41 42 43 44 45 46 47 48

	const folderParam = testWorkspaceUri;
	const payloadParam = `[["extensionDevelopmentPath","${testExtensionUri}"],["extensionTestsPath","${testFilesUri}"]]`;

	await page.goto(`${endpoint}&folder=${folderParam}&payload=${payloadParam}`);

	// const emitter = new events.EventEmitter();
	// await page.exposeFunction('mocha_report', (type, data1, data2) => {
	// 	emitter.emit(type, data1, data2)
	// });

49
	page.on('console', async (msg: playwright.ConsoleMessage) => {
50 51 52 53 54 55 56 57 58 59 60
		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) {
			browser.close();
			teardownServer();
			setTimeout(() => process.exit(msgText === 'vscode:exit 0' ? 0 : 1), 10);
		}
	});
}

61 62 63 64 65 66 67
async function launchServer(): Promise<string> {
	const tmpDir = tmp.dirSync({ prefix: 't' });
	const testDataPath = tmpDir.name;
	process.once('exit', () => rimraf.sync(testDataPath));

	const userDataDir = path.join(testDataPath, 'd');

68
	const env = {
69
		VSCODE_AGENT_FOLDER: userDataDir,
70 71 72 73 74 75 76
		...process.env
	};

	let serverLocation;
	if (process.env.VSCODE_REMOTE_SERVER_PATH) {
		serverLocation = path.join(process.env.VSCODE_REMOTE_SERVER_PATH, `server.${process.platform === 'win32' ? 'cmd' : 'sh'}`);
	} else {
77 78 79
		serverLocation = path.join(__dirname, '..', '..', '..', '..', `resources/server/web.${process.platform === 'win32' ? 'bat' : 'sh'}`);

		process.env.VSCODE_DEV = '1';
80 81 82 83 84 85 86 87
	}

	serverProcess = cp.spawn(
		serverLocation,
		['--browser', 'none', '--driver', 'web'],
		{ env }
	);

88 89
	serverProcess?.stderr?.on('data', e => console.log(`Server stderr: ${e}`));
	serverProcess?.stdout?.on('data', e => console.log(`Server stdout: ${e}`));
90 91 92 93 94 95

	process.on('exit', teardownServer);
	process.on('SIGINT', teardownServer);
	process.on('SIGTERM', teardownServer);

	return new Promise(r => {
96
		serverProcess?.stdout?.on('data', d => {
97 98 99 100 101 102 103 104
			const matches = d.toString('ascii').match(/Web UI available at (.+)/);
			if (matches !== null) {
				r(matches[1]);
			}
		});
	});
}

105 106
launchServer().then(async endpoint => {
	return runTestsInBrowser(optimist.argv.browser, endpoint);
107
}, console.error);