vscode-extension-tester
Version:
ExTester is a package that is designed to help you run UI tests for your Visual Studio Code extensions using selenium-webdriver.
227 lines • 9.26 kB
JavaScript
;
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License", destination); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.VSRunner = void 0;
const browser_1 = require("../browser");
const fs = __importStar(require("fs-extra"));
const mocha_1 = __importDefault(require("mocha"));
const glob_1 = require("glob");
const path = __importStar(require("path"));
const yaml = __importStar(require("js-yaml"));
const sanitize_filename_1 = __importDefault(require("sanitize-filename"));
const selenium_webdriver_1 = require("selenium-webdriver");
const os = __importStar(require("os"));
const coverage_1 = require("../util/coverage");
/**
* Mocha runner wrapper
*/
class VSRunner {
mocha;
chromeBin;
customSettings;
codeVersion;
cleanup;
tmpLink = path.join(os.tmpdir(), 'extest-code');
releaseType;
constructor(bin, codeVersion, customSettings = {}, cleanup = false, releaseType, config) {
const conf = this.loadConfig(config);
this.mocha = new mocha_1.default(conf);
this.chromeBin = bin;
this.customSettings = customSettings;
this.codeVersion = codeVersion;
this.cleanup = cleanup;
this.releaseType = releaseType;
}
/**
* Set up mocha suite, add vscode instance handling, run tests
* @param testFilesPattern glob pattern of test files to run
* @param logLevel The logging level for the Webdriver
* @return The exit code of the mocha process
*/
runTests(testFilesPattern, code, logLevel = selenium_webdriver_1.logging.Level.INFO, resources) {
return new Promise((resolve) => {
const self = this;
const browser = new browser_1.VSBrowser(this.codeVersion, this.releaseType, this.customSettings, logLevel);
let coverage;
const testFiles = new Set();
for (const pattern of testFilesPattern) {
const universalPattern = pattern.replace(/'/g, '');
(0, glob_1.globSync)(universalPattern)
.reverse()
.forEach((val) => testFiles.add(val));
}
testFiles.forEach((file) => this.mocha.addFile(file));
this.mocha.suite.afterEach(async function () {
if (this.currentTest && this.currentTest.state !== 'passed') {
try {
const filename = (0, sanitize_filename_1.default)(this.currentTest.fullTitle());
await browser.takeScreenshot(filename);
}
catch (err) {
console.log('Screenshot capture failed.', err);
}
}
});
this.mocha.suite.beforeAll(async function () {
this.timeout(180000);
if (code.coverageEnabled) {
coverage = new coverage_1.Coverage();
await coverage.loadConfig();
process.env.NODE_V8_COVERAGE = coverage?.targetDir;
}
const start = Date.now();
const binPath = process.platform === 'darwin' ? await self.createShortcut(code.getCodeFolder(), self.tmpLink) : self.chromeBin;
await browser.start(binPath);
await browser.openResources(...resources);
await browser.waitForWorkbench();
await new Promise((res) => {
setTimeout(res, 3000);
});
console.log(`Browser ready in ${Date.now() - start} ms`);
console.log('Launching tests...');
});
this.mocha.suite.afterAll(async function () {
this.timeout(180000);
await browser.quit();
if (process.platform === 'darwin') {
if (await fs.pathExists(self.tmpLink)) {
try {
fs.unlinkSync(self.tmpLink);
}
catch (err) {
console.log(err);
}
}
}
if (code.coverageEnabled) {
await coverage?.write();
}
code.uninstallExtension(self.cleanup);
});
this.mocha.run((failures) => {
process.exitCode = failures ? 1 : 0;
if (process.exitCode) {
console.log('\x1b[33m%s\x1b[0m', `INFO: Screenshots of failures can be found in: ${browser.getScreenshotsDir()}\n`);
}
resolve(process.exitCode);
});
});
}
async createShortcut(src, dest) {
try {
await fs.ensureSymlink(src, dest, 'dir');
}
catch (err) {
return this.chromeBin;
}
const dir = path.parse(src);
const segments = this.chromeBin.split(path.sep);
const newSegments = dest.split(path.sep);
let found = false;
for (const segment of segments) {
if (!found) {
found = segment === dir.base;
}
else {
newSegments.push(segment);
}
}
return path.join(dir.root, ...newSegments);
}
loadConfig(config) {
const defaultFiles = ['.mocharc.js', '.mocharc.json', '.mocharc.yml', '.mocharc.yaml'];
let conf = {};
let file = config;
if (!config) {
file = path.resolve('.');
for (const defFile of defaultFiles) {
if (fs.existsSync(path.join(file, defFile))) {
file = path.join(file, defFile);
break;
}
}
}
if (file && fs.existsSync(file) && fs.statSync(file).isFile()) {
console.log(`Loading mocha configuration from ${file}`);
if (/\.(yml|yaml)$/.test(file)) {
try {
conf = yaml.load(fs.readFileSync(file, 'utf-8'));
}
catch (err) {
console.log('Invalid mocha configuration file, will be ignored');
}
}
else if (/\.(js|json)$/.test(file)) {
try {
conf = require(path.resolve(file));
}
catch (err) {
console.log('Invalid mocha configuration file, will be ignored');
}
}
else {
console.log('Unsupported mocha configuration file extension, make sure to use .js, .json, .yml or .yaml file');
}
}
if (process.env.MOCHA_GREP) {
conf.grep = process.env.MOCHA_GREP;
}
if (process.env.MOCHA_INVERT) {
conf.invert = process.env.MOCHA_INVERT === 'true';
}
return conf;
}
}
exports.VSRunner = VSRunner;
//# sourceMappingURL=runner.js.map