blob: 70dc9bf847da77ccc28f6535485727f85c42901d [file] [log] [blame]
// Karma configuration
// GENERATED BY Bazel
try
{
const fs = require('fs');
const path = require('path');
const tmp = require('tmp');
const child_process = require('child_process');
// Helper function to find a particular namedFile
// within the webTestMetadata webTestFiles
function findNamedFile(webTestMetadata, key) {
let result;
webTestMetadata['webTestFiles'].forEach(entry => {
const webTestNamedFiles = entry['namedFiles'];
if (webTestNamedFiles && webTestNamedFiles[key]) {
result = webTestNamedFiles[key];
}
});
return result;
}
// Helper function to extract a browser archive
// and return the path to extract executable
function extractWebArchive(extractExe, archiveFile, executablePath) {
try {
// Paths are relative to the root runfiles folder
extractExe = extractExe ? path.join('..', extractExe) : extractExe;
archiveFile = path.join('..', archiveFile);
const extractedExecutablePath = path.join(process.cwd(), executablePath);
if (!extractExe) {
throw new Error('No EXTRACT_EXE found');
}
child_process.execFileSync(
extractExe, [archiveFile, '.'],
{stdio: [process.stdin, process.stdout, process.stderr]});
return extractedExecutablePath;
} catch (e) {
console.error(`Failed to extract ${archiveFile}`);
throw e;
}
}
// Chrome on Linux uses sandboxing, which needs user namespaces to be enabled.
// This is not available on all kernels and it might be turned off even if it is available.
// Notable examples where user namespaces are not available include:
// - In Debian it is compiled-in but disabled by default.
// - The Docker daemon for Windows or OSX does not support user namespaces.
// We can detect if user namespaces are supported via /proc/sys/kernel/unprivileged_userns_clone.
// For more information see:
// https://github.com/Googlechrome/puppeteer/issues/290
// https://superuser.com/questions/1094597/enable-user-namespaces-in-debian-kernel#1122977
// https://github.com/karma-runner/karma-chrome-launcher/issues/158
// https://github.com/angular/angular/pull/24906
function supportsSandboxing() {
if (process.platform !== 'linux') {
return true;
}
try {
const res = child_process
.execSync('cat /proc/sys/kernel/unprivileged_userns_clone').toString().trim();
return res === '1';
} catch (error) { }
return false;
}
const browsers = [];
let customLaunchers = null;
// WEB_TEST_METADATA is configured in rules_webtesting based on value
// of the browsers attribute passed to ts_web_test_suite
// We setup the karma configuration based on the values in this object
if (process.env['WEB_TEST_METADATA']) {
const webTestMetadata = require(process.env['WEB_TEST_METADATA']);
if (webTestMetadata['environment'] === 'sauce') {
// If a sauce labs browser is chosen for the test such as
// "@io_bazel_rules_webtesting//browsers/sauce:chrome-win10"
// than the 'environment' will equal 'sauce'.
// We expect that a SAUCE_USERNAME and SAUCE_ACCESS_KEY is available
// from the environment for this test to run
if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) {
console.error('Make sure the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables are set.');
process.exit(1);
}
// 'capabilities' will specify the sauce labs configuration to use
const capabilities = webTestMetadata['capabilities'];
customLaunchers = {
'sauce': {
base: 'SauceLabs',
browserName: capabilities['browserName'],
platform: capabilities['platform'],
version: capabilities['version'],
}
};
browsers.push('sauce');
} else if (webTestMetadata['environment'] === 'local') {
// When a local chrome or firefox browser is chosen such as
// "@io_bazel_rules_webtesting//browsers:chromium-local" or
// "@io_bazel_rules_webtesting//browsers:firefox-local"
// then the 'environment' will equal 'local' and
// 'webTestFiles' will contain the path to the binary to use
const extractExe = findNamedFile(webTestMetadata, 'EXTRACT_EXE');
webTestMetadata['webTestFiles'].forEach(webTestFiles => {
const webTestNamedFiles = webTestFiles['namedFiles'];
const archiveFile = webTestFiles['archiveFile'];
if (webTestNamedFiles['CHROMIUM']) {
// When karma is configured to use Chrome it will look for a CHROME_BIN
// environment variable.
if (archiveFile) {
process.env.CHROME_BIN = extractWebArchive(extractExe, archiveFile, webTestNamedFiles['CHROMIUM']);
} else {
process.env.CHROME_BIN = require.resolve(webTestNamedFiles['CHROMIUM']);
}
const browser = process.env['DISPLAY'] ? 'Chrome' : 'ChromeHeadless';
if (!supportsSandboxing()) {
const launcher = 'CustomChromeWithoutSandbox';
customLaunchers = {
[launcher]: {
base: browser,
flags: ['--no-sandbox']
}
};
browsers.push(launcher);
} else {
browsers.push(browser);
}
}
if (webTestNamedFiles['FIREFOX']) {
// When karma is configured to use Firefox it will look for a
// FIREFOX_BIN environment variable.
if (archiveFile) {
process.env.FIREFOX_BIN = extractWebArchive(extractExe, archiveFile, webTestNamedFiles['FIREFOX']);
} else {
process.env.FIREFOX_BIN = require.resolve(webTestNamedFiles['FIREFOX']);
}
browsers.push(process.env['DISPLAY'] ? 'Firefox' : 'FirefoxHeadless');
}
});
} else {
console.warn(`Unknown WEB_TEST_METADATA environment '${webTestMetadata['environment']}'`);
}
}
// Fallback to using the system local chrome if no valid browsers have been
// configured above
if (!browsers.length) {
console.warn('No browsers configured. Configuring Karma to use system Chrome.');
browsers.push(process.env['DISPLAY'] ? 'Chrome': 'ChromeHeadless');
}
const proxies = {};
const files = [
TMPL_bootstrap_files
TMPL_user_files
].map(f => {
if (f.startsWith('NODE_MODULES/')) {
try {
// attempt to resolve in @bazel/karma nested node_modules first
return require.resolve(f.replace(/^NODE_MODULES\//, '@bazel/karma/node_modules/'));
} catch (e) {
// if that failed then attempt to resolve in root node_modules
return require.resolve(f.replace(/^NODE_MODULES\//, ''));
}
} else {
return require.resolve(f);
}
});
// static files are added to the files array but
// configured to not be included so karma-concat-js does
// not included them in the bundle
[TMPL_static_files].forEach((f) => {
// In Windows, the runfile will probably not be symlinked. Se we need to
// serve the real file through karma, and proxy calls to the expected file
// location in the runfiles to the real file.
const resolvedFile = require.resolve(f);
files.push({pattern: resolvedFile, included: false});
// Prefixing the proxy path with '/absolute' allows karma to load local
// files. This doesn't see to be an official API.
// https://github.com/karma-runner/karma/issues/2703
proxies['/base/' + f] = '/absolute' + resolvedFile;
});
var requireConfigContent = `
// A simplified version of Karma's requirejs.config.tpl.js for use with Karma under Bazel.
// This does an explicit \`require\` on each test script in the files, otherwise nothing will be loaded.
(function(){
var runtimeFiles = [TMPL_runtime_files].map(function(file) { return file.replace(/\\.js$/, ''); });
var allFiles = [TMPL_user_files];
var allTestFiles = [];
allFiles.forEach(function (file) {
if (/[^a-zA-Z0-9](spec|test)\\.js$/i.test(file) && !/\\/node_modules\\//.test(file)) {
allTestFiles.push(file.replace(/\\.js$/, ''))
}
});
require(runtimeFiles, function() { return require(allTestFiles, window.__karma__.start); });
})();
`;
const requireConfigFile = tmp.fileSync(
{keep: false, postfix: '.js', dir: process.env['TEST_TMPDIR']});
fs.writeFileSync(requireConfigFile.name, requireConfigContent);
files.push(requireConfigFile.name);
module.exports = function(config) {
const configuration = {
// list of karma plugins
plugins: [
'karma-*',
'@bazel/karma',
'karma-sourcemap-loader',
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-sauce-launcher',
],
// list of karma preprocessors
preprocessors: {'**/*.js': ['sourcemap']},
// list of test frameworks to use
frameworks: ['jasmine', 'concat_js'],
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR ||
// config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file
// changes
autoWatch: true,
// start these browsers
// available browser launchers:
// https://npmjs.org/browse/keyword/karma-launcher
browsers: browsers,
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
// note: run_karma.sh may override this as a command-line option.
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity,
// base path that will be used to resolve all patterns (eg. files,
// exclude)
basePath: 'TMPL_runfiles_path',
// list of files passed to karma; these are concatenated into a single
// file by karma-concat-js
files,
proxies,
}
if (process.env['IBAZEL_NOTIFY_CHANGES'] === 'y') {
// Tell karma to only listen for ibazel messages on stdin rather than
// watch all the input files This is from fork alexeagle/karma in the
// ibazel branch:
// https://github.com/alexeagle/karma/blob/576d262af50b10e63485b86aee99c5358958c4dd/lib/server.js#L172
configuration.watchMode = 'ibazel';
}
// Extra configuration is needed for saucelabs
// See: https://github.com/karma-runner/karma-sauce-launcher
if (customLaunchers) {
// set the test name for sauce labs to use
// TEST_BINARY is set by Bazel and contains the name of the test
// target posfixed with the the browser name such as
// 'examples/testing/testing_sauce_chrome-win10' for the
// test target examples/testing:testing
configuration.sauceLabs = {
testName: process.env['TEST_BINARY'] || 'ts_web_test_suite'
};
// setup the custom launchers for saucelabs
configuration.customLaunchers = customLaunchers;
// add the saucelabs reporter
configuration.reporters.push('saucelabs');
}
config.set(configuration);
}
} catch (e) {
console.error('Error in karma configuration', e.toString());
throw e;
}