| // 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; |
| } |