@fpjs-incubator/broyster
Version:
195 lines (194 loc) • 11.2 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeKarmaConfigurator = void 0;
const tslib_1 = require("tslib");
const path = require("path");
const fs_1 = require("fs");
const arguments_1 = require("./arguments");
const karma_plugin_1 = require("./karma_plugin");
const karma_https_config_1 = require("./karma_https_config");
/**
* Makes a function that applies an opinionated configuration, used by Fingerprint's projects, to Karma.
*
* When a Karma configuration file is created, add `--preset local`, `--preset browserstack` or
* `--preset browserstack-beta` to the Karma command to choose where to run the tests.
*
* @example karma.conf.ts in the project's root directory
* module.exports = makeKarmaConfigurator({ ... })
*
* @example Run tests in the local browsers
* karma start --preset local --single-run
*/
function makeKarmaConfigurator(options) {
return (karmaConfig) => tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a;
switch (karmaConfig.preset) {
case 'local':
yield setupLocal(karmaConfig, options);
break;
case 'browserstack':
yield setupBrowserstack(karmaConfig, options);
break;
case 'browserstack-beta':
yield setupBrowserstack(karmaConfig, options, true);
break;
default:
throw new Error('No --preset option is set or an unknown value is set');
}
yield ((_a = options.configureCustom) === null || _a === void 0 ? void 0 : _a.call(options, karmaConfig));
});
}
exports.makeKarmaConfigurator = makeKarmaConfigurator;
function setupLocal(karmaConfig, { alwaysRetryTests = false, includeFiles = [], tsconfigPath = 'tsconfig.json' }) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const createdFiles = yield createFilesToInject();
const files = [];
if (process.env.CI || alwaysRetryTests) {
files.push(createdFiles.setupJasmineRetries);
}
files.push(...includeFiles);
karmaConfig.set({
frameworks: ['jasmine', 'karma-typescript'],
files,
preprocessors: {
'**/*.ts': 'karma-typescript',
},
reporters: ['spec', 'summary'],
browsers: ['ChromeHeadless', 'FirefoxHeadless'],
concurrency: 3,
karmaTypescriptConfig: {
tsconfig: tsconfigPath,
compilerOptions: {
module: 'commonjs',
sourceMap: true,
},
// The `include` and `exclude` options of tsconfig.json are not inherited, because every given `includeFiles` file
// must be compiled, and it makes no sense to compile anything else.
include: {
mode: 'replace',
values: files.filter((file) => typeof file === 'string' && /(\*|\.ts)$/.test(file)),
},
exclude: { mode: 'replace', values: [] },
},
specReporter: {
suppressSummary: true,
suppressErrorSummary: true,
suppressPassed: true,
suppressSkipped: true,
},
});
});
}
function setupBrowserstack(karmaConfig, options, onlyBetaBrowsers = false) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
yield setupLocal(karmaConfig, options);
const customLaunchers = {};
for (const [key, data] of Object.entries(browserstackBrowsers)) {
if (onlyBetaBrowsers && !('browserVersion' in data && /beta/i.test(data.browserVersion))) {
continue;
}
customLaunchers[key] = Object.assign({ base: 'BrowserStack', name: key.replace(/_/g, ' ') }, data);
}
karmaConfig.set({
reporters: [...(karmaConfig.reporters || []), 'BrowserStack'],
plugins: [...(karmaConfig.plugins || []), karma_plugin_1.default],
browsers: Object.keys(customLaunchers),
customLaunchers,
concurrency: 5,
retryLimit: 3,
captureTimeout: 15000,
browserDisconnectTolerance: 2,
browserDisconnectTimeout: 15000,
browserStack: {
project: options.projectName,
// A build number is required to group testing sessions in the BrowserStack UI.
// GitHub Actions will add a value for GITHUB_RUN_ID. More on the environment variables:
// https://docs.github.com/en/free-pro-team@latest/actions/reference/environment-variables#default-environment-variables
build: process.env.GITHUB_RUN_ID || makeBuildNumber(),
// The timeout is reduced for testing sessions to not hold the BrowserStack queue long in case of problems.
idleTimeout: 20000,
queueTimeout: 300000,
},
});
(0, karma_https_config_1.setHttpsAndServerForKarma)(karmaConfig);
});
}
function createFilesToInject() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
// `package.json` is imported using `require` to prevent TypeScript from putting it into `dist`
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { name: packageName } = require('../package.json');
// The injected files must be within the current working directory, otherwise karma-typescript won't compile them
const temporaryDirectory = path.join('node_modules', '.tmp', packageName);
yield fs_1.promises.mkdir(temporaryDirectory, { recursive: true });
const filesToCreate = {
setupJasmineRetries: {
name: 'setup_jasmine_retries.ts',
content: `import { retryFailedTests } from '${packageName}/browser'; retryFailedTests(3, 100)`,
},
};
const createdFiles = {};
yield Promise.all(Object.keys(filesToCreate).map((id) => tslib_1.__awaiter(this, void 0, void 0, function* () {
createdFiles[id] = path.join(temporaryDirectory, filesToCreate[id].name);
yield fs_1.promises.writeFile(createdFiles[id], filesToCreate[id].content);
})));
return createdFiles;
});
}
// The shapes of these objects are taken from:
// https://github.com/SeleniumHQ/selenium/tree/d8ddb4d83972df0f565ef65264bcb733e7a94584/javascript/node/selenium-webdriver
// It doesn't work, trying to work it out with BrowserStack support.
/*
const chromeIncognitoCapabilities = {
'goog:chromeOptions': {
args: ['--incognito'],
},
}
const firefoxIncognitoCapabilities = {
'moz:firefoxOptions': {
prefs: {
'browser.privatebrowsing.autostart': true,
},
},
}
*/
/*
* You can find values for any supported browsers in the interactive form at
* https://www.browserstack.com/docs/automate/javascript-testing/configure-test-run-options
* The keys are arbitrary values.
*
* Only Chrome is supported on Android, only Safari is supported on iOS: https://www.browserstack.com/question/659
*/
/* eslint-disable max-len */
// prettier-ignore
const browserstackBrowsers = {
Windows10_Chrome73: { platform: 'Windows', osVersion: '10', browserName: 'Chrome', browserVersion: '73', useHttps: true },
// Windows10_Chrome73_Incognito: { platform: 'Windows', osVersion: '10', browserName: 'Chrome', browserVersion: '73', ...chromeIncognitoCapabilities },
Windows11_ChromeLatest: { platform: 'Windows', osVersion: '11', browserName: 'Chrome', browserVersion: 'latest-beta', useHttps: true },
// Windows11_ChromeLatest_Incognito: { platform: 'Windows', osVersion: '11', browserName: 'Chrome', browserVersion: 'latest-beta, ...chromeIncognitoCapabilities },
Windows10_Firefox89: { platform: 'Windows', osVersion: '10', browserName: 'Firefox', browserVersion: '89', useHttps: true, firefoxCapabilities: [['security.csp.enable', true]] },
// Windows10_Firefox89_Incognito: { platform: 'Windows', osVersion: '10', browserName: 'Firefox', browserVersion: '89', ...firefoxIncognitoCapabilities },
Windows11_FirefoxLatest: { platform: 'Windows', osVersion: '11', browserName: 'Firefox', browserVersion: 'latest-beta', useHttps: true },
// Windows11_FirefoxLatest_Incognito: { platform: 'Windows', osVersion: '11', browserName: 'Firefox', browserVersion: 'latest-beta, ...firefoxIncognitoCapabilities },
Windows11_EdgeLatest: { platform: 'Windows', osVersion: '11', browserName: 'Edge', browserVersion: 'latest-beta', useHttps: true },
'OSX10.15_Safari13': { platform: 'OS X', osVersion: 'Catalina', browserName: 'Safari', browserVersion: '13', useHttps: true },
OSX12_Safari15: { platform: 'OS X', osVersion: 'Monterey', browserName: 'Safari', browserVersion: '15', useHttps: false },
OSX15_Safari18: { platform: 'OS X', osVersion: 'Sequoia', browserName: 'Safari', browserVersion: '18', useHttps: false },
OSX15_ChromeLatest: { platform: 'OS X', osVersion: 'Sequoia', browserName: 'Chrome', browserVersion: 'latest-beta', useHttps: true },
// OSX15_ChromeLatest_Incognito: { platform: 'OS X', osVersion: 'Sequoia', browserName: 'Chrome', browserVersion: 'latest-beta, ...chromeIncognitoCapabilities },
OSX15_FirefoxLatest: { platform: 'OS X', osVersion: 'Sequoia', browserName: 'Firefox', browserVersion: 'latest-beta', useHttps: true },
// OSX15_FirefoxLatest_Incognito: { platform: 'OS X', osVersion: 'Sequoia', browserName: 'Firefox', browserVersion: 'latest-beta, ...firefoxIncognitoCapabilities },
OSX15_EdgeLatest: { platform: 'OS X', osVersion: 'Sequoia', browserName: 'Edge', browserVersion: 'latest-beta', useHttps: true },
Android14_ChromeLatest: { platform: 'Android', osVersion: '14.0', browserName: 'Chrome', browserVersion: 'latest-beta', useHttps: true, flags: [arguments_1.Arguments.MobileUserAgent] },
Android14_SamsungLatest: { platform: 'Android', osVersion: '14.0', browserName: 'Samsung', browserVersion: 'latest-beta', useHttps: true, flags: [arguments_1.Arguments.MobileUserAgent] },
iOS13_Safari: { platform: 'iOS', osVersion: '13', browserName: 'Safari', useHttps: true, flags: [arguments_1.Arguments.MobileUserAgent] },
iOS14_Safari: { platform: 'iOS', osVersion: '14', browserName: 'Safari', useHttps: true, flags: [arguments_1.Arguments.MobileUserAgent] },
iOS15_Safari: { platform: 'iOS', osVersion: '15', browserName: 'Safari', useHttps: true, flags: [arguments_1.Arguments.MobileUserAgent] },
iOS16_Safari: { platform: 'iOS', osVersion: '16', browserName: 'Safari', useHttps: true, flags: [arguments_1.Arguments.MobileUserAgent] },
iOS17_Safari: { platform: 'iOS', osVersion: '17', browserName: 'Safari', useHttps: true, flags: [arguments_1.Arguments.MobileUserAgent] },
iOS18_Safari: { platform: 'iOS', osVersion: '18', browserName: 'Safari', useHttps: true, flags: [arguments_1.Arguments.MobileUserAgent] },
};
/* eslint-enable max-len */
function makeBuildNumber() {
return `No CI ${Math.floor(Math.random() * 1e10)}`;
}
;