Updated the files.

This commit is contained in:
Batuhan Berk Başoğlu 2024-02-08 19:38:41 -05:00
parent 1553e6b971
commit 753967d4f5
23418 changed files with 3784666 additions and 0 deletions

271
my-app/node_modules/karma/lib/browser.js generated vendored Executable file
View file

@ -0,0 +1,271 @@
'use strict'
const BrowserResult = require('./browser_result')
const helper = require('./helper')
const logger = require('./logger')
const CONNECTED = 'CONNECTED' // The browser is connected but not yet been commanded to execute tests.
const CONFIGURING = 'CONFIGURING' // The browser has been told to execute tests; it is configuring before tests execution.
const EXECUTING = 'EXECUTING' // The browser is executing the tests.
const EXECUTING_DISCONNECTED = 'EXECUTING_DISCONNECTED' // The browser is executing the tests, but temporarily disconnect (waiting for socket reconnecting).
const DISCONNECTED = 'DISCONNECTED' // The browser got completely disconnected (e.g. browser crash) and can be only restored with a restart of execution.
class Browser {
constructor (id, fullName, collection, emitter, socket, timer, disconnectDelay,
noActivityTimeout, singleRun, clientConfig) {
this.id = id
this.fullName = fullName
this.name = helper.browserFullNameToShort(fullName)
this.lastResult = new BrowserResult()
this.disconnectsCount = 0
this.activeSockets = [socket]
this.noActivityTimeout = noActivityTimeout
this.singleRun = singleRun
this.clientConfig = clientConfig
this.collection = collection
this.emitter = emitter
this.socket = socket
this.timer = timer
this.disconnectDelay = disconnectDelay
this.log = logger.create(this.name)
this.noActivityTimeoutId = null
this.pendingDisconnect = null
this.setState(CONNECTED)
}
init () {
this.log.info(`Connected on socket ${this.socket.id} with id ${this.id}`)
this.bindSocketEvents(this.socket)
this.collection.add(this)
this.emitter.emit('browser_register', this)
}
setState (toState) {
this.log.debug(`${this.state} -> ${toState}`)
this.state = toState
}
onKarmaError (error) {
if (this.isNotConnected()) {
this.lastResult.error = true
}
this.emitter.emit('browser_error', this, error)
this.refreshNoActivityTimeout()
}
onInfo (info) {
if (helper.isDefined(info.dump)) {
this.emitter.emit('browser_log', this, info.dump, 'dump')
}
if (helper.isDefined(info.log)) {
this.emitter.emit('browser_log', this, info.log, info.type)
} else if (helper.isDefined(info.total)) {
if (this.state === EXECUTING) {
this.lastResult.total = info.total
}
} else if (!helper.isDefined(info.dump)) {
this.emitter.emit('browser_info', this, info)
}
this.refreshNoActivityTimeout()
}
onStart (info) {
if (info.total === null) {
this.log.warn('Adapter did not report total number of specs.')
}
this.lastResult = new BrowserResult(info.total)
this.setState(EXECUTING)
this.emitter.emit('browser_start', this, info)
this.refreshNoActivityTimeout()
}
onComplete (result) {
if (this.isNotConnected()) {
this.setState(CONNECTED)
this.lastResult.totalTimeEnd()
this.emitter.emit('browsers_change', this.collection)
this.emitter.emit('browser_complete', this, result)
this.clearNoActivityTimeout()
}
}
onSocketDisconnect (reason, disconnectedSocket) {
helper.arrayRemove(this.activeSockets, disconnectedSocket)
if (this.activeSockets.length) {
this.log.debug(`Disconnected ${disconnectedSocket.id}, still have ${this.getActiveSocketsIds()}`)
return
}
if (this.isConnected()) {
this.disconnect(`Client disconnected from CONNECTED state (${reason})`)
} else if ([CONFIGURING, EXECUTING].includes(this.state)) {
this.log.debug(`Disconnected during run, waiting ${this.disconnectDelay}ms for reconnecting.`)
this.setState(EXECUTING_DISCONNECTED)
this.pendingDisconnect = this.timer.setTimeout(() => {
this.lastResult.totalTimeEnd()
this.lastResult.disconnected = true
this.disconnect(`reconnect failed before timeout of ${this.disconnectDelay}ms (${reason})`)
this.emitter.emit('browser_complete', this)
}, this.disconnectDelay)
this.clearNoActivityTimeout()
}
}
reconnect (newSocket, clientSaysReconnect) {
if (!clientSaysReconnect || this.state === DISCONNECTED) {
this.log.info(`Disconnected browser returned on socket ${newSocket.id} with id ${this.id}.`)
this.setState(CONNECTED)
// The disconnected browser is already part of the collection.
// Update the collection view in the UI (header on client.html)
this.emitter.emit('browsers_change', this.collection)
// Notify the launcher
this.emitter.emit('browser_register', this)
// Execute tests if configured to do so.
if (this.singleRun) {
this.execute()
}
} else if (this.state === EXECUTING_DISCONNECTED) {
this.log.debug('Lost socket connection, but browser continued to execute. Reconnected ' +
`on socket ${newSocket.id}.`)
this.setState(EXECUTING)
} else if ([CONNECTED, CONFIGURING, EXECUTING].includes(this.state)) {
this.log.debug(`Rebinding to new socket ${newSocket.id} (already have ` +
`${this.getActiveSocketsIds()})`)
}
if (!this.activeSockets.some((s) => s.id === newSocket.id)) {
this.activeSockets.push(newSocket)
this.bindSocketEvents(newSocket)
}
if (this.pendingDisconnect) {
this.timer.clearTimeout(this.pendingDisconnect)
}
this.refreshNoActivityTimeout()
}
onResult (result) {
if (Array.isArray(result)) {
result.forEach(this.onResult, this)
} else if (this.isNotConnected()) {
this.lastResult.add(result)
this.emitter.emit('spec_complete', this, result)
}
this.refreshNoActivityTimeout()
}
execute () {
this.activeSockets.forEach((socket) => socket.emit('execute', this.clientConfig))
this.setState(CONFIGURING)
this.refreshNoActivityTimeout()
}
getActiveSocketsIds () {
return this.activeSockets.map((s) => s.id).join(', ')
}
disconnect (reason) {
this.log.warn(`Disconnected (${this.disconnectsCount} times) ${reason || ''}`)
this.disconnectsCount++
this.emitter.emit('browser_error', this, `Disconnected ${reason || ''}`)
this.remove()
}
remove () {
this.setState(DISCONNECTED)
this.collection.remove(this)
}
refreshNoActivityTimeout () {
if (this.noActivityTimeout) {
this.clearNoActivityTimeout()
this.noActivityTimeoutId = this.timer.setTimeout(() => {
this.lastResult.totalTimeEnd()
this.lastResult.disconnected = true
this.disconnect(`, because no message in ${this.noActivityTimeout} ms.`)
this.emitter.emit('browser_complete', this)
}, this.noActivityTimeout)
}
}
clearNoActivityTimeout () {
if (this.noActivityTimeout && this.noActivityTimeoutId) {
this.timer.clearTimeout(this.noActivityTimeoutId)
this.noActivityTimeoutId = null
}
}
bindSocketEvents (socket) {
// TODO: check which of these events are actually emitted by socket
socket.on('disconnect', (reason) => this.onSocketDisconnect(reason, socket))
socket.on('start', (info) => this.onStart(info))
socket.on('karma_error', (error) => this.onKarmaError(error))
socket.on('complete', (result) => this.onComplete(result))
socket.on('info', (info) => this.onInfo(info))
socket.on('result', (result) => this.onResult(result))
}
isConnected () {
return this.state === CONNECTED
}
isNotConnected () {
return !this.isConnected()
}
serialize () {
return {
id: this.id,
name: this.name,
isConnected: this.state === CONNECTED
}
}
toString () {
return this.name
}
toJSON () {
return {
id: this.id,
fullName: this.fullName,
name: this.name,
state: this.state,
lastResult: this.lastResult,
disconnectsCount: this.disconnectsCount,
noActivityTimeout: this.noActivityTimeout,
disconnectDelay: this.disconnectDelay
}
}
}
Browser.factory = function (
id, fullName, /* capturedBrowsers */ collection, emitter, socket, timer,
/* config.browserDisconnectTimeout */ disconnectDelay,
/* config.browserNoActivityTimeout */ noActivityTimeout,
/* config.singleRun */ singleRun,
/* config.client */ clientConfig) {
return new Browser(id, fullName, collection, emitter, socket, timer,
disconnectDelay, noActivityTimeout, singleRun, clientConfig)
}
Browser.STATE_CONNECTED = CONNECTED
Browser.STATE_CONFIGURING = CONFIGURING
Browser.STATE_EXECUTING = EXECUTING
Browser.STATE_EXECUTING_DISCONNECTED = EXECUTING_DISCONNECTED
Browser.STATE_DISCONNECTED = DISCONNECTED
module.exports = Browser

103
my-app/node_modules/karma/lib/browser_collection.js generated vendored Executable file
View file

@ -0,0 +1,103 @@
'use strict'
const BrowserResult = require('./browser_result')
const helper = require('./helper')
class BrowserCollection {
constructor (emitter, browsers = []) {
this.browsers = browsers
this.emitter = emitter
}
add (browser) {
this.browsers.push(browser)
this.emitter.emit('browsers_change', this)
}
remove (browser) {
if (helper.arrayRemove(this.browsers, browser)) {
this.emitter.emit('browsers_change', this)
return true
}
return false
}
getById (browserId) {
return this.browsers.find((browser) => browser.id === browserId) || null
}
getNonReady () {
return this.browsers.filter((browser) => !browser.isConnected())
}
areAllReady () {
return this.browsers.every((browser) => browser.isConnected())
}
serialize () {
return this.browsers.map((browser) => browser.serialize())
}
calculateExitCode (results, singleRunBrowserNotCaptured, config) {
config = config || {}
if (results.disconnected || singleRunBrowserNotCaptured) {
return 1
}
if (results.skipped && config.failOnSkippedTests) {
return 1
}
if (results.success + results.failed === 0 && !!config.failOnEmptyTestSuite) {
return 1
}
if (results.error) {
return 1
}
if (config.failOnFailingTestSuite === false) {
return 0 // Tests executed without infrastructure error, exit with 0 independent of test status.
}
return results.failed ? 1 : 0
}
getResults (singleRunBrowserNotCaptured, config) {
const results = { success: 0, failed: 0, skipped: 0, error: false, disconnected: false, exitCode: 0 }
this.browsers.forEach((browser) => {
results.success += browser.lastResult.success
results.failed += browser.lastResult.failed
results.skipped += browser.lastResult.skipped
results.error = results.error || browser.lastResult.error
results.disconnected = results.disconnected || browser.lastResult.disconnected
})
results.exitCode = this.calculateExitCode(results, singleRunBrowserNotCaptured, config)
return results
}
clearResults () {
this.browsers.forEach((browser) => {
browser.lastResult = new BrowserResult()
})
}
clone () {
return new BrowserCollection(this.emitter, this.browsers.slice())
}
// Array APIs
map (callback, context) {
return this.browsers.map(callback, context)
}
forEach (callback, context) {
return this.browsers.forEach(callback, context)
}
get length () {
return this.browsers.length
}
}
BrowserCollection.factory = function (emitter) {
return new BrowserCollection(emitter)
}
module.exports = BrowserCollection

30
my-app/node_modules/karma/lib/browser_result.js generated vendored Executable file
View file

@ -0,0 +1,30 @@
'use strict'
class BrowserResult {
constructor (total = 0) {
this.startTime = Date.now()
this.total = total
this.skipped = this.failed = this.success = 0
this.netTime = this.totalTime = 0
this.disconnected = this.error = false
}
totalTimeEnd () {
this.totalTime = Date.now() - this.startTime
}
add (result) {
if (result.skipped) {
this.skipped++
} else if (result.success) {
this.success++
} else {
this.failed++
}
this.netTime += result.time
}
}
module.exports = BrowserResult

331
my-app/node_modules/karma/lib/cli.js generated vendored Executable file
View file

@ -0,0 +1,331 @@
'use strict'
const path = require('path')
const yargs = require('yargs')
const fs = require('graceful-fs')
const Server = require('./server')
const helper = require('./helper')
const constant = require('./constants')
const cfg = require('./config')
function processArgs (argv, options, fs, path) {
Object.getOwnPropertyNames(argv).forEach(function (name) {
let argumentValue = argv[name]
if (name !== '_' && name !== '$0') {
if (Array.isArray(argumentValue)) {
argumentValue = argumentValue.pop() // If the same argument is defined multiple times, override.
}
options[helper.dashToCamel(name)] = argumentValue
}
})
if (helper.isString(options.autoWatch)) {
options.autoWatch = options.autoWatch === 'true'
}
if (helper.isString(options.colors)) {
options.colors = options.colors === 'true'
}
if (helper.isString(options.failOnEmptyTestSuite)) {
options.failOnEmptyTestSuite = options.failOnEmptyTestSuite === 'true'
}
if (helper.isString(options.failOnFailingTestSuite)) {
options.failOnFailingTestSuite = options.failOnFailingTestSuite === 'true'
}
if (helper.isString(options.formatError)) {
let required
try {
required = require(options.formatError)
} catch (err) {
console.error('Could not require formatError: ' + options.formatError, err)
}
// support exports.formatError and module.exports = function
options.formatError = required.formatError || required
if (!helper.isFunction(options.formatError)) {
console.error(`Format error must be a function, got: ${typeof options.formatError}`)
process.exit(1)
}
}
if (helper.isString(options.logLevel)) {
const logConstant = constant['LOG_' + options.logLevel.toUpperCase()]
if (helper.isDefined(logConstant)) {
options.logLevel = logConstant
} else {
console.error('Log level must be one of disable, error, warn, info, or debug.')
process.exit(1)
}
} else if (helper.isDefined(options.logLevel)) {
console.error('Log level must be one of disable, error, warn, info, or debug.')
process.exit(1)
}
if (helper.isString(options.singleRun)) {
options.singleRun = options.singleRun === 'true'
}
if (helper.isString(options.browsers)) {
options.browsers = options.browsers.split(',')
}
if (options.reportSlowerThan === false) {
options.reportSlowerThan = 0
}
if (helper.isString(options.reporters)) {
options.reporters = options.reporters.split(',')
}
if (helper.isString(options.removedFiles)) {
options.removedFiles = options.removedFiles.split(',')
}
if (helper.isString(options.addedFiles)) {
options.addedFiles = options.addedFiles.split(',')
}
if (helper.isString(options.changedFiles)) {
options.changedFiles = options.changedFiles.split(',')
}
if (helper.isString(options.refresh)) {
options.refresh = options.refresh === 'true'
}
let configFile = argv.configFile
if (!configFile) {
// default config file (if exists)
if (fs.existsSync('./karma.conf.js')) {
configFile = './karma.conf.js'
} else if (fs.existsSync('./karma.conf.coffee')) {
configFile = './karma.conf.coffee'
} else if (fs.existsSync('./karma.conf.ts')) {
configFile = './karma.conf.ts'
} else if (fs.existsSync('./.config/karma.conf.js')) {
configFile = './.config/karma.conf.js'
} else if (fs.existsSync('./.config/karma.conf.coffee')) {
configFile = './.config/karma.conf.coffee'
} else if (fs.existsSync('./.config/karma.conf.ts')) {
configFile = './.config/karma.conf.ts'
}
}
options.configFile = configFile ? path.resolve(configFile) : null
if (options.cmd === 'run') {
options.clientArgs = parseClientArgs(process.argv)
}
return options
}
function parseClientArgs (argv) {
// extract any args after '--' as clientArgs
let clientArgs = []
argv = argv.slice(2)
const idx = argv.indexOf('--')
if (idx !== -1) {
clientArgs = argv.slice(idx + 1)
}
return clientArgs
}
// return only args that occur before `--`
function argsBeforeDoubleDash (argv) {
const idx = argv.indexOf('--')
return idx === -1 ? argv : argv.slice(0, idx)
}
function describeRoot () {
return yargs
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
'Run --help with particular command to see its description and available options.\n\n' +
'Usage:\n' +
' $0 <command>')
.command('init [configFile]', 'Initialize a config file.', describeInit)
.command('start [configFile]', 'Start the server / do a single run.', describeStart)
.command('run [configFile]', 'Trigger a test run.', describeRun)
.command('stop [configFile]', 'Stop the server.', describeStop)
.command('completion', 'Shell completion for karma.', describeCompletion)
.demandCommand(1, 'Command not specified.')
.strictCommands()
.describe('help', 'Print usage and options.')
.describe('version', 'Print current version.')
}
function describeInit (yargs) {
yargs
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
'INIT - Initialize a config file.\n\n' +
'Usage:\n' +
' $0 init [configFile]')
.strictCommands(false)
.version(false)
.positional('configFile', {
describe: 'Name of the generated Karma configuration file',
type: 'string'
})
.describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
.describe('colors', 'Use colors when reporting and printing logs.')
.describe('no-colors', 'Do not use colors when reporting or printing logs.')
}
function describeStart (yargs) {
yargs
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
'START - Start the server / do a single run.\n\n' +
'Usage:\n' +
' $0 start [configFile]')
.strictCommands(false)
.version(false)
.positional('configFile', {
describe: 'Path to the Karma configuration file',
type: 'string'
})
.describe('port', '<integer> Port where the server is running.')
.describe('auto-watch', 'Auto watch source files and run on change.')
.describe('detached', 'Detach the server.')
.describe('no-auto-watch', 'Do not watch source files.')
.describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
.describe('colors', 'Use colors when reporting and printing logs.')
.describe('no-colors', 'Do not use colors when reporting or printing logs.')
.describe('reporters', 'List of reporters (available: dots, progress, junit, growl, coverage).')
.describe('browsers', 'List of browsers to start (eg. --browsers Chrome,ChromeCanary,Firefox).')
.describe('capture-timeout', '<integer> Kill browser if does not capture in given time [ms].')
.describe('single-run', 'Run the test when browsers captured and exit.')
.describe('no-single-run', 'Disable single-run.')
.describe('report-slower-than', '<integer> Report tests that are slower than given time [ms].')
.describe('fail-on-empty-test-suite', 'Fail on empty test suite.')
.describe('no-fail-on-empty-test-suite', 'Do not fail on empty test suite.')
.describe('fail-on-failing-test-suite', 'Fail on failing test suite.')
.describe('no-fail-on-failing-test-suite', 'Do not fail on failing test suite.')
.option('format-error', {
describe: 'A path to a file that exports the format function.',
type: 'string'
})
}
function describeRun (yargs) {
yargs
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
'RUN - Run the tests (requires running server).\n\n' +
'Usage:\n' +
' $0 run [configFile] [-- <clientArgs>]')
.strictCommands(false)
.version(false)
.positional('configFile', {
describe: 'Path to the Karma configuration file',
type: 'string'
})
.describe('port', '<integer> Port where the server is listening.')
.describe('no-refresh', 'Do not re-glob all the patterns.')
.describe('fail-on-empty-test-suite', 'Fail on empty test suite.')
.describe('no-fail-on-empty-test-suite', 'Do not fail on empty test suite.')
.describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
.describe('colors', 'Use colors when reporting and printing logs.')
.describe('no-colors', 'Do not use colors when reporting or printing logs.')
.option('removed-files', {
describe: 'Comma-separated paths to removed files. Useful when automatic file watching is disabled.',
type: 'string'
})
.option('changed-files', {
describe: 'Comma-separated paths to changed files. Useful when automatic file watching is disabled.',
type: 'string'
})
.option('added-files', {
describe: 'Comma-separated paths to added files. Useful when automatic file watching is disabled.',
type: 'string'
})
}
function describeStop (yargs) {
yargs
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
'STOP - Stop the server (requires running server).\n\n' +
'Usage:\n' +
' $0 stop [configFile]')
.strictCommands(false)
.version(false)
.positional('configFile', {
describe: 'Path to the Karma configuration file',
type: 'string'
})
.describe('port', '<integer> Port where the server is listening.')
.describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
}
function describeCompletion (yargs) {
yargs
.usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
'COMPLETION - Bash/ZSH completion for karma.\n\n' +
'Installation:\n' +
' $0 completion >> ~/.bashrc')
.version(false)
}
function printRunnerProgress (data) {
process.stdout.write(data)
}
exports.process = () => {
const argv = describeRoot().parse(argsBeforeDoubleDash(process.argv.slice(2)))
return processArgs(argv, { cmd: argv._.shift() }, fs, path)
}
exports.run = async () => {
const cliOptions = exports.process()
const cmd = cliOptions.cmd // prevent config from changing the command
const cmdNeedsConfig = cmd === 'start' || cmd === 'run' || cmd === 'stop'
if (cmdNeedsConfig) {
let config
try {
config = await cfg.parseConfig(
cliOptions.configFile,
cliOptions,
{
promiseConfig: true,
throwErrors: true
}
)
} catch (karmaConfigException) {
// The reject reason/exception isn't used to log a message since
// parseConfig already calls a configured logger method with an almost
// identical message.
// The `run` function is a private application, not a public API. We don't
// need to worry about process.exit vs throw vs promise rejection here.
process.exit(1)
}
switch (cmd) {
case 'start': {
const server = new Server(config)
await server.start()
return server
}
case 'run':
return require('./runner')
.run(config)
.on('progress', printRunnerProgress)
case 'stop':
return require('./stopper').stop(config)
}
} else {
switch (cmd) {
case 'init':
return require('./init').init(cliOptions)
case 'completion':
return require('./completion').completion(cliOptions)
}
}
}
// just for testing
exports.processArgs = processArgs
exports.parseClientArgs = parseClientArgs
exports.argsBeforeDoubleDash = argsBeforeDoubleDash

126
my-app/node_modules/karma/lib/completion.js generated vendored Executable file
View file

@ -0,0 +1,126 @@
'use strict'
const glob = require('glob')
const CUSTOM = ['']
const BOOLEAN = false
const options = {
start: {
'--port': CUSTOM,
'--auto-watch': BOOLEAN,
'--no-auto-watch': BOOLEAN,
'--log-level': ['disable', 'debug', 'info', 'warn', 'error'],
'--colors': BOOLEAN,
'--no-colors': BOOLEAN,
'--reporters': ['dots', 'progress'],
'--no-reporters': BOOLEAN,
'--browsers': ['Chrome', 'ChromeHeadless', 'ChromeCanary', 'Firefox', 'PhantomJS', 'Safari', 'Opera'],
'--no-browsers': BOOLEAN,
'--single-run': BOOLEAN,
'--no-single-run': BOOLEAN,
'--help': BOOLEAN
},
init: {
'--log-level': ['disable', 'debug', 'info', 'warn', 'error'],
'--colors': BOOLEAN,
'--no-colors': BOOLEAN,
'--help': BOOLEAN
},
run: {
'--no-refresh': BOOLEAN,
'--port': CUSTOM,
'--help': BOOLEAN
}
}
function opositeWord (word) {
if (word.startsWith('-')) {
return word.startsWith('--no-') ? `--${word.slice(5)}` : `--no-${word.slice(2)}`
} else {
return null
}
}
function sendCompletion (possibleWords, env) {
const regexp = new RegExp('^' + env.last)
possibleWords
.filter((word) => regexp.test(word) && !env.words.includes(word) && !env.words.includes(opositeWord(word)))
.forEach((word) => {
console.log(word)
})
}
function sendCompletionFiles (env) {
glob(env.last + '*', { mark: true, nocase: true }, (err, files) => {
if (err) return console.error(err)
if (files.length === 1 && files[0].endsWith('/')) {
sendCompletionFiles({ last: files[0] })
} else {
console.log(files.join('\n'))
}
})
}
function complete (env) {
if (env.count === 1) {
return sendCompletion(env.words[0].startsWith('-') ? ['--help', '--version'] : Object.keys(options), env)
} else if (env.count === 2 && !env.words[1].startsWith('-')) {
return sendCompletionFiles(env)
}
const cmdOptions = options[env.words[0]]
if (cmdOptions) {
if (cmdOptions[env.prev] === CUSTOM && env.last) {
console.log(env.last)
} else {
return sendCompletion(cmdOptions[env.prev] || Object.keys(cmdOptions), env)
}
}
}
function completion () {
if (process.argv[3] === '--') {
return complete({
words: process.argv.slice(5),
count: parseInt(process.env.COMP_CWORD, 10),
last: process.argv[process.argv.length - 1],
prev: process.argv[process.argv.length - 2]
})
}
// just print out the karma-completion.sh
const fs = require('graceful-fs')
const path = require('path')
fs.readFile(path.resolve(__dirname, '../scripts/karma-completion.sh'), 'utf8', function (err, data) {
if (err) return console.error(err)
process.stdout.write(data)
process.stdout.on('error', function (error) {
// Darwin is a real dick sometimes.
//
// This is necessary because the "source" or "." program in
// bash on OS X closes its file argument before reading
// from it, meaning that you get exactly 1 write, which will
// work most of the time, and will always raise an EPIPE.
//
// Really, one should not be tossing away EPIPE errors, or any
// errors, so casually. But, without this, `. <(karma completion)`
// can never ever work on OS X.
if (error.errno === 'EPIPE') {
error = null
}
})
})
}
// PUBLIC API
exports.completion = completion
// for testing
exports.opositeWord = opositeWord
exports.sendCompletion = sendCompletion
exports.complete = complete

544
my-app/node_modules/karma/lib/config.js generated vendored Executable file
View file

@ -0,0 +1,544 @@
'use strict'
const path = require('path')
const assert = require('assert')
const logger = require('./logger')
const log = logger.create('config')
const helper = require('./helper')
const constant = require('./constants')
const _ = require('lodash')
let COFFEE_SCRIPT_AVAILABLE = false
let LIVE_SCRIPT_AVAILABLE = false
let TYPE_SCRIPT_AVAILABLE = false
try {
require('coffeescript').register()
COFFEE_SCRIPT_AVAILABLE = true
} catch {}
// LiveScript is required here to enable config files written in LiveScript.
// It's not directly used in this file.
try {
require('LiveScript')
LIVE_SCRIPT_AVAILABLE = true
} catch {}
try {
require('ts-node')
TYPE_SCRIPT_AVAILABLE = true
} catch {}
class Pattern {
constructor (pattern, served, included, watched, nocache, type, isBinary, integrity) {
this.pattern = pattern
this.served = helper.isDefined(served) ? served : true
this.included = helper.isDefined(included) ? included : true
this.watched = helper.isDefined(watched) ? watched : true
this.nocache = helper.isDefined(nocache) ? nocache : false
this.weight = helper.mmPatternWeight(pattern)
this.type = type
this.isBinary = isBinary
this.integrity = integrity
}
compare (other) {
return helper.mmComparePatternWeights(this.weight, other.weight)
}
}
class UrlPattern extends Pattern {
constructor (url, type, integrity) {
super(url, false, true, false, false, type, undefined, integrity)
}
}
function createPatternObject (pattern) {
if (pattern && helper.isString(pattern)) {
return helper.isUrlAbsolute(pattern)
? new UrlPattern(pattern)
: new Pattern(pattern)
} else if (helper.isObject(pattern) && pattern.pattern && helper.isString(pattern.pattern)) {
return helper.isUrlAbsolute(pattern.pattern)
? new UrlPattern(pattern.pattern, pattern.type, pattern.integrity)
: new Pattern(pattern.pattern, pattern.served, pattern.included, pattern.watched, pattern.nocache, pattern.type)
} else {
log.warn(`Invalid pattern ${pattern}!\n\tExpected string or object with "pattern" property.`)
return new Pattern(null, false, false, false, false)
}
}
function normalizeUrl (url) {
if (!url.startsWith('/')) {
url = `/${url}`
}
if (!url.endsWith('/')) {
url = url + '/'
}
return url
}
function normalizeUrlRoot (urlRoot) {
const normalizedUrlRoot = normalizeUrl(urlRoot)
if (normalizedUrlRoot !== urlRoot) {
log.warn(`urlRoot normalized to "${normalizedUrlRoot}"`)
}
return normalizedUrlRoot
}
function normalizeProxyPath (proxyPath) {
const normalizedProxyPath = normalizeUrl(proxyPath)
if (normalizedProxyPath !== proxyPath) {
log.warn(`proxyPath normalized to "${normalizedProxyPath}"`)
}
return normalizedProxyPath
}
function normalizeConfig (config, configFilePath) {
function basePathResolve (relativePath) {
if (helper.isUrlAbsolute(relativePath)) {
return relativePath
} else if (helper.isDefined(config.basePath) && helper.isDefined(relativePath)) {
return path.resolve(config.basePath, relativePath)
} else {
return ''
}
}
function createPatternMapper (resolve) {
return (objectPattern) => Object.assign(objectPattern, { pattern: resolve(objectPattern.pattern) })
}
if (helper.isString(configFilePath)) {
config.basePath = path.resolve(path.dirname(configFilePath), config.basePath) // resolve basePath
config.exclude.push(configFilePath) // always ignore the config file itself
} else {
config.basePath = path.resolve(config.basePath || '.')
}
config.files = config.files.map(createPatternObject).map(createPatternMapper(basePathResolve))
config.exclude = config.exclude.map(basePathResolve)
config.customContextFile = config.customContextFile && basePathResolve(config.customContextFile)
config.customDebugFile = config.customDebugFile && basePathResolve(config.customDebugFile)
config.customClientContextFile = config.customClientContextFile && basePathResolve(config.customClientContextFile)
// normalize paths on windows
config.basePath = helper.normalizeWinPath(config.basePath)
config.files = config.files.map(createPatternMapper(helper.normalizeWinPath))
config.exclude = config.exclude.map(helper.normalizeWinPath)
config.customContextFile = helper.normalizeWinPath(config.customContextFile)
config.customDebugFile = helper.normalizeWinPath(config.customDebugFile)
config.customClientContextFile = helper.normalizeWinPath(config.customClientContextFile)
// normalize urlRoot
config.urlRoot = normalizeUrlRoot(config.urlRoot)
// normalize and default upstream proxy settings if given
if (config.upstreamProxy) {
const proxy = config.upstreamProxy
proxy.path = helper.isDefined(proxy.path) ? normalizeProxyPath(proxy.path) : '/'
proxy.hostname = helper.isDefined(proxy.hostname) ? proxy.hostname : 'localhost'
proxy.port = helper.isDefined(proxy.port) ? proxy.port : 9875
// force protocol to end with ':'
proxy.protocol = (proxy.protocol || 'http').split(':')[0] + ':'
if (proxy.protocol.match(/https?:/) === null) {
log.warn(`"${proxy.protocol}" is not a supported upstream proxy protocol, defaulting to "http:"`)
proxy.protocol = 'http:'
}
}
// force protocol to end with ':'
config.protocol = (config.protocol || 'http').split(':')[0] + ':'
if (config.protocol.match(/https?:/) === null) {
log.warn(`"${config.protocol}" is not a supported protocol, defaulting to "http:"`)
config.protocol = 'http:'
}
if (config.proxies && Object.prototype.hasOwnProperty.call(config.proxies, config.urlRoot)) {
log.warn(`"${config.urlRoot}" is proxied, you should probably change urlRoot to avoid conflicts`)
}
if (config.singleRun && config.autoWatch) {
log.debug('autoWatch set to false, because of singleRun')
config.autoWatch = false
}
if (config.runInParent) {
log.debug('useIframe set to false, because using runInParent')
config.useIframe = false
}
if (!config.singleRun && !config.useIframe && config.runInParent) {
log.debug('singleRun set to true, because using runInParent')
config.singleRun = true
}
if (helper.isString(config.reporters)) {
config.reporters = config.reporters.split(',')
}
if (config.client && config.client.args) {
assert(Array.isArray(config.client.args), 'Invalid configuration: client.args must be an array of strings')
}
if (config.browsers) {
assert(Array.isArray(config.browsers), 'Invalid configuration: browsers option must be an array')
}
if (config.formatError) {
assert(helper.isFunction(config.formatError), 'Invalid configuration: formatError option must be a function.')
}
if (config.processKillTimeout) {
assert(helper.isNumber(config.processKillTimeout), 'Invalid configuration: processKillTimeout option must be a number.')
}
if (config.browserSocketTimeout) {
assert(helper.isNumber(config.browserSocketTimeout), 'Invalid configuration: browserSocketTimeout option must be a number.')
}
if (config.pingTimeout) {
assert(helper.isNumber(config.pingTimeout), 'Invalid configuration: pingTimeout option must be a number.')
}
const defaultClient = config.defaultClient || {}
Object.keys(defaultClient).forEach(function (key) {
const option = config.client[key]
config.client[key] = helper.isDefined(option) ? option : defaultClient[key]
})
// normalize preprocessors
const preprocessors = config.preprocessors || {}
const normalizedPreprocessors = config.preprocessors = Object.create(null)
Object.keys(preprocessors).forEach(function (pattern) {
const normalizedPattern = helper.normalizeWinPath(basePathResolve(pattern))
normalizedPreprocessors[normalizedPattern] = helper.isString(preprocessors[pattern])
? [preprocessors[pattern]] : preprocessors[pattern]
})
// define custom launchers/preprocessors/reporters - create a new plugin
const module = Object.create(null)
let hasSomeInlinedPlugin = false
const types = ['launcher', 'preprocessor', 'reporter']
types.forEach(function (type) {
const definitions = config[`custom${helper.ucFirst(type)}s`] || {}
Object.keys(definitions).forEach(function (name) {
const definition = definitions[name]
if (!helper.isObject(definition)) {
return log.warn(`Can not define ${type} ${name}. Definition has to be an object.`)
}
if (!helper.isString(definition.base)) {
return log.warn(`Can not define ${type} ${name}. Missing base ${type}.`)
}
const token = type + ':' + definition.base
const locals = {
args: ['value', definition]
}
module[type + ':' + name] = ['factory', function (injector) {
const plugin = injector.createChild([locals], [token]).get(token)
if (type === 'launcher' && helper.isDefined(definition.displayName)) {
plugin.displayName = definition.displayName
}
return plugin
}]
hasSomeInlinedPlugin = true
})
})
if (hasSomeInlinedPlugin) {
config.plugins.push(module)
}
return config
}
/**
* @class
*/
class Config {
constructor () {
this.LOG_DISABLE = constant.LOG_DISABLE
this.LOG_ERROR = constant.LOG_ERROR
this.LOG_WARN = constant.LOG_WARN
this.LOG_INFO = constant.LOG_INFO
this.LOG_DEBUG = constant.LOG_DEBUG
// DEFAULT CONFIG
this.frameworks = []
this.protocol = 'http:'
this.port = constant.DEFAULT_PORT
this.listenAddress = constant.DEFAULT_LISTEN_ADDR
this.hostname = constant.DEFAULT_HOSTNAME
this.httpsServerConfig = {}
this.basePath = ''
this.files = []
this.browserConsoleLogOptions = {
level: 'debug',
format: '%b %T: %m',
terminal: true
}
this.customContextFile = null
this.customDebugFile = null
this.customClientContextFile = null
this.exclude = []
this.logLevel = constant.LOG_INFO
this.colors = true
this.autoWatch = true
this.autoWatchBatchDelay = 250
this.restartOnFileChange = false
this.usePolling = process.platform === 'linux'
this.reporters = ['progress']
this.singleRun = false
this.browsers = []
this.captureTimeout = 60000
this.pingTimeout = 5000
this.proxies = {}
this.proxyValidateSSL = true
this.preprocessors = {}
this.preprocessor_priority = {}
this.urlRoot = '/'
this.upstreamProxy = undefined
this.reportSlowerThan = 0
this.loggers = [constant.CONSOLE_APPENDER]
this.transports = ['polling', 'websocket']
this.forceJSONP = false
this.plugins = ['karma-*']
this.defaultClient = this.client = {
args: [],
useIframe: true,
runInParent: false,
captureConsole: true,
clearContext: true,
allowedReturnUrlPatterns: ['^https?://']
}
this.browserDisconnectTimeout = 2000
this.browserDisconnectTolerance = 0
this.browserNoActivityTimeout = 30000
this.processKillTimeout = 2000
this.concurrency = Infinity
this.failOnEmptyTestSuite = true
this.retryLimit = 2
this.detached = false
this.crossOriginAttribute = true
this.browserSocketTimeout = 20000
}
set (newConfig) {
_.mergeWith(this, newConfig, (obj, src) => {
// Overwrite arrays to keep consistent with #283
if (Array.isArray(src)) {
return src
}
})
}
}
const CONFIG_SYNTAX_HELP = ' module.exports = function(config) {\n' +
' config.set({\n' +
' // your config\n' +
' });\n' +
' };\n'
/**
* Retrieve a parsed and finalized Karma `Config` instance. This `karmaConfig`
* object may be used to configure public API methods such a `Server`,
* `runner.run`, and `stopper.stop`.
*
* @param {?string} [configFilePath=null]
* A string representing a file system path pointing to the config file
* whose default export is a function that will be used to set Karma
* configuration options. This function will be passed an instance of the
* `Config` class as its first argument. If this option is not provided,
* then only the options provided by the `cliOptions` argument will be
* set.
* @param {Object} cliOptions
* An object whose values will take priority over options set in the
* config file. The config object passed to function exported by the
* config file will already have these options applied. Any changes the
* config file makes to these options will effectively be ignored in the
* final configuration.
*
* `cliOptions` all the same options as the config file and is applied
* using the same `config.set()` method.
* @param {Object} parseOptions
* @param {boolean} [parseOptions.promiseConfig=false]
* When `true`, a promise that resolves to a `Config` object will be
* returned. This also allows the function exported by config files (if
* provided) to be asynchronous by returning a promise. Resolving this
* promise indicates that all async activity has completed. The resolution
* value itself is ignored, all configuration must be done with
* `config.set`.
* @param {boolean} [parseOptions.throwErrors=false]
* When `true`, process exiting on critical failures will be disabled. In
* The error will be thrown as an exception. If
* `parseOptions.promiseConfig` is also `true`, then the error will
* instead be used as the promise's reject reason.
* @returns {Config|Promise<Config>}
*/
function parseConfig (configFilePath, cliOptions, parseOptions) {
const promiseConfig = parseOptions && parseOptions.promiseConfig === true
const throwErrors = parseOptions && parseOptions.throwErrors === true
const shouldSetupLoggerEarly = promiseConfig
if (shouldSetupLoggerEarly) {
// `setupFromConfig` provides defaults for `colors` and `logLevel`.
// `setup` provides defaults for `appenders`
// The first argument MUST BE an object
logger.setupFromConfig({})
}
function fail () {
log.error(...arguments)
if (throwErrors) {
const errorMessage = Array.from(arguments).join(' ')
const err = new Error(errorMessage)
if (promiseConfig) {
return Promise.reject(err)
}
throw err
} else {
const warningMessage =
'The `parseConfig()` function historically called `process.exit(1)`' +
' when it failed. This behavior is now deprecated and function will' +
' throw an error in the next major release. To suppress this warning' +
' pass `throwErrors: true` as a third argument to opt-in into the new' +
' behavior and adjust your code to respond to the exception' +
' accordingly.' +
' Example: `parseConfig(path, cliOptions, { throwErrors: true })`'
log.warn(warningMessage)
process.exit(1)
}
}
let configModule
if (configFilePath) {
try {
if (path.extname(configFilePath) === '.ts' && TYPE_SCRIPT_AVAILABLE) {
require('ts-node').register()
}
configModule = require(configFilePath)
if (typeof configModule === 'object' && typeof configModule.default !== 'undefined') {
configModule = configModule.default
}
} catch (e) {
const extension = path.extname(configFilePath)
if (extension === '.coffee' && !COFFEE_SCRIPT_AVAILABLE) {
log.error('You need to install CoffeeScript.\n npm install coffeescript --save-dev')
} else if (extension === '.ls' && !LIVE_SCRIPT_AVAILABLE) {
log.error('You need to install LiveScript.\n npm install LiveScript --save-dev')
} else if (extension === '.ts' && !TYPE_SCRIPT_AVAILABLE) {
log.error('You need to install TypeScript.\n npm install typescript ts-node --save-dev')
}
return fail('Error in config file!\n ' + e.stack || e)
}
if (!helper.isFunction(configModule)) {
return fail('Config file must export a function!\n' + CONFIG_SYNTAX_HELP)
}
} else {
configModule = () => {} // if no config file path is passed, we define a dummy config module.
}
const config = new Config()
// save and reset hostname and listenAddress so we can detect if the user
// changed them
const defaultHostname = config.hostname
config.hostname = null
const defaultListenAddress = config.listenAddress
config.listenAddress = null
// add the user's configuration in
config.set(cliOptions)
let configModuleReturn
try {
configModuleReturn = configModule(config)
} catch (e) {
return fail('Error in config file!\n', e)
}
function finalizeConfig (config) {
// merge the config from config file and cliOptions (precedence)
config.set(cliOptions)
// if the user changed listenAddress, but didn't set a hostname, warn them
if (config.hostname === null && config.listenAddress !== null) {
log.warn(`ListenAddress was set to ${config.listenAddress} but hostname was left as the default: ` +
`${defaultHostname}. If your browsers fail to connect, consider changing the hostname option.`)
}
// restore values that weren't overwritten by the user
if (config.hostname === null) {
config.hostname = defaultHostname
}
if (config.listenAddress === null) {
config.listenAddress = defaultListenAddress
}
// configure the logger as soon as we can
logger.setup(config.logLevel, config.colors, config.loggers)
log.debug(configFilePath ? `Loading config ${configFilePath}` : 'No config file specified.')
return normalizeConfig(config, configFilePath)
}
/**
* Return value is a function or (non-null) object that has a `then` method.
*
* @type {boolean}
* @see {@link https://promisesaplus.com/}
*/
const returnIsThenable = (
(
(configModuleReturn != null && typeof configModuleReturn === 'object') ||
typeof configModuleReturn === 'function'
) && typeof configModuleReturn.then === 'function'
)
if (returnIsThenable) {
if (promiseConfig !== true) {
const errorMessage =
'The `parseOptions.promiseConfig` option must be set to `true` to ' +
'enable promise return values from configuration files. ' +
'Example: `parseConfig(path, cliOptions, { promiseConfig: true })`'
return fail(errorMessage)
}
return configModuleReturn.then(
function onKarmaConfigModuleFulfilled (/* ignoredResolutionValue */) {
return finalizeConfig(config)
},
function onKarmaConfigModuleRejected (reason) {
return fail('Error in config file!\n', reason)
}
)
} else {
if (promiseConfig) {
try {
return Promise.resolve(finalizeConfig(config))
} catch (exception) {
return Promise.reject(exception)
}
} else {
return finalizeConfig(config)
}
}
}
// PUBLIC API
exports.parseConfig = parseConfig
exports.Pattern = Pattern
exports.createPatternObject = createPatternObject
exports.Config = Config

43
my-app/node_modules/karma/lib/constants.js generated vendored Executable file
View file

@ -0,0 +1,43 @@
'use strict'
const fs = require('graceful-fs')
const path = require('path')
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '/../package.json')).toString())
exports.VERSION = pkg.version
exports.DEFAULT_PORT = process.env.PORT || 9876
exports.DEFAULT_HOSTNAME = process.env.IP || 'localhost'
exports.DEFAULT_LISTEN_ADDR = process.env.LISTEN_ADDR || '0.0.0.0'
// log levels
exports.LOG_DISABLE = 'OFF'
exports.LOG_ERROR = 'ERROR'
exports.LOG_WARN = 'WARN'
exports.LOG_INFO = 'INFO'
exports.LOG_DEBUG = 'DEBUG'
exports.LOG_LOG = 'LOG'
exports.LOG_PRIORITIES = [
exports.LOG_DISABLE,
exports.LOG_ERROR,
exports.LOG_WARN,
exports.LOG_LOG,
exports.LOG_INFO,
exports.LOG_DEBUG
]
// Default patterns for the pattern layout.
exports.COLOR_PATTERN = '%[%d{DATETIME}:%p [%c]: %]%m'
exports.NO_COLOR_PATTERN = '%d{DATETIME}:%p [%c]: %m'
// Default console appender
exports.CONSOLE_APPENDER = {
type: 'console',
layout: {
type: 'pattern',
pattern: exports.COLOR_PATTERN
}
}
exports.EXIT_CODE = '\x1FEXIT'

11
my-app/node_modules/karma/lib/detached.js generated vendored Executable file
View file

@ -0,0 +1,11 @@
'use strict'
const fs = require('fs')
const Server = require('./server')
const configurationFile = process.argv[2]
const fileContents = fs.readFileSync(configurationFile, 'utf-8')
fs.unlink(configurationFile, function () {})
const data = JSON.parse(fileContents)
const server = new Server(data)
server.start(data)

33
my-app/node_modules/karma/lib/emitter_wrapper.js generated vendored Executable file
View file

@ -0,0 +1,33 @@
'use strict'
class EmitterWrapper {
constructor (emitter) {
this.listeners = {}
this.emitter = emitter
}
addListener (event, listener) {
this.emitter.addListener(event, listener)
this.listeners[event] = this.listeners[event] || []
this.listeners[event].push(listener)
return this
}
on (event, listener) {
return this.addListener(event, listener)
}
removeAllListeners (event) {
const events = event ? [event] : Object.keys(this.listeners)
events.forEach((event) => {
this.listeners[event].forEach((listener) => {
this.emitter.removeListener(event, listener)
})
delete this.listeners[event]
})
return this
}
}
module.exports = EmitterWrapper

67
my-app/node_modules/karma/lib/events.js generated vendored Executable file
View file

@ -0,0 +1,67 @@
'use strict'
const EventEmitter = require('events').EventEmitter
const helper = require('./helper')
function bufferEvents (emitter, eventsToBuffer) {
const listeners = []
const eventsToReply = []
function genericListener () {
eventsToReply.push(Array.from(arguments))
}
eventsToBuffer.forEach((eventName) => {
const listener = genericListener.bind(null, eventName)
listeners.push(listener)
emitter.on(eventName, listener)
})
return function () {
listeners.forEach((listener, i) => {
emitter.removeListener(eventsToBuffer[i], listener)
})
eventsToReply.forEach((args) => {
EventEmitter.prototype.emit.apply(emitter, args)
})
listeners.length = 0
eventsToReply.length = 0
}
}
class KarmaEventEmitter extends EventEmitter {
bind (object) {
for (const method in object) {
if (method.startsWith('on') && helper.isFunction(object[method])) {
this.on(helper.camelToSnake(method.slice(2)), function () {
// We do not use an arrow function here, to supply the caller as this.
object[method].apply(object, Array.from(arguments).concat(this))
})
}
}
}
emitAsync (name) {
// TODO(vojta): allow passing args
// TODO(vojta): ignore/throw if listener call done() multiple times
let pending = this.listeners(name).length
const deferred = helper.defer()
this.emit(name, () => {
if (!--pending) {
deferred.resolve()
}
})
if (!pending) {
deferred.resolve()
}
return deferred.promise
}
}
exports.EventEmitter = KarmaEventEmitter
exports.bufferEvents = bufferEvents

96
my-app/node_modules/karma/lib/executor.js generated vendored Executable file
View file

@ -0,0 +1,96 @@
'use strict'
const log = require('./logger').create()
class Executor {
constructor (capturedBrowsers, config, emitter) {
this.capturedBrowsers = capturedBrowsers
this.config = config
this.emitter = emitter
this.executionScheduled = false
this.errorsScheduled = []
this.pendingCount = 0
this.runningBrowsers = null
this.emitter.on('run_complete', () => this.onRunComplete())
this.emitter.on('browser_complete', () => this.onBrowserComplete())
}
schedule () {
if (this.capturedBrowsers.length === 0) {
log.warn(`No captured browser, open ${this.config.protocol}//${this.config.hostname}:${this.config.port}${this.config.urlRoot}`)
return false
} else if (this.capturedBrowsers.areAllReady()) {
log.debug('All browsers are ready, executing')
log.debug(`Captured ${this.capturedBrowsers.length} browsers`)
this.executionScheduled = false
this.capturedBrowsers.clearResults()
this.pendingCount = this.capturedBrowsers.length
this.runningBrowsers = this.capturedBrowsers.clone()
this.emitter.emit('run_start', this.runningBrowsers)
this.socketIoSockets.emit('execute', this.config.client)
return true
} else {
log.info('Delaying execution, these browsers are not ready: ' + this.capturedBrowsers.getNonReady().join(', '))
this.executionScheduled = true
return false
}
}
/**
* Schedule an error to be reported
* @param {string} errorMessage
* @returns {boolean} a boolean indicating whether or not the error was handled synchronously
*/
scheduleError (errorMessage) {
// We don't want to interfere with any running test.
// Verify that no test is running before reporting the error.
if (this.capturedBrowsers.areAllReady()) {
log.warn(errorMessage)
const errorResult = {
success: 0,
failed: 0,
skipped: 0,
error: errorMessage,
exitCode: 1
}
const noBrowsersStartedTests = []
this.emitter.emit('run_start', noBrowsersStartedTests) // A run cannot complete without being started
this.emitter.emit('run_complete', noBrowsersStartedTests, errorResult)
return true
} else {
this.errorsScheduled.push(errorMessage)
return false
}
}
onRunComplete () {
if (this.executionScheduled) {
this.schedule()
}
if (this.errorsScheduled.length) {
const errorsToReport = this.errorsScheduled
this.errorsScheduled = []
errorsToReport.forEach((error) => this.scheduleError(error))
}
}
onBrowserComplete () {
this.pendingCount--
if (!this.pendingCount) {
// Ensure run_complete is emitted in the next tick
// so it is never emitted before browser_complete
setTimeout(() => {
this.emitter.emit('run_complete', this.runningBrowsers, this.runningBrowsers.getResults())
})
}
}
}
Executor.factory = function (capturedBrowsers, config, emitter) {
return new Executor(capturedBrowsers, config, emitter)
}
module.exports = Executor

242
my-app/node_modules/karma/lib/file-list.js generated vendored Executable file
View file

@ -0,0 +1,242 @@
'use strict'
const { promisify } = require('util')
const mm = require('minimatch')
const Glob = require('glob').Glob
const fs = require('graceful-fs')
const statAsync = promisify(fs.stat.bind(fs))
const pathLib = require('path')
const _ = require('lodash')
const File = require('./file')
const Url = require('./url')
const helper = require('./helper')
const log = require('./logger').create('filelist')
const createPatternObject = require('./config').createPatternObject
class FileList {
constructor (patterns, excludes, emitter, preprocess, autoWatchBatchDelay) {
this._patterns = patterns || []
this._excludes = excludes || []
this._emitter = emitter
this._preprocess = preprocess
this.buckets = new Map()
// A promise that is pending if and only if we are active in this.refresh_()
this._refreshing = null
const emit = () => {
this._emitter.emit('file_list_modified', this.files)
}
const debouncedEmit = _.debounce(emit, autoWatchBatchDelay)
this._emitModified = (immediate) => {
immediate ? emit() : debouncedEmit()
}
}
_findExcluded (path) {
return this._excludes.find((pattern) => mm(path, pattern))
}
_findIncluded (path) {
return this._patterns.find((pattern) => mm(path, pattern.pattern))
}
_findFile (path, pattern) {
if (!path || !pattern) return
return this._getFilesByPattern(pattern.pattern).find((file) => file.originalPath === path)
}
_exists (path) {
return !!this._patterns.find((pattern) => mm(path, pattern.pattern) && this._findFile(path, pattern))
}
_getFilesByPattern (pattern) {
return this.buckets.get(pattern) || []
}
_refresh () {
const matchedFiles = new Set()
let lastCompletedRefresh = this._refreshing
lastCompletedRefresh = Promise.all(
this._patterns.map(async ({ pattern, type, nocache, isBinary, integrity }) => {
if (helper.isUrlAbsolute(pattern)) {
this.buckets.set(pattern, [new Url(pattern, type, integrity)])
return
}
const mg = new Glob(pathLib.normalize(pattern), { cwd: '/', follow: true, nodir: true, sync: true })
const files = mg.found
.filter((path) => {
if (this._findExcluded(path)) {
log.debug(`Excluded file "${path}"`)
return false
} else if (matchedFiles.has(path)) {
return false
} else {
matchedFiles.add(path)
return true
}
})
.map((path) => new File(path, mg.statCache[path].mtime, nocache, type, isBinary))
if (nocache) {
log.debug(`Not preprocessing "${pattern}" due to nocache`)
} else {
await Promise.all(files.map((file) => this._preprocess(file)))
}
this.buckets.set(pattern, files)
if (_.isEmpty(mg.found)) {
log.warn(`Pattern "${pattern}" does not match any file.`)
} else if (_.isEmpty(files)) {
log.warn(`All files matched by "${pattern}" were excluded or matched by prior matchers.`)
}
})
)
.then(() => {
// When we return from this function the file processing chain will be
// complete. In the case of two fast refresh() calls, the second call
// will overwrite this._refreshing, and we want the status to reflect
// the second call and skip the modification event from the first call.
if (this._refreshing !== lastCompletedRefresh) {
return this._refreshing
}
this._emitModified(true)
return this.files
})
return lastCompletedRefresh
}
get files () {
const served = []
const included = {}
const lookup = {}
this._patterns.forEach((p) => {
// This needs to be here sadly, as plugins are modifiying
// the _patterns directly resulting in elements not being
// instantiated properly
if (p.constructor.name !== 'Pattern') {
p = createPatternObject(p)
}
const files = this._getFilesByPattern(p.pattern)
files.sort((a, b) => {
if (a.path > b.path) return 1
if (a.path < b.path) return -1
return 0
})
if (p.served) {
served.push(...files)
}
files.forEach((file) => {
if (lookup[file.path] && lookup[file.path].compare(p) < 0) return
lookup[file.path] = p
if (p.included) {
included[file.path] = file
} else {
delete included[file.path]
}
})
})
return {
served: _.uniq(served, 'path'),
included: _.values(included)
}
}
refresh () {
this._refreshing = this._refresh()
return this._refreshing
}
reload (patterns, excludes) {
this._patterns = patterns || []
this._excludes = excludes || []
return this.refresh()
}
async addFile (path) {
const excluded = this._findExcluded(path)
if (excluded) {
log.debug(`Add file "${path}" ignored. Excluded by "${excluded}".`)
return this.files
}
const pattern = this._findIncluded(path)
if (!pattern) {
log.debug(`Add file "${path}" ignored. Does not match any pattern.`)
return this.files
}
if (this._exists(path)) {
log.debug(`Add file "${path}" ignored. Already in the list.`)
return this.files
}
const file = new File(path)
this._getFilesByPattern(pattern.pattern).push(file)
const [stat] = await Promise.all([statAsync(path), this._refreshing])
file.mtime = stat.mtime
await this._preprocess(file)
log.info(`Added file "${path}".`)
this._emitModified()
return this.files
}
async changeFile (path, force) {
const pattern = this._findIncluded(path)
const file = this._findFile(path, pattern)
if (!file) {
log.debug(`Changed file "${path}" ignored. Does not match any file in the list.`)
return this.files
}
const [stat] = await Promise.all([statAsync(path), this._refreshing])
if (force || stat.mtime > file.mtime) {
file.mtime = stat.mtime
await this._preprocess(file)
log.info(`Changed file "${path}".`)
this._emitModified(force)
}
return this.files
}
async removeFile (path) {
const pattern = this._findIncluded(path)
const file = this._findFile(path, pattern)
if (file) {
helper.arrayRemove(this._getFilesByPattern(pattern.pattern), file)
log.info(`Removed file "${path}".`)
this._emitModified()
} else {
log.debug(`Removed file "${path}" ignored. Does not match any file in the list.`)
}
return this.files
}
}
FileList.factory = function (config, emitter, preprocess) {
return new FileList(config.files, config.exclude, emitter, preprocess, config.autoWatchBatchDelay)
}
FileList.factory.$inject = ['config', 'emitter', 'preprocess']
module.exports = FileList

49
my-app/node_modules/karma/lib/file.js generated vendored Executable file
View file

@ -0,0 +1,49 @@
'use strict'
const path = require('path')
/**
* File object used for tracking files in `file-list.js`.
*/
class File {
constructor (path, mtime, doNotCache, type, isBinary, integrity) {
// used for serving (processed path, eg some/file.coffee -> some/file.coffee.js)
this.path = path
// original absolute path, id of the file
this.originalPath = path
// where the content is stored (processed)
this.contentPath = path
// encodings format {[encodingType]: encodedContent}
// example: {gzip: <Buffer 1f 8b 08...>}
this.encodings = Object.create(null)
this.mtime = mtime
this.isUrl = false
this.doNotCache = doNotCache === undefined ? false : doNotCache
this.type = type
// Tri state: null means probe file for binary.
this.isBinary = isBinary === undefined ? null : isBinary
this.integrity = integrity
}
/**
* Detect type from the file extension.
* @returns {string} detected file type or empty string
*/
detectType () {
return path.extname(this.path).slice(1)
}
toString () {
return this.path
}
}
module.exports = File

171
my-app/node_modules/karma/lib/helper.js generated vendored Executable file
View file

@ -0,0 +1,171 @@
'use strict'
const _ = require('lodash')
const mkdirp = require('mkdirp')
const useragent = require('ua-parser-js')
const mm = require('minimatch')
exports.browserFullNameToShort = (fullName) => {
const ua = useragent(fullName)
if (!ua.browser.name && !ua.browser.version && !ua.os.name && !ua.os.version) {
return fullName
}
return `${ua.browser.name} ${ua.browser.version || '0.0.0'} (${ua.os.name} ${ua.os.version || '0.0.0'})`
}
exports.isDefined = (value) => {
return !_.isUndefined(value)
}
const parser = (pattern, out) => {
if (pattern.length === 0) return out
const p = /^(\[[^\]]*\]|[*+@?]\((.+?)\))/g
const matches = p.exec(pattern)
if (!matches) {
const c = pattern[0]
let t = 'word'
if (c === '*') {
t = 'star'
} else if (c === '?') {
t = 'optional'
}
out[t]++
return parser(pattern.slice(1), out)
}
if (matches[2] !== undefined) {
out.ext_glob++
parser(matches[2], out)
return parser(pattern.slice(matches[0].length), out)
}
out.range++
return parser(pattern.slice(matches[0].length), out)
}
const gsParser = (pattern, out) => {
if (pattern === '**') {
out.glob_star++
return out
}
return parser(pattern, out)
}
const compareWeightObject = (w1, w2) => {
return exports.mmComparePatternWeights(
[w1.glob_star, w1.star, w1.ext_glob, w1.range, w1.optional],
[w2.glob_star, w2.star, w2.ext_glob, w2.range, w2.optional]
)
}
exports.mmPatternWeight = (pattern) => {
const m = new mm.Minimatch(pattern)
if (!m.globParts) return [0, 0, 0, 0, 0, 0]
const result = m.globParts.reduce((prev, p) => {
const r = p.reduce((prev, p) => {
return gsParser(p, prev)
}, { glob_star: 0, ext_glob: 0, word: 0, star: 0, optional: 0, range: 0 })
if (prev === undefined) return r
return compareWeightObject(r, prev) > 0 ? r : prev
}, undefined)
result.glob_sets = m.set.length
return [result.glob_sets, result.glob_star, result.star, result.ext_glob, result.range, result.optional]
}
exports.mmComparePatternWeights = (weight1, weight2) => {
const n1 = weight1[0]
const n2 = weight2[0]
const diff = n1 - n2
if (diff !== 0) return diff / Math.abs(diff)
return weight1.length > 1 ? exports.mmComparePatternWeights(weight1.slice(1), weight2.slice(1)) : 0
}
exports.isFunction = _.isFunction
exports.isString = _.isString
exports.isObject = _.isObject
exports.isArray = _.isArray
exports.isNumber = _.isNumber
const ABS_URL = /^https?:\/\//
exports.isUrlAbsolute = (url) => {
return ABS_URL.test(url)
}
exports.camelToSnake = (camelCase) => {
return camelCase.replace(/[A-Z]/g, (match, pos) => {
return (pos > 0 ? '_' : '') + match.toLowerCase()
})
}
exports.ucFirst = (word) => {
return word.charAt(0).toUpperCase() + word.slice(1)
}
exports.dashToCamel = (dash) => {
const words = dash.split('-')
return words.shift() + words.map(exports.ucFirst).join('')
}
exports.arrayRemove = (collection, item) => {
const idx = collection.indexOf(item)
if (idx !== -1) {
collection.splice(idx, 1)
return true
}
return false
}
exports.merge = function () {
const args = Array.prototype.slice.call(arguments, 0)
args.unshift({})
return _.merge.apply({}, args)
}
exports.formatTimeInterval = (time) => {
const mins = Math.floor(time / 60000)
const secs = (time - mins * 60000) / 1000
let str = secs + (secs === 1 ? ' sec' : ' secs')
if (mins) {
str = mins + (mins === 1 ? ' min ' : ' mins ') + str
}
return str
}
const replaceWinPath = (path) => {
return _.isString(path) ? path.replace(/\\/g, '/') : path
}
exports.normalizeWinPath = process.platform === 'win32' ? replaceWinPath : _.identity
exports.mkdirIfNotExists = (directory, done) => {
mkdirp(directory, done)
}
exports.defer = () => {
let res
let rej
const promise = new Promise((resolve, reject) => {
res = resolve
rej = reject
})
return {
resolve: res,
reject: rej,
promise: promise
}
}
exports.saveOriginalArgs = (config) => {
if (config && config.client && config.client.args) {
config.client.originalArgs = _.cloneDeep(config.client.args)
}
}
exports.restoreOriginalArgs = (config) => {
if (config && config.client && config.client.originalArgs) {
config.client.args = _.cloneDeep(config.client.originalArgs)
}
}

18
my-app/node_modules/karma/lib/index.js generated vendored Executable file
View file

@ -0,0 +1,18 @@
'use strict'
const constants = require('./constants')
const Server = require('./server')
const runner = require('./runner')
const stopper = require('./stopper')
const launcher = require('./launcher')
const cfg = require('./config')
module.exports = {
constants: constants,
VERSION: constants.VERSION,
Server: Server,
runner: runner,
stopper: stopper,
launcher: launcher,
config: { parseConfig: cfg.parseConfig } // lets start with only opening up the `parseConfig` api
}

239
my-app/node_modules/karma/lib/init.js generated vendored Executable file
View file

@ -0,0 +1,239 @@
'use strict'
const readline = require('readline')
const path = require('path')
const glob = require('glob')
const mm = require('minimatch')
const exec = require('child_process').exec
const helper = require('./helper')
const logger = require('./logger')
const log = logger.create('init')
const logQueue = require('./init/log-queue')
const StateMachine = require('./init/state_machine')
const COLOR_SCHEME = require('./init/color_schemes')
const formatters = require('./init/formatters')
// TODO(vojta): coverage
// TODO(vojta): html preprocessors
// TODO(vojta): SauceLabs
// TODO(vojta): BrowserStack
let NODE_MODULES_DIR = path.resolve(__dirname, '../..')
// Karma is not in node_modules, probably a symlink,
// use current working dir.
if (!/node_modules$/.test(NODE_MODULES_DIR)) {
NODE_MODULES_DIR = path.resolve('node_modules')
}
function installPackage (pkgName) {
// Do not install if already installed.
try {
require(NODE_MODULES_DIR + '/' + pkgName)
return
} catch (e) {}
log.debug(`Missing plugin "${pkgName}". Installing...`)
const options = {
cwd: path.resolve(NODE_MODULES_DIR, '..')
}
exec(`npm install ${pkgName} --save-dev`, options, function (err, stdout, stderr) {
// Put the logs into the queue and print them after answering current question.
// Otherwise the log would clobber the interactive terminal.
logQueue.push(function () {
if (!err) {
log.debug(`${pkgName} successfully installed.`)
} else if (/is not in the npm registry/.test(stderr)) {
log.warn(`Failed to install "${pkgName}". It is not in the npm registry!\n Please install it manually.`)
} else if (/Error: EACCES/.test(stderr)) {
log.warn(`Failed to install "${pkgName}". No permissions to write in ${options.cwd}!\n Please install it manually.`)
} else {
log.warn(`Failed to install "${pkgName}"\n Please install it manually.`)
}
})
})
}
function validatePattern (pattern) {
if (!glob.sync(pattern).length) {
log.warn('There is no file matching this pattern.\n')
}
}
function validateBrowser (name) {
// TODO(vojta): check if the path resolves to a binary
installPackage('karma-' + name.toLowerCase().replace('headless', '').replace('canary', '') + '-launcher')
}
function validateFramework (name) {
installPackage('karma-' + name)
}
function validateRequireJs (useRequire) {
if (useRequire) {
validateFramework('requirejs')
}
}
var questions = [{
id: 'framework',
question: 'Which testing framework do you want to use ?',
hint: 'Press tab to list possible options. Enter to move to the next question.',
options: ['jasmine', 'mocha', 'qunit', 'nodeunit', 'nunit', ''],
validate: validateFramework
}, {
id: 'requirejs',
question: 'Do you want to use Require.js ?',
hint: 'This will add Require.js plugin.\nPress tab to list possible options. Enter to move to the next question.',
options: ['no', 'yes'],
validate: validateRequireJs,
boolean: true
}, {
id: 'browsers',
question: 'Do you want to capture any browsers automatically ?',
hint: 'Press tab to list possible options. Enter empty string to move to the next question.',
options: ['Chrome', 'ChromeHeadless', 'ChromeCanary', 'Firefox', 'Safari', 'PhantomJS', 'Opera', 'IE', ''],
validate: validateBrowser,
multiple: true
}, {
id: 'files',
question: 'What is the location of your source and test files ?',
hint: 'You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".\nEnter empty string to move to the next question.',
multiple: true,
validate: validatePattern
}, {
id: 'exclude',
question: 'Should any of the files included by the previous patterns be excluded ?',
hint: 'You can use glob patterns, eg. "**/*.swp".\nEnter empty string to move to the next question.',
multiple: true,
validate: validatePattern
}, {
id: 'generateTestMain',
question: 'Do you wanna generate a bootstrap file for RequireJS?',
hint: 'This will generate test-main.js/coffee that configures RequireJS and starts the tests.',
options: ['no', 'yes'],
boolean: true,
condition: (answers) => answers.requirejs
}, {
id: 'includedFiles',
question: 'Which files do you want to include with <script> tag ?',
hint: 'This should be a script that bootstraps your test by configuring Require.js and ' +
'kicking __karma__.start(), probably your test-main.js file.\n' +
'Enter empty string to move to the next question.',
multiple: true,
validate: validatePattern,
condition: (answers) => answers.requirejs && !answers.generateTestMain
}, {
id: 'autoWatch',
question: 'Do you want Karma to watch all the files and run the tests on change ?',
hint: 'Press tab to list possible options.',
options: ['yes', 'no'],
boolean: true
}]
function getBasePath (configFilePath, cwd) {
const configParts = path.dirname(configFilePath).split(path.sep)
const cwdParts = cwd.split(path.sep)
const base = []
while (configParts.length && configParts[0] === cwdParts[0]) {
configParts.shift()
cwdParts.shift()
}
while (configParts.length) {
const part = configParts.shift()
if (part === '..') {
base.unshift(cwdParts.pop())
} else if (part !== '.') {
base.unshift('..')
}
}
return base.join(path.sep)
}
function processAnswers (answers, basePath, testMainFile) {
const processedAnswers = {
basePath: basePath,
files: answers.files,
onlyServedFiles: [],
exclude: answers.exclude,
autoWatch: answers.autoWatch,
generateTestMain: answers.generateTestMain,
browsers: answers.browsers,
frameworks: [],
preprocessors: {}
}
if (answers.framework) {
processedAnswers.frameworks.push(answers.framework)
}
if (answers.requirejs) {
processedAnswers.frameworks.push('requirejs')
processedAnswers.files = answers.includedFiles || []
processedAnswers.onlyServedFiles = answers.files
if (answers.generateTestMain) {
processedAnswers.files.push(testMainFile)
}
}
const allPatterns = answers.files.concat(answers.includedFiles || [])
if (allPatterns.some((pattern) => mm(pattern, '**/*.coffee'))) {
installPackage('karma-coffee-preprocessor')
processedAnswers.preprocessors['**/*.coffee'] = ['coffee']
}
return processedAnswers
}
exports.init = function (config) {
logger.setupFromConfig(config)
const colorScheme = !helper.isDefined(config.colors) || config.colors ? COLOR_SCHEME.ON : COLOR_SCHEME.OFF
// need to be registered before creating readlineInterface
process.stdin.on('keypress', function (s, key) {
sm.onKeypress(key)
})
const rli = readline.createInterface(process.stdin, process.stdout)
const sm = new StateMachine(rli, colorScheme)
rli.on('line', sm.onLine.bind(sm))
// clean colors
rli.on('SIGINT', function () {
sm.kill()
process.exit(0)
})
sm.process(questions, function (answers) {
const cwd = process.cwd()
const configFile = config.configFile || 'karma.conf.js'
const isCoffee = path.extname(configFile) === '.coffee'
const testMainFile = isCoffee ? 'test-main.coffee' : 'test-main.js'
const formatter = formatters.createForPath(configFile)
const processedAnswers = processAnswers(answers, getBasePath(configFile, cwd), testMainFile)
const configFilePath = path.resolve(cwd, configFile)
const testMainFilePath = path.resolve(cwd, testMainFile)
if (isCoffee) {
installPackage('coffeescript')
}
if (processedAnswers.generateTestMain) {
formatter.writeRequirejsConfigFile(testMainFilePath)
console.log(colorScheme.success(`RequireJS bootstrap file generated at "${testMainFilePath}".`))
}
formatter.writeConfigFile(configFilePath, processedAnswers)
console.log(colorScheme.success(`Config file generated at "${configFilePath}".`))
})
}

28
my-app/node_modules/karma/lib/init/color_schemes.js generated vendored Executable file
View file

@ -0,0 +1,28 @@
const COLORS_ON = {
RESET: '\x1B[39m',
ANSWER: '\x1B[36m', // NYAN
SUCCESS: '\x1B[32m', // GREEN
QUESTION: '\x1B[1m', // BOLD
question: function (str) {
return this.QUESTION + str + '\x1B[22m'
},
success: function (str) {
return this.SUCCESS + str + this.RESET
}
}
const COLORS_OFF = {
RESET: '',
ANSWER: '',
SUCCESS: '',
QUESTION: '',
question: function (str) {
return str
},
success: function (str) {
return str
}
}
exports.ON = COLORS_ON
exports.OFF = COLORS_OFF

116
my-app/node_modules/karma/lib/init/formatters.js generated vendored Executable file
View file

@ -0,0 +1,116 @@
'use strict'
const path = require('path')
const FileUtils = require('../utils/file-utils')
function quote (value) {
return `'${value}'`
}
function formatLine (items) {
return items.map(quote).join(', ')
}
function formatMultiLines (items) {
return items
.map((file) => '\n ' + file)
.join(',')
}
function formatFiles (includedFiles, onlyServedFiles) {
const lines = []
.concat(includedFiles.map(quote))
.concat(onlyServedFiles.map((file) => `{ pattern: ${quote(file)}, included: false }`))
return formatMultiLines(lines)
}
function formatPreprocessors (preprocessors) {
const lines = Object.keys(preprocessors)
.map((pattern) => `${quote(pattern)}: [${formatLine(preprocessors[pattern])}]`)
return formatMultiLines(lines)
}
function getConfigPath (file) {
return path.join(__dirname, `/../../${file}`)
}
class JavaScriptFormatter {
constructor () {
this.TEMPLATE_FILE_PATH = getConfigPath('config.tpl.js')
this.REQUIREJS_TEMPLATE_FILE = getConfigPath('requirejs.config.tpl.js')
}
generateConfigFile (answers) {
const replacements = this.formatAnswers(answers)
return FileUtils
.readFile(this.TEMPLATE_FILE_PATH)
.replace(/%(.*)%/g, (a, key) => replacements[key])
}
writeConfigFile (path, answers) {
FileUtils.saveFile(path, this.generateConfigFile(answers))
}
writeRequirejsConfigFile (path) {
FileUtils.copyFile(this.REQUIREJS_TEMPLATE_FILE, path)
}
formatAnswers (answers) {
return {
DATE: new Date(),
BASE_PATH: answers.basePath,
FRAMEWORKS: formatLine(answers.frameworks),
FILES: formatFiles(answers.files, answers.onlyServedFiles),
EXCLUDE: formatFiles(answers.exclude, []),
AUTO_WATCH: answers.autoWatch ? 'true' : 'false',
BROWSERS: formatLine(answers.browsers),
PREPROCESSORS: formatPreprocessors(answers.preprocessors)
}
}
}
class CoffeeFormatter extends JavaScriptFormatter {
constructor () {
super()
this.TEMPLATE_FILE_PATH = getConfigPath('config.tpl.coffee')
this.REQUIREJS_TEMPLATE_FILE = getConfigPath('requirejs.config.tpl.coffee')
}
}
class LiveFormatter extends JavaScriptFormatter {
constructor () {
super()
this.TEMPLATE_FILE_PATH = getConfigPath('config.tpl.ls')
}
}
class TypeFormatter extends JavaScriptFormatter {
constructor () {
super()
this.TEMPLATE_FILE_PATH = getConfigPath('config.tpl.ts')
}
}
exports.JavaScript = JavaScriptFormatter
exports.Coffee = CoffeeFormatter
exports.Live = LiveFormatter
exports.Type = TypeFormatter
exports.createForPath = function (path) {
if (/\.coffee$/.test(path)) {
return new CoffeeFormatter()
}
if (/\.ls$/.test(path)) {
return new LiveFormatter()
}
if (/\.ts$/.test(path)) {
return new TypeFormatter()
}
return new JavaScriptFormatter()
}

15
my-app/node_modules/karma/lib/init/log-queue.js generated vendored Executable file
View file

@ -0,0 +1,15 @@
'use strict'
const logQueue = []
function printLogQueue () {
logQueue.forEach((log) => log())
logQueue.length = 0
}
function push (log) {
logQueue.push(log)
}
module.exports = {
printLogQueue, push
}

143
my-app/node_modules/karma/lib/init/state_machine.js generated vendored Executable file
View file

@ -0,0 +1,143 @@
'use strict'
const logQueue = require('./log-queue')
let questions
let currentQuestion
let answers
let currentOptions
let currentOptionsPointer
let currentQuestionId
let done
class StateMachine {
constructor (rli, colors) {
this.rli = rli
this.colors = colors
}
showPrompt () {
this.rli.write(this.colors.ANSWER)
this.rli.prompt()
}
onKeypress (key) {
if (!currentOptions || !key) {
return
}
if (key.name === 'tab' || key.name === 'right' || key.name === 'down') {
this.suggestOption(currentOptionsPointer + 1)
} else if (key.name === 'left' || key.name === 'up') {
this.suggestOption(currentOptionsPointer - 1)
}
if (!key.ctrl && !key.meta && key.name !== 'enter' && key.name !== 'return') {
key.name = 'escape'
}
}
suggestOption (index) {
if (!currentOptions) {
return
}
if (index === -1) {
currentOptionsPointer = currentOptions.length - 1
} else if (index === currentOptions.length) {
currentOptionsPointer = 0
} else {
currentOptionsPointer = index
}
this.rli._deleteLineLeft()
this.rli._deleteLineRight()
this.rli.write(currentOptions[currentOptionsPointer])
}
kill () {
currentOptions = null
currentQuestionId = null
this.rli.write('\n' + this.colors.RESET + '\n')
this.rli.close()
}
onLine (line) {
if (currentQuestionId) {
this.rli.write(this.colors.RESET)
line = line.trim().replace(this.colors.ANSWER, '').replace(this.colors.RESET, '')
if (currentOptions) {
currentOptionsPointer = currentOptions.indexOf(line)
if (currentOptionsPointer === -1) {
return
}
}
if (line === '') {
line = null
}
if (currentQuestion.boolean) {
line = (line === 'yes' || line === 'true' || line === 'on')
}
if (line !== null && currentQuestion.validate) {
currentQuestion.validate(line)
}
if (currentQuestion.multiple) {
answers[currentQuestionId] = answers[currentQuestionId] || []
if (line !== null) {
answers[currentQuestionId].push(line)
this.showPrompt()
if (currentOptions) {
currentOptions.splice(currentOptionsPointer, 1)
currentOptionsPointer = -1
}
} else {
this.nextQuestion()
}
} else {
answers[currentQuestionId] = line
this.nextQuestion()
}
}
}
nextQuestion () {
currentQuestion = questions.shift()
while (currentQuestion && currentQuestion.condition && !currentQuestion.condition(answers)) {
currentQuestion = questions.shift()
}
logQueue.printLogQueue()
if (currentQuestion) {
currentQuestionId = null
this.rli.write('\n' + this.colors.question(currentQuestion.question) + '\n')
this.rli.write(currentQuestion.hint + '\n')
this.showPrompt()
currentOptions = currentQuestion.options || null
currentQuestionId = currentQuestion.id
this.suggestOption(0)
} else {
this.kill()
done(answers)
}
}
process (_questions, _done) {
questions = _questions
answers = {}
done = _done
this.nextQuestion()
}
}
module.exports = StateMachine

199
my-app/node_modules/karma/lib/launcher.js generated vendored Executable file
View file

@ -0,0 +1,199 @@
'use strict'
const Jobs = require('qjobs')
const log = require('./logger').create('launcher')
const baseDecorator = require('./launchers/base').decoratorFactory
const captureTimeoutDecorator = require('./launchers/capture_timeout').decoratorFactory
const retryDecorator = require('./launchers/retry').decoratorFactory
const processDecorator = require('./launchers/process').decoratorFactory
// TODO(vojta): remove once nobody uses it
const baseBrowserDecoratorFactory = function (
baseLauncherDecorator,
captureTimeoutLauncherDecorator,
retryLauncherDecorator,
processLauncherDecorator,
processKillTimeout
) {
return function (launcher) {
baseLauncherDecorator(launcher)
captureTimeoutLauncherDecorator(launcher)
retryLauncherDecorator(launcher)
processLauncherDecorator(launcher, processKillTimeout)
}
}
class Launcher {
constructor (server, emitter, injector) {
this._server = server
this._emitter = emitter
this._injector = injector
this._browsers = []
this._lastStartTime = null
// Attach list of dependency injection parameters to methods.
this.launch.$inject = [
'config.browsers',
'config.concurrency'
]
this.launchSingle.$inject = [
'config.protocol',
'config.hostname',
'config.port',
'config.urlRoot',
'config.upstreamProxy',
'config.processKillTimeout'
]
this._emitter.on('exit', (callback) => this.killAll(callback))
}
getBrowserById (id) {
return this._browsers.find((browser) => browser.id === id)
}
launchSingle (protocol, hostname, port, urlRoot, upstreamProxy, processKillTimeout) {
if (upstreamProxy) {
protocol = upstreamProxy.protocol
hostname = upstreamProxy.hostname
port = upstreamProxy.port
urlRoot = upstreamProxy.path + urlRoot.slice(1)
}
return (name) => {
let browser
const locals = {
id: ['value', Launcher.generateId()],
name: ['value', name],
processKillTimeout: ['value', processKillTimeout],
baseLauncherDecorator: ['factory', baseDecorator],
captureTimeoutLauncherDecorator: ['factory', captureTimeoutDecorator],
retryLauncherDecorator: ['factory', retryDecorator],
processLauncherDecorator: ['factory', processDecorator],
baseBrowserDecorator: ['factory', baseBrowserDecoratorFactory]
}
// TODO(vojta): determine script from name
if (name.includes('/')) {
name = 'Script'
}
try {
browser = this._injector.createChild([locals], ['launcher:' + name]).get('launcher:' + name)
} catch (e) {
if (e.message.includes(`No provider for "launcher:${name}"`)) {
log.error(`Cannot load browser "${name}": it is not registered! Perhaps you are missing some plugin?`)
} else {
log.error(`Cannot load browser "${name}"!\n ` + e.stack)
}
this._emitter.emit('load_error', 'launcher', name)
return
}
this.jobs.add((args, done) => {
log.info(`Starting browser ${browser.displayName || browser.name}`)
browser.on('browser_process_failure', () => done(browser.error))
browser.on('done', () => {
if (!browser.error && browser.state !== browser.STATE_RESTARTING) {
done(null, browser)
}
})
browser.start(`${protocol}//${hostname}:${port}${urlRoot}`)
}, [])
this.jobs.run()
this._browsers.push(browser)
}
}
launch (names, concurrency) {
log.info(`Launching browsers ${names.join(', ')} with concurrency ${concurrency === Infinity ? 'unlimited' : concurrency}`)
this.jobs = new Jobs({ maxConcurrency: concurrency })
this._lastStartTime = Date.now()
if (this._server.loadErrors.length) {
this.jobs.add((args, done) => done(), [])
} else {
names.forEach((name) => this._injector.invoke(this.launchSingle, this)(name))
}
this.jobs.on('end', (err) => {
log.debug('Finished all browsers')
if (err) {
log.error(err)
}
})
this.jobs.run()
return this._browsers
}
kill (id, callback) {
callback = callback || function () {}
const browser = this.getBrowserById(id)
if (browser) {
browser.forceKill().then(callback)
return true
}
process.nextTick(callback)
return false
}
restart (id) {
const browser = this.getBrowserById(id)
if (browser) {
browser.restart()
return true
}
return false
}
killAll (callback) {
callback = callback || function () {}
log.debug('Disconnecting all browsers')
if (!this._browsers.length) {
return process.nextTick(callback)
}
Promise.all(
this._browsers
.map((browser) => browser.forceKill())
).then(callback)
}
areAllCaptured () {
return this._browsers.every((browser) => browser.isCaptured())
}
markCaptured (id) {
const browser = this.getBrowserById(id)
if (browser) {
browser.markCaptured()
log.debug(`${browser.name} (id ${browser.id}) captured in ${(Date.now() - this._lastStartTime) / 1000} secs`)
}
}
static generateId () {
return Math.floor(Math.random() * 100000000).toString()
}
}
Launcher.factory = function (server, emitter, injector) {
return new Launcher(server, emitter, injector)
}
Launcher.factory.$inject = ['server', 'emitter', 'injector']
exports.Launcher = Launcher

140
my-app/node_modules/karma/lib/launchers/base.js generated vendored Executable file
View file

@ -0,0 +1,140 @@
const KarmaEventEmitter = require('../events').EventEmitter
const EventEmitter = require('events').EventEmitter
const log = require('../logger').create('launcher')
const helper = require('../helper')
const BEING_CAPTURED = 'BEING_CAPTURED'
const CAPTURED = 'CAPTURED'
const BEING_KILLED = 'BEING_KILLED'
const FINISHED = 'FINISHED'
const RESTARTING = 'RESTARTING'
const BEING_FORCE_KILLED = 'BEING_FORCE_KILLED'
/**
* Base launcher that any custom launcher extends.
*/
function BaseLauncher (id, emitter) {
if (this.start) {
return
}
// TODO(vojta): figure out how to do inheritance with DI
Object.keys(EventEmitter.prototype).forEach(function (method) {
this[method] = EventEmitter.prototype[method]
}, this)
this.bind = KarmaEventEmitter.prototype.bind.bind(this)
this.emitAsync = KarmaEventEmitter.prototype.emitAsync.bind(this)
this.id = id
this._state = null
Object.defineProperty(this, 'state', {
get: () => {
return this._state
},
set: (toState) => {
log.debug(`${this._state} -> ${toState}`)
this._state = toState
}
})
this.error = null
let killingPromise
let previousUrl
this.start = function (url) {
previousUrl = url
this.error = null
this.state = BEING_CAPTURED
this.emit('start', url + '?id=' + this.id + (helper.isDefined(this.displayName) ? '&displayName=' + encodeURIComponent(this.displayName) : ''))
}
this.kill = function () {
// Already killed, or being killed.
if (killingPromise) {
return killingPromise
}
killingPromise = this.emitAsync('kill').then(() => {
this.state = FINISHED
})
this.state = BEING_KILLED
return killingPromise
}
this.forceKill = function () {
this.kill()
this.state = BEING_FORCE_KILLED
return killingPromise
}
this.restart = function () {
if (this.state === BEING_FORCE_KILLED) {
return
}
if (!killingPromise) {
killingPromise = this.emitAsync('kill')
}
killingPromise.then(() => {
if (this.state === BEING_FORCE_KILLED) {
this.state = FINISHED
} else {
killingPromise = null
log.debug(`Restarting ${this.name}`)
this.start(previousUrl)
}
})
this.state = RESTARTING
}
this.markCaptured = function () {
if (this.state === BEING_CAPTURED) {
this.state = CAPTURED
}
}
this.isCaptured = function () {
return this.state === CAPTURED
}
this.toString = function () {
return this.name
}
this._done = function (error) {
killingPromise = killingPromise || Promise.resolve()
this.error = this.error || error
this.emit('done')
if (this.error && this.state !== BEING_FORCE_KILLED && this.state !== RESTARTING) {
emitter.emit('browser_process_failure', this)
}
this.state = FINISHED
}
this.STATE_BEING_CAPTURED = BEING_CAPTURED
this.STATE_CAPTURED = CAPTURED
this.STATE_BEING_KILLED = BEING_KILLED
this.STATE_FINISHED = FINISHED
this.STATE_RESTARTING = RESTARTING
this.STATE_BEING_FORCE_KILLED = BEING_FORCE_KILLED
}
BaseLauncher.decoratorFactory = function (id, emitter) {
return function (launcher) {
BaseLauncher.call(launcher, id, emitter)
}
}
module.exports = BaseLauncher

43
my-app/node_modules/karma/lib/launchers/capture_timeout.js generated vendored Executable file
View file

@ -0,0 +1,43 @@
const log = require('../logger').create('launcher')
/**
* Kill browser if it does not capture in given `captureTimeout`.
*/
function CaptureTimeoutLauncher (timer, captureTimeout) {
if (!captureTimeout) {
return
}
let pendingTimeoutId = null
this.on('start', () => {
pendingTimeoutId = timer.setTimeout(() => {
pendingTimeoutId = null
if (this.state !== this.STATE_BEING_CAPTURED) {
return
}
log.warn(`${this.name} has not captured in ${captureTimeout} ms, killing.`)
this.error = 'timeout'
this.kill()
}, captureTimeout)
})
this.on('done', () => {
if (pendingTimeoutId) {
timer.clearTimeout(pendingTimeoutId)
pendingTimeoutId = null
}
})
}
CaptureTimeoutLauncher.decoratorFactory = function (timer,
/* config.captureTimeout */ captureTimeout) {
return function (launcher) {
CaptureTimeoutLauncher.call(launcher, timer, captureTimeout)
}
}
CaptureTimeoutLauncher.decoratorFactory.$inject = ['timer', 'config.captureTimeout']
module.exports = CaptureTimeoutLauncher

185
my-app/node_modules/karma/lib/launchers/process.js generated vendored Executable file
View file

@ -0,0 +1,185 @@
const path = require('path')
const log = require('../logger').create('launcher')
const env = process.env
function ProcessLauncher (spawn, tempDir, timer, processKillTimeout) {
const self = this
let onExitCallback
const killTimeout = processKillTimeout || 2000
// Will hold output from the spawned child process
const streamedOutputs = {
stdout: '',
stderr: ''
}
this._tempDir = tempDir.getPath(`/karma-${this.id.toString()}`)
this.on('start', function (url) {
tempDir.create(self._tempDir)
self._start(url)
})
this.on('kill', function (done) {
if (!self._process) {
return process.nextTick(done)
}
onExitCallback = done
self._process.kill()
self._killTimer = timer.setTimeout(self._onKillTimeout, killTimeout)
})
this._start = function (url) {
self._execCommand(self._getCommand(), self._getOptions(url))
}
this._getCommand = function () {
return env[self.ENV_CMD] || self.DEFAULT_CMD[process.platform]
}
this._getOptions = function (url) {
return [url]
}
// Normalize the command, remove quotes (spawn does not like them).
this._normalizeCommand = function (cmd) {
if (cmd.charAt(0) === cmd.charAt(cmd.length - 1) && '\'`"'.includes(cmd.charAt(0))) {
cmd = cmd.slice(1, -1)
log.warn(`The path should not be quoted.\n Normalized the path to ${cmd}`)
}
return path.normalize(cmd)
}
this._onStdout = function (data) {
streamedOutputs.stdout += data
}
this._onStderr = function (data) {
streamedOutputs.stderr += data
}
this._execCommand = function (cmd, args) {
if (!cmd) {
log.error(`No binary for ${self.name} browser on your platform.\n Please, set "${self.ENV_CMD}" env variable.`)
// disable restarting
self._retryLimit = -1
return self._clearTempDirAndReportDone('no binary')
}
cmd = this._normalizeCommand(cmd)
log.debug(cmd + ' ' + args.join(' '))
self._process = spawn(cmd, args)
let errorOutput = ''
self._process.stdout.on('data', self._onStdout)
self._process.stderr.on('data', self._onStderr)
self._process.on('exit', function (code, signal) {
self._onProcessExit(code, signal, errorOutput)
})
self._process.on('error', function (err) {
if (err.code === 'ENOENT') {
self._retryLimit = -1
errorOutput = `Can not find the binary ${cmd}\n\tPlease set env variable ${self.ENV_CMD}`
} else if (err.code === 'EACCES') {
self._retryLimit = -1
errorOutput = `Permission denied accessing the binary ${cmd}\n\tMaybe it's a directory?`
} else {
errorOutput += err.toString()
}
self._onProcessExit(-1, null, errorOutput)
})
self._process.stderr.on('data', function (errBuff) {
errorOutput += errBuff.toString()
})
}
this._onProcessExit = function (code, signal, errorOutput) {
if (!self._process) {
// Both exit and error events trigger _onProcessExit(), but we only need one cleanup.
return
}
log.debug(`Process ${self.name} exited with code ${code} and signal ${signal}`)
let error = null
if (self.state === self.STATE_BEING_CAPTURED) {
log.error(`Cannot start ${self.name}\n\t${errorOutput}`)
error = 'cannot start'
}
if (self.state === self.STATE_CAPTURED) {
log.error(`${self.name} crashed.\n\t${errorOutput}`)
error = 'crashed'
}
if (error) {
log.error(`${self.name} stdout: ${streamedOutputs.stdout}`)
log.error(`${self.name} stderr: ${streamedOutputs.stderr}`)
}
self._process = null
streamedOutputs.stdout = ''
streamedOutputs.stderr = ''
if (self._killTimer) {
timer.clearTimeout(self._killTimer)
self._killTimer = null
}
self._clearTempDirAndReportDone(error)
}
this._clearTempDirAndReportDone = function (error) {
tempDir.remove(self._tempDir, function () {
self._done(error)
if (onExitCallback) {
onExitCallback()
onExitCallback = null
}
})
}
this._onKillTimeout = function () {
if (self.state !== self.STATE_BEING_KILLED && self.state !== self.STATE_BEING_FORCE_KILLED) {
return
}
log.warn(`${self.name} was not killed in ${killTimeout} ms, sending SIGKILL.`)
self._process.kill('SIGKILL')
// NOTE: https://github.com/karma-runner/karma/pull/1184
// NOTE: SIGKILL is just a signal. Processes should never ignore it, but they can.
// If a process gets into a state where it doesn't respond in a reasonable amount of time
// Karma should warn, and continue as though the kill succeeded.
// This a certainly suboptimal, but it is better than having the test harness hang waiting
// for a zombie child process to exit.
self._killTimer = timer.setTimeout(function () {
log.warn(`${self.name} was not killed by SIGKILL in ${killTimeout} ms, continuing.`)
self._onProcessExit(-1, null, '')
}, killTimeout)
}
}
ProcessLauncher.decoratorFactory = function (timer) {
return function (launcher, processKillTimeout) {
const spawn = require('child_process').spawn
function spawnWithoutOutput () {
const proc = spawn.apply(null, arguments)
proc.stdout.resume()
proc.stderr.resume()
return proc
}
ProcessLauncher.call(launcher, spawnWithoutOutput, require('../temp_dir'), timer, processKillTimeout)
}
}
module.exports = ProcessLauncher

31
my-app/node_modules/karma/lib/launchers/retry.js generated vendored Executable file
View file

@ -0,0 +1,31 @@
const log = require('../logger').create('launcher')
function RetryLauncher (retryLimit) {
this._retryLimit = retryLimit
this.on('done', () => {
if (!this.error) {
return
}
if (this._retryLimit > 0) {
log.info(`Trying to start ${this.name} again (${retryLimit - this._retryLimit + 1}/${retryLimit}).`)
this.restart()
this._retryLimit--
} else if (this._retryLimit === 0) {
log.error(`${this.name} failed ${retryLimit} times (${this.error}). Giving up.`)
} else {
log.debug(`${this.name} failed (${this.error}). Not restarting.`)
}
})
}
RetryLauncher.decoratorFactory = function (retryLimit) {
return function (launcher) {
RetryLauncher.call(launcher, retryLimit)
}
}
RetryLauncher.decoratorFactory.$inject = ['config.retryLimit']
module.exports = RetryLauncher

115
my-app/node_modules/karma/lib/logger.js generated vendored Executable file
View file

@ -0,0 +1,115 @@
// This is the **logger** module for *Karma*. It uses
// [log4js](https://github.com/nomiddlename/log4js-node) to handle and
// configure all logging that happens inside of *Karma*.
// ### Helpers and Setup
let log4js = require('log4js')
const helper = require('./helper')
const constant = require('./constants')
// #### Public Functions
// Setup the logger by passing in the configuration options. It needs
// three arguments:
//
// setup(logLevel, colors, appenders)
//
// * `logLevel`: *String* Defines the global log level.
// * `colors`: *Boolean* Use colors in the stdout or not.
// * `appenders`: *Object* This will be passed as appenders to log4js
// to allow for fine grained configuration of log4js. For more information
// see https://github.com/nomiddlename/log4js-node.
// *Array* is also accepted for backwards compatibility.
function setup (level, colors, appenders) {
// Turn color on/off on the console appenders with pattern layout
const pattern = colors ? constant.COLOR_PATTERN : constant.NO_COLOR_PATTERN
if (appenders) {
// Convert Array to Object for backwards compatibility.
if (appenders.map) {
if (appenders.length === 0) {
appenders = [constant.CONSOLE_APPENDER]
}
const v1Appenders = appenders
appenders = {}
v1Appenders.forEach(function (appender, index) {
if (appender.type === 'console') {
appenders.console = appender
if (helper.isDefined(appender.layout) && appender.layout.type === 'pattern') {
appender.layout.pattern = pattern
}
} else {
appenders[index + ''] = appender
}
return appender
})
}
} else {
appenders = { console: constant.CONSOLE_APPENDER }
}
log4js.configure({
appenders: appenders,
categories: {
default: {
appenders: Object.keys(appenders),
level: level
}
}
})
}
// Setup the logger by passing in the config object. The function sets the
// `colors` and `logLevel` if they are defined. It takes two arguments:
//
// setupFromConfig(config, appenders)
//
// * `config`: *Object* The configuration object.
// * `appenders`: *Object* This will be passed as appenders to log4js
// to allow for fine grained configuration of log4js. For more information
// see https://github.com/nomiddlename/log4js-node.
// *Array* is also accepted for backwards compatibility.
function setupFromConfig (config, appenders) {
let useColors = true
let logLevel = constant.LOG_INFO
if (helper.isDefined(config.colors)) {
useColors = config.colors
}
if (helper.isDefined(config.logLevel)) {
logLevel = config.logLevel
}
setup(logLevel, useColors, appenders)
}
const loggerCache = {}
// Create a new logger. There are two optional arguments
// * `name`, which defaults to `karma` and
// If the `name = 'socket.io'` this will create a special wrapper
// to be used as a logger for socket.io.
// * `level`, which defaults to the global level.
function create (name, level) {
name = name || 'karma'
let logger
if (Object.prototype.hasOwnProperty.call(loggerCache, name)) {
logger = loggerCache[name]
} else {
logger = log4js.getLogger(name)
loggerCache[name] = logger
}
if (helper.isDefined(level)) {
logger.setLevel(level)
}
return logger
}
// #### Publish
exports.create = create
exports.setup = setup
exports.setupFromConfig = setupFromConfig
exports._rebindLog4js4testing = function (mockLog4js) {
log4js = mockLog4js
}

105
my-app/node_modules/karma/lib/middleware/common.js generated vendored Executable file
View file

@ -0,0 +1,105 @@
/**
* This module contains some common helpers shared between middlewares
*/
'use strict'
const mime = require('mime')
const parseRange = require('range-parser')
const log = require('../logger').create('web-server')
function createServeFile (fs, directory, config) {
const cache = Object.create(null)
return function (filepath, rangeHeader, response, transform, content, doNotCache) {
let responseData
function convertForRangeRequest () {
const range = parseRange(responseData.length, rangeHeader)
if (range === -2) {
return 200 // malformed header string
} else if (range === -1) {
responseData = Buffer.alloc(0) // unsatisfiable range
return 416
} else if (range.type === 'bytes') {
responseData = Buffer.from(responseData)
if (range.length === 1) {
const { start, end } = range[0]
response.setHeader('Content-Range', `bytes ${start}-${end}/${responseData.length}`)
response.setHeader('Accept-Ranges', 'bytes')
response.setHeader('Content-Length', end - start + 1)
responseData = responseData.slice(start, end + 1)
return 206
} else {
responseData = Buffer.alloc(0) // Multiple ranges are not supported. Maybe future?
return 416
}
}
return 200 // All other states, ignore
}
if (directory) {
filepath = directory + filepath
}
if (!content && cache[filepath]) {
content = cache[filepath]
}
if (config && config.customHeaders && config.customHeaders.length > 0) {
config.customHeaders.forEach((header) => {
const regex = new RegExp(header.match)
if (regex.test(filepath)) {
log.debug(`setting header: ${header.name} for: ${filepath}`)
response.setHeader(header.name, header.value)
}
})
}
if (content && !doNotCache) {
log.debug(`serving (cached): ${filepath}`)
response.setHeader('Content-Type', mime.getType(filepath, 'text/plain'))
responseData = (transform && transform(content)) || content
response.writeHead(rangeHeader ? convertForRangeRequest() : 200)
return response.end(responseData)
}
return fs.readFile(filepath, function (error, data) {
if (error) {
return serve404(response, filepath)
}
if (!doNotCache) {
cache[filepath] = data.toString()
}
log.debug('serving: ' + filepath)
response.setHeader('Content-Type', mime.getType(filepath, 'text/plain'))
responseData = (transform && transform(data.toString())) || data
response.writeHead(rangeHeader ? convertForRangeRequest() : 200)
return response.end(responseData)
})
}
}
function serve404 (response, path) {
log.warn(`404: ${path}`)
response.writeHead(404)
return response.end('NOT FOUND')
}
function setNoCacheHeaders (response) {
response.setHeader('Cache-Control', 'no-cache')
response.setHeader('Pragma', 'no-cache')
response.setHeader('Expires', (new Date(0)).toUTCString())
}
function setHeavyCacheHeaders (response) {
response.setHeader('Cache-Control', 'public, max-age=31536000')
}
// PUBLIC API
exports.createServeFile = createServeFile
exports.setNoCacheHeaders = setNoCacheHeaders
exports.setHeavyCacheHeaders = setHeavyCacheHeaders
exports.serve404 = serve404

259
my-app/node_modules/karma/lib/middleware/karma.js generated vendored Executable file
View file

@ -0,0 +1,259 @@
/**
* Karma middleware is responsible for serving:
* - client.html (the entrypoint for capturing a browser)
* - debug.html
* - context.html (the execution context, loaded within an iframe)
* - karma.js
*
* The main part is generating context.html, as it contains:
* - generating mappings
* - including <script> and <link> tags
* - setting propert caching headers
*/
const url = require('url')
const log = require('../logger').create('middleware:karma')
const stripHost = require('./strip_host').stripHost
const common = require('./common')
const VERSION = require('../constants').VERSION
const SCRIPT_TYPE = {
js: 'text/javascript',
module: 'module'
}
const FILE_TYPES = [
'css',
'html',
'js',
'module',
'dom'
]
function filePathToUrlPath (filePath, basePath, urlRoot, proxyPath) {
if (filePath.startsWith(basePath)) {
return proxyPath + urlRoot.slice(1) + 'base' + filePath.slice(basePath.length)
}
return proxyPath + urlRoot.slice(1) + 'absolute' + filePath
}
function getQuery (urlStr) {
// eslint-disable-next-line node/no-deprecated-api
return url.parse(urlStr, true).query || {}
}
function getXUACompatibleMetaElement (url) {
const query = getQuery(url)
if (query['x-ua-compatible']) {
return `<meta http-equiv="X-UA-Compatible" content="${query['x-ua-compatible']}"/>`
}
return ''
}
function getXUACompatibleUrl (url) {
const query = getQuery(url)
if (query['x-ua-compatible']) {
return '?x-ua-compatible=' + encodeURIComponent(query['x-ua-compatible'])
}
return ''
}
function createKarmaMiddleware (
filesPromise,
serveStaticFile,
serveFile,
injector,
basePath,
urlRoot,
upstreamProxy,
browserSocketTimeout
) {
const proxyPath = upstreamProxy ? upstreamProxy.path : '/'
return function (request, response, next) {
// These config values should be up to date on every request
const client = injector.get('config.client')
const customContextFile = injector.get('config.customContextFile')
const customDebugFile = injector.get('config.customDebugFile')
const customClientContextFile = injector.get('config.customClientContextFile')
const includeCrossOriginAttribute = injector.get('config.crossOriginAttribute')
const normalizedUrl = stripHost(request.url) || request.url
// For backwards compatibility in middleware plugins, remove in v4.
request.normalizedUrl = normalizedUrl
let requestUrl = normalizedUrl.replace(/\?.*/, '')
const requestedRangeHeader = request.headers.range
// redirect /__karma__ to /__karma__ (trailing slash)
if (requestUrl === urlRoot.slice(0, -1)) {
response.setHeader('Location', proxyPath + urlRoot.slice(1))
response.writeHead(301)
return response.end('MOVED PERMANENTLY')
}
// ignore urls outside urlRoot
if (!requestUrl.startsWith(urlRoot)) {
return next()
}
// remove urlRoot prefix
requestUrl = requestUrl.slice(urlRoot.length - 1)
// serve client.html
if (requestUrl === '/') {
// redirect client_with_context.html
if (!client.useIframe && client.runInParent) {
requestUrl = '/client_with_context.html'
} else { // serve client.html
return serveStaticFile('/client.html', requestedRangeHeader, response, (data) =>
data
.replace('%X_UA_COMPATIBLE%', getXUACompatibleMetaElement(request.url))
.replace('%X_UA_COMPATIBLE_URL%', getXUACompatibleUrl(request.url)))
}
}
if (['/karma.js', '/context.js', '/debug.js'].includes(requestUrl)) {
return serveStaticFile(requestUrl, requestedRangeHeader, response, (data) =>
data
.replace('%KARMA_URL_ROOT%', urlRoot)
.replace('%KARMA_VERSION%', VERSION)
.replace('%KARMA_PROXY_PATH%', proxyPath)
.replace('%BROWSER_SOCKET_TIMEOUT%', browserSocketTimeout))
}
// serve the favicon
if (requestUrl === '/favicon.ico') {
return serveStaticFile(requestUrl, requestedRangeHeader, response)
}
// serve context.html - execution context within the iframe
// or debug.html - execution context without channel to the server
const isRequestingContextFile = requestUrl === '/context.html'
const isRequestingDebugFile = requestUrl === '/debug.html'
const isRequestingClientContextFile = requestUrl === '/client_with_context.html'
if (isRequestingContextFile || isRequestingDebugFile || isRequestingClientContextFile) {
return filesPromise.then((files) => {
let fileServer
let requestedFileUrl
log.debug('custom files', customContextFile, customDebugFile, customClientContextFile)
if (isRequestingContextFile && customContextFile) {
log.debug(`Serving customContextFile ${customContextFile}`)
fileServer = serveFile
requestedFileUrl = customContextFile
} else if (isRequestingDebugFile && customDebugFile) {
log.debug(`Serving customDebugFile ${customDebugFile}`)
fileServer = serveFile
requestedFileUrl = customDebugFile
} else if (isRequestingClientContextFile && customClientContextFile) {
log.debug(`Serving customClientContextFile ${customClientContextFile}`)
fileServer = serveFile
requestedFileUrl = customClientContextFile
} else {
log.debug(`Serving static request ${requestUrl}`)
fileServer = serveStaticFile
requestedFileUrl = requestUrl
}
fileServer(requestedFileUrl, requestedRangeHeader, response, function (data) {
common.setNoCacheHeaders(response)
const scriptTags = []
for (const file of files.included) {
let filePath = file.path
const fileType = file.type || file.detectType()
if (!FILE_TYPES.includes(fileType)) {
if (file.type == null) {
log.warn(
'Unable to determine file type from the file extension, defaulting to js.\n' +
` To silence the warning specify a valid type for ${file.originalPath} in the configuration file.\n` +
' See https://karma-runner.github.io/latest/config/files.html'
)
} else {
log.warn(`Invalid file type (${file.type || 'empty string'}), defaulting to js.`)
}
}
if (!file.isUrl) {
filePath = filePathToUrlPath(filePath, basePath, urlRoot, proxyPath)
if (requestUrl === '/context.html') {
filePath += '?' + file.sha
}
}
const integrityAttribute = file.integrity ? ` integrity="${file.integrity}"` : ''
const crossOriginAttribute = includeCrossOriginAttribute ? ' crossorigin="anonymous"' : ''
if (fileType === 'css') {
scriptTags.push(`<link type="text/css" href="${filePath}" rel="stylesheet"${integrityAttribute}${crossOriginAttribute}>`)
} else if (fileType === 'dom') {
scriptTags.push(file.content)
} else if (fileType === 'html') {
scriptTags.push(`<link href="${filePath}" rel="import"${integrityAttribute}${crossOriginAttribute}>`)
} else {
const scriptType = (SCRIPT_TYPE[fileType] || 'text/javascript')
if (fileType === 'module') {
scriptTags.push(`<script onerror="throw 'Error loading ${filePath}'" type="${scriptType}" src="${filePath}"${integrityAttribute}${crossOriginAttribute}></script>`)
} else {
scriptTags.push(`<script type="${scriptType}" src="${filePath}"${integrityAttribute}${crossOriginAttribute}></script>`)
}
}
}
const scriptUrls = []
// For client_with_context, html elements are not added directly through an iframe.
// Instead, scriptTags is stored to window.__karma__.scriptUrls first. Later, the
// client will read window.__karma__.scriptUrls and dynamically add them to the DOM
// using DOMParser.
if (requestUrl === '/client_with_context.html') {
for (const script of scriptTags) {
scriptUrls.push(
// Escape characters with special roles (tags) in HTML. Open angle brackets are parsed as tags
// immediately, even if it is within double quotations in browsers
script.replace(/</g, '\\x3C').replace(/>/g, '\\x3E'))
}
}
const mappings = data.includes('%MAPPINGS%') ? files.served.map((file) => {
const filePath = filePathToUrlPath(file.path, basePath, urlRoot, proxyPath)
.replace(/\\/g, '\\\\') // Windows paths contain backslashes and generate bad IDs if not escaped
.replace(/'/g, '\\\'') // Escape single quotes - double quotes should not be allowed!
return ` '${filePath}': '${file.sha}'`
}) : []
return data
.replace('%SCRIPTS%', () => scriptTags.join('\n'))
.replace('%CLIENT_CONFIG%', 'window.__karma__.config = ' + JSON.stringify(client) + ';\n')
.replace('%SCRIPT_URL_ARRAY%', () => 'window.__karma__.scriptUrls = ' + JSON.stringify(scriptUrls) + ';\n')
.replace('%MAPPINGS%', () => 'window.__karma__.files = {\n' + mappings.join(',\n') + '\n};\n')
.replace('%X_UA_COMPATIBLE%', getXUACompatibleMetaElement(request.url))
})
})
} else if (requestUrl === '/context.json') {
return filesPromise.then((files) => {
common.setNoCacheHeaders(response)
response.writeHead(200)
response.end(JSON.stringify({
files: files.included.map((file) => filePathToUrlPath(file.path + '?' + file.sha, basePath, urlRoot, proxyPath))
}))
})
}
return next()
}
}
createKarmaMiddleware.$inject = [
'filesPromise',
'serveStaticFile',
'serveFile',
'injector',
'config.basePath',
'config.urlRoot',
'config.upstreamProxy',
'config.browserSocketTimeout'
]
// PUBLIC API
exports.create = createKarmaMiddleware

130
my-app/node_modules/karma/lib/middleware/proxy.js generated vendored Executable file
View file

@ -0,0 +1,130 @@
const url = require('url')
const { Agent: httpAgent } = require('http')
const { Agent: httpsAgent } = require('https')
const httpProxy = require('http-proxy')
const _ = require('lodash')
const { lookup } = require('../utils/dns-utils')
const log = require('../logger').create('proxy')
function parseProxyConfig (proxies, config) {
proxies = proxies || []
return _.sortBy(_.map(proxies, function (proxyConfiguration, proxyPath) {
if (typeof proxyConfiguration === 'string') {
proxyConfiguration = { target: proxyConfiguration }
}
let proxyUrl = proxyConfiguration.target
// eslint-disable-next-line node/no-deprecated-api
const proxyDetails = url.parse(proxyUrl)
let pathname = proxyDetails.pathname
if (proxyPath.endsWith('/') && !proxyUrl.endsWith('/')) {
log.warn(`proxy "${proxyUrl}" normalized to "${proxyUrl}/"`)
proxyUrl += '/'
pathname += '/'
}
if (!proxyPath.endsWith('/') && proxyUrl.endsWith('/')) {
log.warn(`proxy "${proxyPath}" normalized to "${proxyPath}/"`)
proxyPath += '/'
}
if (pathname === '/' && !proxyUrl.endsWith('/')) {
pathname = ''
}
const hostname = proxyDetails.hostname || config.hostname
const protocol = proxyDetails.protocol || config.protocol
const defaultPorts = {
'http:': '80',
'https:': '443'
}
const port = proxyDetails.port || defaultPorts[proxyDetails.protocol] || config.port
const changeOrigin = proxyConfiguration.changeOrigin || false
const Agent = protocol === 'https:' ? httpsAgent : httpAgent
const agent = new Agent({
keepAlive: true,
lookup
})
const proxy = httpProxy.createProxyServer({
target: { host: hostname, port, protocol },
xfwd: true,
changeOrigin: changeOrigin,
secure: config.proxyValidateSSL,
agent
})
;['proxyReq', 'proxyRes'].forEach(function (name) {
const callback = proxyDetails[name] || config[name]
if (callback) {
proxy.on(name, callback)
}
})
proxy.on('error', function proxyError (err, req, res) {
if (err.code === 'ECONNRESET' && req.socket.destroyed) {
log.debug(`failed to proxy ${req.url} (browser hung up the socket)`)
} else {
log.warn(`failed to proxy ${req.url} (${err.message})`)
}
res.destroy()
})
return { path: proxyPath, baseUrl: pathname, host: hostname, port, proxy, agent }
}), 'path').reverse()
}
/**
* Returns a handler which understands the proxies and its redirects, along with the proxy to use
* @param proxies An array of proxy record objects
* @param urlRoot The URL root that karma is mounted on
* @return {Function} handler function
*/
function createProxyHandler (proxies, urlRoot) {
if (!proxies.length) {
const nullProxy = (request, response, next) => next()
nullProxy.upgrade = () => {}
return nullProxy
}
function createProxy (request, response, next) {
const proxyRecord = proxies.find((p) => request.url.startsWith(p.path))
if (proxyRecord) {
log.debug(`proxying request - ${request.url} to ${proxyRecord.host}:${proxyRecord.port}`)
request.url = request.url.replace(proxyRecord.path, proxyRecord.baseUrl)
proxyRecord.proxy.web(request, response)
} else {
return next()
}
}
createProxy.upgrade = function (request, socket, head) {
// special-case karma's route to avoid upgrading it
if (request.url.startsWith(urlRoot)) {
log.debug(`NOT upgrading proxyWebSocketRequest ${request.url}`)
return
}
const proxyRecord = proxies.find((p) => request.url.startsWith(p.path))
if (proxyRecord) {
log.debug(`upgrade proxyWebSocketRequest ${request.url} to ${proxyRecord.host}:${proxyRecord.port}`)
request.url = request.url.replace(proxyRecord.path, proxyRecord.baseUrl)
proxyRecord.proxy.ws(request, socket, head)
}
}
return createProxy
}
exports.create = function (/* config */config, /* config.proxies */proxies, /* emitter */emitter) {
const proxyRecords = parseProxyConfig(proxies, config)
emitter.on('exit', (done) => {
log.debug('Destroying proxy agents')
proxyRecords.forEach((proxyRecord) => {
proxyRecord.agent.destroy()
})
done()
})
return createProxyHandler(proxyRecords, config.urlRoot)
}

114
my-app/node_modules/karma/lib/middleware/runner.js generated vendored Executable file
View file

@ -0,0 +1,114 @@
/**
* Runner middleware is responsible for communication with `karma run`.
*
* It basically triggers a test run and streams stdout back.
*/
const _ = require('lodash')
const path = require('path')
const helper = require('../helper')
const log = require('../logger').create()
const constant = require('../constants')
const json = require('body-parser').json()
// TODO(vojta): disable when single-run mode
function createRunnerMiddleware (emitter, fileList, capturedBrowsers, reporter, executor,
/* config.protocol */ protocol, /* config.hostname */ hostname, /* config.port */
port, /* config.urlRoot */ urlRoot, config) {
helper.saveOriginalArgs(config)
return function (request, response, next) {
if (request.url !== '/__run__' && request.url !== urlRoot + 'run') {
return next()
}
log.debug('Execution (fired by runner)')
response.writeHead(200)
if (!capturedBrowsers.length) {
const url = `${protocol}//${hostname}:${port}${urlRoot}`
return response.end(`No captured browser, open ${url}\n`)
}
json(request, response, function () {
if (!capturedBrowsers.areAllReady([])) {
response.write('Waiting for previous execution...\n')
}
const data = request.body
updateClientArgs(data)
handleRun(data)
refreshFileList(data).then(() => {
executor.schedule()
}).catch((error) => {
const errorMessage = `Error during refresh file list. ${error.stack || error}`
executor.scheduleError(errorMessage)
})
})
function updateClientArgs (data) {
helper.restoreOriginalArgs(config)
if (_.isEmpty(data.args)) {
log.debug('Ignoring empty client.args from run command')
} else if ((_.isArray(data.args) && _.isArray(config.client.args)) ||
(_.isPlainObject(data.args) && _.isPlainObject(config.client.args))) {
log.debug('Merging client.args with ', data.args)
config.client.args = _.merge(config.client.args, data.args)
} else {
log.warn('Replacing client.args with ', data.args, ' as their types do not match.')
config.client.args = data.args
}
}
async function refreshFileList (data) {
let fullRefresh = true
if (helper.isArray(data.changedFiles)) {
await Promise.all(data.changedFiles.map(async function (filepath) {
await fileList.changeFile(path.resolve(config.basePath, filepath))
fullRefresh = false
}))
}
if (helper.isArray(data.addedFiles)) {
await Promise.all(data.addedFiles.map(async function (filepath) {
await fileList.addFile(path.resolve(config.basePath, filepath))
fullRefresh = false
}))
}
if (helper.isArray(data.removedFiles)) {
await Promise.all(data.removedFiles.map(async function (filepath) {
await fileList.removeFile(path.resolve(config.basePath, filepath))
fullRefresh = false
}))
}
if (fullRefresh && data.refresh !== false) {
log.debug('Refreshing all the files / patterns')
await fileList.refresh()
}
}
function handleRun (data) {
emitter.once('run_start', function () {
const responseWrite = response.write.bind(response)
responseWrite.colors = data.colors
reporter.addAdapter(responseWrite)
// clean up, close runner response
emitter.once('run_complete', function (_browsers, results) {
reporter.removeAdapter(responseWrite)
const emptyTestSuite = (results.failed + results.success) === 0 ? 0 : 1
response.end(constant.EXIT_CODE + emptyTestSuite + results.exitCode)
})
})
}
}
}
createRunnerMiddleware.$inject = ['emitter', 'fileList', 'capturedBrowsers', 'reporter', 'executor',
'config.protocol', 'config.hostname', 'config.port', 'config.urlRoot', 'config']
// PUBLIC API
exports.create = createRunnerMiddleware

67
my-app/node_modules/karma/lib/middleware/source_files.js generated vendored Executable file
View file

@ -0,0 +1,67 @@
'use strict'
const querystring = require('querystring')
const common = require('./common')
const log = require('../logger').create('middleware:source-files')
function findByPath (files, path) {
return Array.from(files).find((file) => file.path === path)
}
function composeUrl (url, basePath, urlRoot) {
return url
.replace(urlRoot, '/')
.replace(/\?.*$/, '')
.replace(/^\/absolute/, '')
.replace(/^\/base/, basePath)
}
// Source Files middleware is responsible for serving all the source files under the test.
function createSourceFilesMiddleware (filesPromise, serveFile, basePath, urlRoot) {
return function (request, response, next) {
const requestedFilePath = composeUrl(request.url, basePath, urlRoot)
// When a path contains HTML-encoded characters (e.g %2F used by Jenkins for branches with /)
const requestedFilePathUnescaped = composeUrl(querystring.unescape(request.url), basePath, urlRoot)
request.pause()
log.debug(`Requesting ${request.url}`)
log.debug(`Fetching ${requestedFilePath}`)
return filesPromise.then(function (files) {
// TODO(vojta): change served to be a map rather then an array
const file = findByPath(files.served, requestedFilePath) || findByPath(files.served, requestedFilePathUnescaped)
const rangeHeader = request.headers.range
if (file) {
const acceptEncodingHeader = request.headers['accept-encoding']
const matchedEncoding = Object.keys(file.encodings).find(
(encoding) => new RegExp(`(^|.*, ?)${encoding}(,|$)`).test(acceptEncodingHeader)
)
const content = file.encodings[matchedEncoding] || file.content
serveFile(file.contentPath || file.path, rangeHeader, response, function () {
if (/\?\w+/.test(request.url)) {
common.setHeavyCacheHeaders(response) // files with timestamps - cache one year, rely on timestamps
} else {
common.setNoCacheHeaders(response) // without timestamps - no cache (debug)
}
if (matchedEncoding) {
response.setHeader('Content-Encoding', matchedEncoding)
}
}, content, file.doNotCache)
} else {
next()
}
request.resume()
})
}
}
createSourceFilesMiddleware.$inject = [
'filesPromise', 'serveFile', 'config.basePath', 'config.urlRoot'
]
exports.create = createSourceFilesMiddleware

18
my-app/node_modules/karma/lib/middleware/stopper.js generated vendored Executable file
View file

@ -0,0 +1,18 @@
/**
* Stopper middleware is responsible for communicating with `karma stop`.
*/
const log = require('../logger').create('middleware:stopper')
function createStopperMiddleware (urlRoot) {
return function (request, response, next) {
if (request.url !== urlRoot + 'stop') return next()
response.writeHead(200)
log.info('Stopping server')
response.end('OK')
process.kill(process.pid, 'SIGINT')
}
}
createStopperMiddleware.$inject = ['config.urlRoot']
exports.create = createStopperMiddleware

11
my-app/node_modules/karma/lib/middleware/strip_host.js generated vendored Executable file
View file

@ -0,0 +1,11 @@
/**
* Strip hostname from request path
* This to handle requests that uses (normally over proxies) an absoluteURI as request path
*/
function stripHostFromUrl (url) {
return url.replace(/^https?:\/\/[a-z.:\d-]+\//, '/')
}
// PUBLIC API
exports.stripHost = stripHostFromUrl

98
my-app/node_modules/karma/lib/plugin.js generated vendored Executable file
View file

@ -0,0 +1,98 @@
'use strict'
const fs = require('graceful-fs')
const path = require('path')
const helper = require('./helper')
const log = require('./logger').create('plugin')
const IGNORED_PACKAGES = ['karma-cli', 'karma-runner.github.com']
function resolve (plugins, emitter) {
const modules = []
function requirePlugin (name) {
log.debug(`Loading plugin ${name}.`)
try {
modules.push(require(name))
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND' && e.message.includes(name)) {
log.error(`Cannot find plugin "${name}".\n Did you forget to install it?\n npm install ${name} --save-dev`)
} else {
log.error(`Error during loading "${name}" plugin:\n ${e.message}`)
}
emitter.emit('load_error', 'plug_in', name)
}
}
plugins.forEach(function (plugin) {
if (helper.isString(plugin)) {
if (!plugin.includes('*')) {
requirePlugin(plugin)
return
}
const pluginDirectory = path.normalize(path.join(__dirname, '/../..'))
const regexp = new RegExp(`^${plugin.replace(/\*/g, '.*').replace(/\//g, '[/\\\\]')}`)
log.debug(`Loading ${plugin} from ${pluginDirectory}`)
fs.readdirSync(pluginDirectory)
.map((e) => {
const modulePath = path.join(pluginDirectory, e)
if (e[0] === '@') {
return fs.readdirSync(modulePath).map((e) => path.join(modulePath, e))
}
return modulePath
})
.reduce((a, x) => a.concat(x), [])
.map((modulePath) => path.relative(pluginDirectory, modulePath))
.filter((moduleName) => !IGNORED_PACKAGES.includes(moduleName) && regexp.test(moduleName))
.forEach((pluginName) => requirePlugin(path.join(pluginDirectory, pluginName)))
} else if (helper.isObject(plugin)) {
log.debug(`Loading inline plugin defining ${Object.keys(plugin).join(', ')}.`)
modules.push(plugin)
} else {
log.error(`Invalid plugin ${plugin}`)
emitter.emit('load_error', 'plug_in', plugin)
}
})
return modules
}
/**
Create a function to handle errors in plugin loading.
@param {Object} injector, the dict of dependency injection objects.
@return function closed over injector, which reports errors.
*/
function createInstantiatePlugin (injector) {
const emitter = injector.get('emitter')
// Cache to avoid report errors multiple times per plugin.
const pluginInstances = new Map()
return function instantiatePlugin (kind, name) {
if (pluginInstances.has(name)) {
return pluginInstances.get(name)
}
let p
try {
p = injector.get(`${kind}:${name}`)
if (!p) {
log.error(`Failed to instantiate ${kind} ${name}`)
emitter.emit('load_error', kind, name)
}
} catch (e) {
if (e.message.includes(`No provider for "${kind}:${name}"`)) {
log.error(`Cannot load "${name}", it is not registered!\n Perhaps you are missing some plugin?`)
} else {
log.error(`Cannot load "${name}"!\n ` + e.stack)
}
emitter.emit('load_error', kind, name)
}
pluginInstances.set(name, p, `${kind}:${name}`)
return p
}
}
createInstantiatePlugin.$inject = ['injector']
module.exports = { resolve, createInstantiatePlugin }

111
my-app/node_modules/karma/lib/preprocessor.js generated vendored Executable file
View file

@ -0,0 +1,111 @@
'use strict'
const util = require('util')
const fs = require('graceful-fs')
// bind need only for mock unit tests
const readFile = util.promisify(fs.readFile.bind(fs))
const tryToRead = function (path, log) {
const maxRetries = 3
let promise = readFile(path)
for (let retryCount = 1; retryCount <= maxRetries; retryCount++) {
promise = promise.catch((err) => {
log.warn(err)
log.warn('retrying ' + retryCount)
return readFile(path)
})
}
return promise.catch((err) => {
log.warn(err)
return Promise.reject(err)
})
}
const mm = require('minimatch')
const { isBinaryFile } = require('isbinaryfile')
const _ = require('lodash')
const CryptoUtils = require('./utils/crypto-utils')
const log = require('./logger').create('preprocess')
function executeProcessor (process, file, content) {
let done = null
const donePromise = new Promise((resolve, reject) => {
done = function (error, content) {
// normalize B-C
if (arguments.length === 1 && typeof error === 'string') {
content = error
error = null
}
if (error) {
reject(error)
} else {
resolve(content)
}
}
})
return (process(content, file, done) || Promise.resolve()).then((content) => {
if (content) {
// async process correctly returned content
return content
}
// process called done() (Either old sync api or an async function that did not return content)
return donePromise
})
}
async function runProcessors (preprocessors, file, content) {
try {
for (const process of preprocessors) {
content = await executeProcessor(process, file, content)
}
} catch (error) {
file.contentPath = null
file.content = null
throw error
}
file.contentPath = null
file.content = content
file.sha = CryptoUtils.sha1(content)
}
function createPriorityPreprocessor (config = {}, preprocessorPriority, basePath, instantiatePlugin) {
_.union.apply(_, Object.values(config)).forEach((name) => instantiatePlugin('preprocessor', name))
return async function preprocess (file) {
const buffer = await tryToRead(file.originalPath, log)
let isBinary = file.isBinary
if (isBinary == null) {
// Pattern did not specify, probe for it.
isBinary = await isBinaryFile(buffer, buffer.length)
}
const preprocessorNames = Object.keys(config).reduce((ppNames, pattern) => {
if (mm(file.originalPath, pattern, { dot: true })) {
ppNames = _.union(ppNames, config[pattern])
}
return ppNames
}, [])
// Apply preprocessor priority.
const preprocessors = preprocessorNames
.map((name) => [name, preprocessorPriority[name] || 0])
.sort((a, b) => b[1] - a[1])
.map((duo) => duo[0])
.reduce((preProcs, name) => {
const p = instantiatePlugin('preprocessor', name)
if (!isBinary || (p && p.handleBinaryFiles)) {
preProcs.push(p)
} else {
log.warn(`Ignored preprocessing ${file.originalPath} because ${name} has handleBinaryFiles=false.`)
}
return preProcs
}, [])
await runProcessors(preprocessors, file, isBinary ? buffer : buffer.toString())
}
}
createPriorityPreprocessor.$inject = ['config.preprocessors', 'config.preprocessor_priority', 'config.basePath', 'instantiatePlugin']
exports.createPriorityPreprocessor = createPriorityPreprocessor

152
my-app/node_modules/karma/lib/reporter.js generated vendored Executable file
View file

@ -0,0 +1,152 @@
'use strict'
// eslint-disable-next-line node/no-deprecated-api
const resolve = require('url').resolve
const SourceMapConsumer = require('source-map').SourceMapConsumer
const _ = require('lodash')
const PathUtils = require('./utils/path-utils')
const log = require('./logger').create('reporter')
const MultiReporter = require('./reporters/multi')
const baseReporterDecoratorFactory = require('./reporters/base').decoratorFactory
function createErrorFormatter (config, emitter, SourceMapConsumer) {
const basePath = config.basePath
const urlRoot = config.urlRoot === '/' ? '' : (config.urlRoot || '')
let lastServedFiles = []
emitter.on('file_list_modified', (files) => {
lastServedFiles = files.served
})
const URL_REGEXP = new RegExp('(?:https?:\\/\\/' +
config.hostname + '(?:\\:' + config.port + ')?' + ')?\\/?' +
urlRoot + '\\/?' +
'(base/|absolute)' + // prefix, including slash for base/ to create relative paths.
'((?:[A-z]\\:)?[^\\?\\s\\:]*)' + // path
'(\\?\\w*)?' + // sha
'(\\:(\\d+))?' + // line
'(\\:(\\d+))?' + // column
'', 'g')
const cache = new WeakMap()
function getSourceMapConsumer (sourceMap) {
if (!cache.has(sourceMap)) {
cache.set(sourceMap, new SourceMapConsumer(sourceMap))
}
return cache.get(sourceMap)
}
return function (input, indentation) {
indentation = _.isString(indentation) ? indentation : ''
if (_.isError(input)) {
input = input.message
} else if (_.isEmpty(input)) {
input = ''
} else if (!_.isString(input)) {
input = JSON.stringify(input, null, indentation)
}
let msg = input.replace(URL_REGEXP, function (stackTracePath, prefix, path, __, ___, line, ____, column) {
const normalizedPath = prefix === 'base/' ? `${basePath}/${path}` : path
const file = lastServedFiles.find((file) => file.path === normalizedPath)
if (file && file.sourceMap && line) {
line = +line
column = +column
// When no column is given and we default to 0, it doesn't make sense to only search for smaller
// or equal columns in the sourcemap, let's search for equal or greater columns.
const bias = column ? SourceMapConsumer.GREATEST_LOWER_BOUND : SourceMapConsumer.LEAST_UPPER_BOUND
try {
const zeroBasedColumn = Math.max(0, (column || 1) - 1)
const original = getSourceMapConsumer(file.sourceMap).originalPositionFor({ line, column: zeroBasedColumn, bias })
// If there is no original position/source for the current stack trace path, then
// we return early with the formatted generated position. This handles the case of
// generated code which does not map to anything, see Case 1 of the source-map spec.
// https://sourcemaps.info/spec.html.
if (original.source === null) {
return PathUtils.formatPathMapping(path, line, column)
}
// Source maps often only have a local file name, resolve to turn into a full path if
// the path is not absolute yet.
const oneBasedOriginalColumn = original.column == null ? original.column : original.column + 1
return `${PathUtils.formatPathMapping(resolve(path, original.source), original.line, oneBasedOriginalColumn)} <- ${PathUtils.formatPathMapping(path, line, column)}`
} catch (e) {
log.warn(`An unexpected error occurred while resolving the original position for: ${stackTracePath}`)
log.warn(e)
}
}
return PathUtils.formatPathMapping(path, line, column) || prefix
})
if (indentation) {
msg = indentation + msg.replace(/\n/g, '\n' + indentation)
}
return config.formatError ? config.formatError(msg) : msg + '\n'
}
}
function createReporters (names, config, emitter, injector) {
const errorFormatter = createErrorFormatter(config, emitter, SourceMapConsumer)
const reporters = []
names.forEach((name) => {
if (['dots', 'progress'].includes(name)) {
[
require(`./reporters/${name}`),
require(`./reporters/${name}_color`)
].forEach((Reporter) => {
reporters.push(new Reporter(errorFormatter, config.reportSlowerThan, config.colors, config.browserConsoleLogOptions))
})
return
}
const locals = {
baseReporterDecorator: ['factory', baseReporterDecoratorFactory],
formatError: ['value', errorFormatter]
}
try {
log.debug(`Trying to load reporter: ${name}`)
reporters.push(injector.createChild([locals], ['reporter:' + name]).get('reporter:' + name))
} catch (e) {
if (e.message.includes(`No provider for "reporter:${name}"`)) {
log.error(`Can not load reporter "${name}", it is not registered!\n Perhaps you are missing some plugin?`)
} else {
log.error(`Can not load "${name}"!\n ${e.stack}`)
}
emitter.emit('load_error', 'reporter', name)
return
}
const colorName = name + '_color'
if (!names.includes(colorName)) {
try {
log.debug(`Trying to load color-version of reporter: ${name} (${colorName})`)
reporters.push(injector.createChild([locals], ['reporter:' + colorName]).get('reporter:' + name))
} catch (e) {
log.debug('Couldn\'t load color-version.')
}
}
})
reporters.forEach((reporter) => emitter.bind(reporter))
return new MultiReporter(reporters)
}
createReporters.$inject = [
'config.reporters',
'config',
'emitter',
'injector'
]
exports.createReporters = createReporters

162
my-app/node_modules/karma/lib/reporters/base.js generated vendored Executable file
View file

@ -0,0 +1,162 @@
'use strict'
const util = require('util')
const constants = require('../constants')
const helper = require('../helper')
const BaseReporter = function (formatError, reportSlow, useColors, browserConsoleLogOptions, adapter) {
this.adapters = [adapter || process.stdout.write.bind(process.stdout)]
this.USE_COLORS = false
this.EXCLUSIVELY_USE_COLORS = undefined
this.LOG_SINGLE_BROWSER = '%s: %s\n'
this.LOG_MULTI_BROWSER = '%s %s: %s\n'
this.SPEC_FAILURE = '%s %s FAILED' + '\n'
this.SPEC_SLOW = '%s SLOW %s: %s\n'
this.ERROR = '%s ERROR\n'
this.FINISHED_ERROR = ' ERROR'
this.FINISHED_SUCCESS = ' SUCCESS'
this.FINISHED_DISCONNECTED = ' DISCONNECTED'
this.X_FAILED = ' (%d FAILED)'
this.TOTAL_SUCCESS = 'TOTAL: %d SUCCESS\n'
this.TOTAL_FAILED = 'TOTAL: %d FAILED, %d SUCCESS\n'
this.onRunStart = () => {
this._browsers = []
}
this.onBrowserStart = (browser) => {
this._browsers.push(browser)
}
this.renderBrowser = (browser) => {
const results = browser.lastResult
const totalExecuted = results.success + results.failed
let msg = `${browser}: Executed ${totalExecuted} of ${results.total}`
if (results.failed) {
msg += util.format(this.X_FAILED, results.failed)
}
if (results.skipped) {
msg += ` (skipped ${results.skipped})`
}
if (browser.isConnected) {
if (results.disconnected) {
msg += this.FINISHED_DISCONNECTED
} else if (results.error) {
msg += this.FINISHED_ERROR
} else if (!results.failed) {
msg += this.FINISHED_SUCCESS
}
msg += ` (${helper.formatTimeInterval(results.totalTime)} / ${helper.formatTimeInterval(results.netTime)})`
}
return msg
}
this.write = function () {
const msg = util.format.apply(null, Array.prototype.slice.call(arguments))
this.adapters.forEach((adapter) => {
if (!helper.isDefined(adapter.colors)) {
adapter.colors = useColors
}
if (!helper.isDefined(this.EXCLUSIVELY_USE_COLORS) || adapter.colors === this.EXCLUSIVELY_USE_COLORS) {
return adapter(msg)
}
})
}
this.writeCommonMsg = function () {
this.write.apply(this, arguments)
}
this.onBrowserError = (browser, error) => {
this.writeCommonMsg(util.format(this.ERROR, browser) + formatError(error, ' '))
}
this.onBrowserLog = (browser, log, type) => {
if (!browserConsoleLogOptions || !browserConsoleLogOptions.terminal) return
type = type.toUpperCase()
if (browserConsoleLogOptions.level) {
const logPriority = constants.LOG_PRIORITIES.indexOf(browserConsoleLogOptions.level.toUpperCase())
if (constants.LOG_PRIORITIES.indexOf(type) > logPriority) return
}
if (!helper.isString(log)) {
// TODO(vojta): change util to new syntax (config object)
log = util.inspect(log, false, undefined, this.USE_COLORS)
}
if (this._browsers && this._browsers.length === 1) {
this.writeCommonMsg(util.format(this.LOG_SINGLE_BROWSER, type, log))
} else {
this.writeCommonMsg(util.format(this.LOG_MULTI_BROWSER, browser, type, log))
}
}
this.onSpecComplete = (browser, result) => {
if (result.skipped) {
this.specSkipped(browser, result)
} else if (result.success) {
this.specSuccess(browser, result)
} else {
this.specFailure(browser, result)
}
if (reportSlow && result.time > reportSlow) {
const specName = result.suite.join(' ') + ' ' + result.description
const time = helper.formatTimeInterval(result.time)
this.writeCommonMsg(util.format(this.SPEC_SLOW, browser, time, specName))
}
}
this.specSuccess = () => {
}
this.specSkipped = () => {
}
this.specFailure = (browser, result) => {
const specName = result.suite.join(' ') + ' ' + result.description
let msg = util.format(this.SPEC_FAILURE, browser, specName)
result.log.forEach((log) => {
msg += formatError(log, '\t')
})
this.writeCommonMsg(msg)
}
this.onRunComplete = (browsers, results) => {
if (browsers.length >= 1 && !results.error && !results.disconnected) {
if (!results.failed) {
this.write(this.TOTAL_SUCCESS, results.success)
} else {
this.write(this.TOTAL_FAILED, results.failed, results.success)
}
}
}
}
BaseReporter.decoratorFactory = function (formatError, reportSlow, useColors, browserConsoleLogOptions) {
return function (self) {
BaseReporter.call(self, formatError, reportSlow, useColors, browserConsoleLogOptions)
}
}
BaseReporter.decoratorFactory.$inject = [
'formatError',
'config.reportSlowerThan',
'config.colors',
'config.browserConsoleLogOptions'
]
// PUBLISH
module.exports = BaseReporter

24
my-app/node_modules/karma/lib/reporters/base_color.js generated vendored Executable file
View file

@ -0,0 +1,24 @@
const { red, yellow, green, cyan } = require('@colors/colors/safe')
function BaseColorReporter () {
this.USE_COLORS = true
this.LOG_SINGLE_BROWSER = '%s: ' + cyan('%s') + '\n'
this.LOG_MULTI_BROWSER = '%s %s: ' + cyan('%s') + '\n'
this.SPEC_FAILURE = red('%s %s FAILED') + '\n'
this.SPEC_SLOW = yellow('%s SLOW %s: %s') + '\n'
this.ERROR = red('%s ERROR') + '\n'
this.FINISHED_ERROR = red(' ERROR')
this.FINISHED_SUCCESS = green(' SUCCESS')
this.FINISHED_DISCONNECTED = red(' DISCONNECTED')
this.X_FAILED = red(' (%d FAILED)')
this.TOTAL_SUCCESS = green('TOTAL: %d SUCCESS') + '\n'
this.TOTAL_FAILED = red('TOTAL: %d FAILED, %d SUCCESS') + '\n'
}
// PUBLISH
module.exports = BaseColorReporter

47
my-app/node_modules/karma/lib/reporters/dots.js generated vendored Executable file
View file

@ -0,0 +1,47 @@
const BaseReporter = require('./base')
function DotsReporter (formatError, reportSlow, useColors, browserConsoleLogOptions) {
BaseReporter.call(this, formatError, reportSlow, useColors, browserConsoleLogOptions)
const DOTS_WRAP = 80
this.EXCLUSIVELY_USE_COLORS = false
this.onRunStart = function () {
this._browsers = []
this._dotsCount = 0
}
this.onBrowserStart = function (browser) {
this._browsers.push(browser)
}
this.writeCommonMsg = function (msg) {
if (this._dotsCount) {
this._dotsCount = 0
msg = '\n' + msg
}
this.write(msg)
}
this.specSuccess = function () {
this._dotsCount = (this._dotsCount + 1) % DOTS_WRAP
this.write(this._dotsCount ? '.' : '.\n')
}
this.onBrowserComplete = function (browser) {
this.writeCommonMsg(this.renderBrowser(browser) + '\n')
}
this.onRunComplete = function (browsers, results) {
if (browsers.length > 1 && !results.disconnected && !results.error) {
if (!results.failed) {
this.write(this.TOTAL_SUCCESS, results.success)
} else {
this.write(this.TOTAL_FAILED, results.failed, results.success)
}
}
}
}
// PUBLISH
module.exports = DotsReporter

11
my-app/node_modules/karma/lib/reporters/dots_color.js generated vendored Executable file
View file

@ -0,0 +1,11 @@
const DotsReporter = require('./dots')
const BaseColorReporter = require('./base_color')
function DotsColorReporter (formatError, reportSlow, useColors, browserConsoleLogOptions) {
DotsReporter.call(this, formatError, reportSlow, useColors, browserConsoleLogOptions)
BaseColorReporter.call(this)
this.EXCLUSIVELY_USE_COLORS = true
}
// PUBLISH
module.exports = DotsColorReporter

19
my-app/node_modules/karma/lib/reporters/multi.js generated vendored Executable file
View file

@ -0,0 +1,19 @@
'use strict'
const helper = require('../helper')
class MultiReporter {
constructor (reporters) {
this._reporters = reporters
}
addAdapter (adapter) {
this._reporters.forEach((reporter) => reporter.adapters.push(adapter))
}
removeAdapter (adapter) {
this._reporters.forEach((reporter) => helper.arrayRemove(reporter.adapters, adapter))
}
}
module.exports = MultiReporter

63
my-app/node_modules/karma/lib/reporters/progress.js generated vendored Executable file
View file

@ -0,0 +1,63 @@
const BaseReporter = require('./base')
function ProgressReporter (formatError, reportSlow, useColors, browserConsoleLogOptions) {
BaseReporter.call(this, formatError, reportSlow, useColors, browserConsoleLogOptions)
this.EXCLUSIVELY_USE_COLORS = false
this._browsers = []
this.writeCommonMsg = function (msg) {
this.write(this._remove() + msg + this._render())
}
this.specSuccess = function () {
this.write(this._refresh())
}
this.onBrowserComplete = function () {
this.write(this._refresh())
}
this.onRunStart = function () {
this._browsers = []
this._isRendered = false
}
this.onBrowserStart = function (browser) {
this._browsers.push(browser)
if (this._isRendered) {
this.write('\n')
}
this.write(this._refresh())
}
this._remove = function () {
if (!this._isRendered) {
return ''
}
let cmd = ''
this._browsers.forEach(function () {
cmd += '\x1B[1A' + '\x1B[2K'
})
this._isRendered = false
return cmd
}
this._render = function () {
this._isRendered = true
return this._browsers.map(this.renderBrowser).join('\n') + '\n'
}
this._refresh = function () {
return this._remove() + this._render()
}
}
// PUBLISH
module.exports = ProgressReporter

11
my-app/node_modules/karma/lib/reporters/progress_color.js generated vendored Executable file
View file

@ -0,0 +1,11 @@
const ProgressReporter = require('./progress')
const BaseColorReporter = require('./base_color')
function ProgressColorReporter (formatError, reportSlow, useColors, browserConsoleLogOptions) {
ProgressReporter.call(this, formatError, reportSlow, useColors, browserConsoleLogOptions)
BaseColorReporter.call(this)
this.EXCLUSIVELY_USE_COLORS = true
}
// PUBLISH
module.exports = ProgressColorReporter

113
my-app/node_modules/karma/lib/runner.js generated vendored Executable file
View file

@ -0,0 +1,113 @@
'use strict'
const http = require('http')
const constant = require('./constants')
const EventEmitter = require('events').EventEmitter
const helper = require('./helper')
const cfg = require('./config')
const logger = require('./logger')
const { lookup } = require('./utils/dns-utils')
const log = logger.create('runner')
function parseExitCode (buffer, defaultExitCode, failOnEmptyTestSuite) {
const tailPos = buffer.length - Buffer.byteLength(constant.EXIT_CODE) - 2
if (tailPos < 0) {
return { exitCode: defaultExitCode, buffer }
}
const tail = buffer.slice(tailPos)
const tailStr = tail.toString()
if (tailStr.slice(0, -2) === constant.EXIT_CODE) {
const emptyInt = parseInt(tailStr.slice(-2, -1), 10)
let exitCode = parseInt(tailStr.slice(-1), 10)
if (failOnEmptyTestSuite === false && emptyInt === 0) {
log.warn('Test suite was empty.')
exitCode = 0
}
return { exitCode, buffer: buffer.slice(0, tailPos) }
}
return { exitCode: defaultExitCode, buffer }
}
// TODO(vojta): read config file (port, host, urlRoot)
function run (cliOptionsOrConfig, done) {
cliOptionsOrConfig = cliOptionsOrConfig || {}
done = helper.isFunction(done) ? done : process.exit
let config
if (cliOptionsOrConfig instanceof cfg.Config) {
config = cliOptionsOrConfig
} else {
logger.setupFromConfig({
colors: cliOptionsOrConfig.colors,
logLevel: cliOptionsOrConfig.logLevel
})
const deprecatedCliOptionsMessage =
'Passing raw CLI options to `runner(config, done)` is deprecated. Use ' +
'`parseConfig(configFilePath, cliOptions, {promiseConfig: true, throwErrors: true})` ' +
'to prepare a processed `Config` instance and pass that as the ' +
'`config` argument instead.'
log.warn(deprecatedCliOptionsMessage)
try {
config = cfg.parseConfig(
cliOptionsOrConfig.configFile,
cliOptionsOrConfig,
{
promiseConfig: false,
throwErrors: true
}
)
} catch (parseConfigError) {
// TODO: change how `done` falls back to exit in next major version
// SEE: https://github.com/karma-runner/karma/pull/3635#discussion_r565399378
done(1)
}
}
let exitCode = 1
const emitter = new EventEmitter()
const options = {
hostname: config.hostname,
path: config.urlRoot + 'run',
port: config.port,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
lookup
}
const request = http.request(options, function (response) {
response.on('data', function (buffer) {
const parsedResult = parseExitCode(buffer, exitCode, config.failOnEmptyTestSuite)
exitCode = parsedResult.exitCode
emitter.emit('progress', parsedResult.buffer)
})
response.on('end', () => done(exitCode))
})
request.on('error', function (e) {
if (e.code === 'ECONNREFUSED') {
log.error('There is no server listening on port %d', options.port)
done(1, e.code)
} else {
throw e
}
})
request.end(JSON.stringify({
args: config.clientArgs,
removedFiles: config.removedFiles,
changedFiles: config.changedFiles,
addedFiles: config.addedFiles,
refresh: config.refresh,
colors: config.colors
}))
return emitter
}
exports.run = run

487
my-app/node_modules/karma/lib/server.js generated vendored Executable file
View file

@ -0,0 +1,487 @@
'use strict'
const SocketIO = require('socket.io')
const di = require('di')
const util = require('util')
const spawn = require('child_process').spawn
const tmp = require('tmp')
const fs = require('fs')
const path = require('path')
const NetUtils = require('./utils/net-utils')
const root = global || window || this
const cfg = require('./config')
const logger = require('./logger')
const constant = require('./constants')
const watcher = require('./watcher')
const plugin = require('./plugin')
const createServeFile = require('./web-server').createServeFile
const createServeStaticFile = require('./web-server').createServeStaticFile
const createFilesPromise = require('./web-server').createFilesPromise
const createWebServer = require('./web-server').createWebServer
const preprocessor = require('./preprocessor')
const Launcher = require('./launcher').Launcher
const FileList = require('./file-list')
const reporter = require('./reporter')
const helper = require('./helper')
const events = require('./events')
const KarmaEventEmitter = events.EventEmitter
const EventEmitter = require('events').EventEmitter
const Executor = require('./executor')
const Browser = require('./browser')
const BrowserCollection = require('./browser_collection')
const EmitterWrapper = require('./emitter_wrapper')
const processWrapper = new EmitterWrapper(process)
function createSocketIoServer (webServer, executor, config) {
const server = new SocketIO.Server(webServer, {
// avoid destroying http upgrades from socket.io to get proxied websockets working
destroyUpgrade: false,
path: config.urlRoot + 'socket.io/',
transports: config.transports,
forceJSONP: config.forceJSONP,
// Default is 5000 in socket.io v2.x and v3.x.
pingTimeout: config.pingTimeout || 5000,
// Default in v2 is 1e8 and coverage results can fail at 1e6
maxHttpBufferSize: 1e8
})
// hack to overcome circular dependency
executor.socketIoSockets = server.sockets
return server
}
class Server extends KarmaEventEmitter {
constructor (cliOptionsOrConfig, done) {
super()
cliOptionsOrConfig = cliOptionsOrConfig || {}
this.log = logger.create('karma-server')
done = helper.isFunction(done) ? done : process.exit
this.loadErrors = []
let config
if (cliOptionsOrConfig instanceof cfg.Config) {
config = cliOptionsOrConfig
} else {
logger.setupFromConfig({
colors: cliOptionsOrConfig.colors,
logLevel: cliOptionsOrConfig.logLevel
})
const deprecatedCliOptionsMessage =
'Passing raw CLI options to `new Server(config, done)` is ' +
'deprecated. Use ' +
'`parseConfig(configFilePath, cliOptions, {promiseConfig: true, throwErrors: true})` ' +
'to prepare a processed `Config` instance and pass that as the ' +
'`config` argument instead.'
this.log.warn(deprecatedCliOptionsMessage)
try {
config = cfg.parseConfig(
cliOptionsOrConfig.configFile,
cliOptionsOrConfig,
{
promiseConfig: false,
throwErrors: true
}
)
} catch (parseConfigError) {
// TODO: change how `done` falls back to exit in next major version
// SEE: https://github.com/karma-runner/karma/pull/3635#discussion_r565399378
done(1)
return
}
}
this.log.debug('Final config', util.inspect(config, false, /** depth **/ null))
if (!config.autoWatch && !config.singleRun) {
this.log.warn('`autowatch` and `singleRun` are both `false`. In order to execute tests use `karma run`.')
}
let modules = [{
helper: ['value', helper],
logger: ['value', logger],
done: ['value', done || process.exit],
emitter: ['value', this],
server: ['value', this],
watcher: ['value', watcher],
launcher: ['factory', Launcher.factory],
config: ['value', config],
instantiatePlugin: ['factory', plugin.createInstantiatePlugin],
preprocess: ['factory', preprocessor.createPriorityPreprocessor],
fileList: ['factory', FileList.factory],
webServer: ['factory', createWebServer],
serveFile: ['factory', createServeFile],
serveStaticFile: ['factory', createServeStaticFile],
filesPromise: ['factory', createFilesPromise],
socketServer: ['factory', createSocketIoServer],
executor: ['factory', Executor.factory],
// TODO: Deprecated. Remove in the next major
customFileHandlers: ['value', []],
reporter: ['factory', reporter.createReporters],
capturedBrowsers: ['factory', BrowserCollection.factory],
args: ['value', {}],
timer: ['value', {
setTimeout () {
return setTimeout.apply(root, arguments)
},
clearTimeout
}]
}]
this.on('load_error', (type, name) => {
this.log.debug(`Registered a load error of type ${type} with name ${name}`)
this.loadErrors.push([type, name])
})
modules = modules.concat(plugin.resolve(config.plugins, this))
this._injector = new di.Injector(modules)
}
async start () {
const config = this.get('config')
try {
this._boundServer = await NetUtils.bindAvailablePort(config.port, config.listenAddress)
this._boundServer.on('connection', (socket) => {
// Attach an error handler to avoid UncaughtException errors.
socket.on('error', (err) => {
// Errors on this socket are retried, ignore them
this.log.debug('Ignoring error on webserver connection: ' + err)
})
})
config.port = this._boundServer.address().port
await this._injector.invoke(this._start, this)
} catch (err) {
this.log.error(`Server start failed on port ${config.port}: ${err}`)
this._close(1)
}
}
get (token) {
return this._injector.get(token)
}
refreshFiles () {
return this._fileList ? this._fileList.refresh() : Promise.resolve()
}
refreshFile (path) {
return this._fileList ? this._fileList.changeFile(path) : Promise.resolve()
}
emitExitAsync (code) {
const name = 'exit'
let pending = this.listeners(name).length
const deferred = helper.defer()
function resolve () {
deferred.resolve(code)
}
try {
this.emit(name, (newCode) => {
if (newCode && typeof newCode === 'number') {
// Only update code if it is given and not zero
code = newCode
}
if (!--pending) {
resolve()
}
})
if (!pending) {
resolve()
}
} catch (err) {
deferred.reject(err)
}
return deferred.promise
}
async _start (config, launcher, preprocess, fileList, capturedBrowsers, executor, done) {
if (config.detached) {
this._detach(config, done)
return
}
this._fileList = fileList
await Promise.all(
config.frameworks.map((framework) => this._injector.get('framework:' + framework))
)
const webServer = this._injector.get('webServer')
const socketServer = this._injector.get('socketServer')
const singleRunDoneBrowsers = Object.create(null)
const singleRunBrowsers = new BrowserCollection(new EventEmitter())
let singleRunBrowserNotCaptured = false
webServer.on('error', (err) => {
this.log.error(`Webserver fail ${err}`)
this._close(1)
})
const afterPreprocess = () => {
if (config.autoWatch) {
const watcher = this.get('watcher')
this._injector.invoke(watcher)
}
webServer.listen(this._boundServer, () => {
this.log.info(`Karma v${constant.VERSION} server started at ${config.protocol}//${config.hostname}:${config.port}${config.urlRoot}`)
this.emit('listening', config.port)
if (config.browsers && config.browsers.length) {
this._injector.invoke(launcher.launch, launcher).forEach((browserLauncher) => {
singleRunDoneBrowsers[browserLauncher.id] = false
})
}
if (this.loadErrors.length > 0) {
this.log.error(new Error(`Found ${this.loadErrors.length} load error${this.loadErrors.length === 1 ? '' : 's'}`))
this._close(1)
}
})
}
fileList.refresh().then(afterPreprocess, (err) => {
this.log.error('Error during file loading or preprocessing\n' + err.stack || err)
afterPreprocess()
})
this.on('browsers_change', () => socketServer.sockets.emit('info', capturedBrowsers.serialize()))
this.on('browser_register', (browser) => {
launcher.markCaptured(browser.id)
if (launcher.areAllCaptured()) {
this.emit('browsers_ready')
if (config.autoWatch) {
executor.schedule()
}
}
})
if (config.browserConsoleLogOptions && config.browserConsoleLogOptions.path) {
const configLevel = config.browserConsoleLogOptions.level || 'debug'
const configFormat = config.browserConsoleLogOptions.format || '%b %T: %m'
const configPath = config.browserConsoleLogOptions.path
const configPathDir = path.dirname(configPath)
if (!fs.existsSync(configPathDir)) fs.mkdirSync(configPathDir, { recursive: true })
this.log.info(`Writing browser console to file: ${configPath}`)
const browserLogFile = fs.openSync(configPath, 'w+')
const levels = ['log', 'error', 'warn', 'info', 'debug']
this.on('browser_log', function (browser, message, level) {
if (levels.indexOf(level.toLowerCase()) > levels.indexOf(configLevel)) {
return
}
if (!helper.isString(message)) {
message = util.inspect(message, { showHidden: false, colors: false })
}
const logMap = { '%m': message, '%t': level.toLowerCase(), '%T': level.toUpperCase(), '%b': browser }
const logString = configFormat.replace(/%[mtTb]/g, (m) => logMap[m])
this.log.debug(`Writing browser console line: ${logString}`)
fs.writeSync(browserLogFile, logString + '\n')
})
}
socketServer.sockets.on('connection', (socket) => {
this.log.debug(`A browser has connected on socket ${socket.id}`)
const replySocketEvents = events.bufferEvents(socket, ['start', 'info', 'karma_error', 'result', 'complete'])
socket.on('error', (err) => {
this.log.debug('karma server socket error: ' + err)
})
socket.on('register', (info) => {
const knownBrowser = info.id ? (capturedBrowsers.getById(info.id) || singleRunBrowsers.getById(info.id)) : null
if (knownBrowser) {
knownBrowser.reconnect(socket, info.isSocketReconnect)
} else {
const newBrowser = this._injector.createChild([{
id: ['value', info.id || null],
fullName: ['value', (helper.isDefined(info.displayName) ? info.displayName : info.name)],
socket: ['value', socket]
}]).invoke(Browser.factory)
newBrowser.init()
if (config.singleRun) {
newBrowser.execute()
singleRunBrowsers.add(newBrowser)
}
}
replySocketEvents()
})
})
const emitRunCompleteIfAllBrowsersDone = () => {
if (Object.keys(singleRunDoneBrowsers).every((key) => singleRunDoneBrowsers[key])) {
this.emit('run_complete', singleRunBrowsers, singleRunBrowsers.getResults(singleRunBrowserNotCaptured, config))
}
}
this.on('browser_complete', (completedBrowser) => {
if (completedBrowser.lastResult.disconnected && completedBrowser.disconnectsCount <= config.browserDisconnectTolerance) {
this.log.info(`Restarting ${completedBrowser.name} (${completedBrowser.disconnectsCount} of ${config.browserDisconnectTolerance} attempts)`)
if (!launcher.restart(completedBrowser.id)) {
this.emit('browser_restart_failure', completedBrowser)
}
} else {
this.emit('browser_complete_with_no_more_retries', completedBrowser)
}
})
this.on('stop', (done) => {
this.log.debug('Received stop event, exiting.')
this._close()
done()
})
if (config.singleRun) {
this.on('browser_restart_failure', (completedBrowser) => {
singleRunDoneBrowsers[completedBrowser.id] = true
emitRunCompleteIfAllBrowsersDone()
})
// This is the normal exit trigger.
this.on('browser_complete_with_no_more_retries', function (completedBrowser) {
singleRunDoneBrowsers[completedBrowser.id] = true
if (launcher.kill(completedBrowser.id)) {
completedBrowser.remove()
}
emitRunCompleteIfAllBrowsersDone()
})
this.on('browser_process_failure', (browserLauncher) => {
singleRunDoneBrowsers[browserLauncher.id] = true
singleRunBrowserNotCaptured = true
emitRunCompleteIfAllBrowsersDone()
})
this.on('run_complete', (browsers, results) => {
this.log.debug('Run complete, exiting.')
this._close(results.exitCode)
})
this.emit('run_start', singleRunBrowsers)
}
if (config.autoWatch) {
this.on('file_list_modified', () => {
this.log.debug('List of files has changed, trying to execute')
if (config.restartOnFileChange) {
socketServer.sockets.emit('stop')
}
executor.schedule()
})
}
processWrapper.on('SIGINT', () => this._close())
processWrapper.on('SIGTERM', () => this._close())
const reportError = (error) => {
this.log.error(error)
process.emit('infrastructure_error', error)
this._close(1)
}
processWrapper.on('unhandledRejection', (error) => {
this.log.error(`UnhandledRejection: ${error.stack || error.message || String(error)}`)
reportError(error)
})
processWrapper.on('uncaughtException', (error) => {
this.log.error(`UncaughtException: ${error.stack || error.message || String(error)}`)
reportError(error)
})
}
_detach (config, done) {
const tmpFile = tmp.fileSync({ keep: true })
this.log.info('Starting karma detached')
this.log.info('Run "karma stop" to stop the server.')
this.log.debug(`Writing config to tmp-file ${tmpFile.name}`)
config.detached = false
try {
fs.writeFileSync(tmpFile.name, JSON.stringify(config), 'utf8')
} catch (e) {
this.log.error("Couldn't write temporary configuration file")
done(1)
return
}
const child = spawn(process.argv[0], [path.resolve(__dirname, '../lib/detached.js'), tmpFile.name], {
detached: true,
stdio: 'ignore'
})
child.unref()
}
/**
* Cleanup all resources allocated by Karma and call the `done` callback
* with the result of the tests execution.
*
* @param [exitCode] - Optional exit code. If omitted will be computed by
* 'exit' event listeners.
*/
_close (exitCode) {
const webServer = this._injector.get('webServer')
const socketServer = this._injector.get('socketServer')
const done = this._injector.get('done')
const webServerCloseTimeout = 3000
const sockets = socketServer.sockets.sockets
Object.keys(sockets).forEach((id) => {
const socket = sockets[id]
socket.removeAllListeners('disconnect')
if (!socket.disconnected) {
process.nextTick(socket.disconnect.bind(socket))
}
})
this.emitExitAsync(exitCode).catch((err) => {
this.log.error('Error while calling exit event listeners\n' + err.stack || err)
return 1
}).then((code) => {
socketServer.sockets.removeAllListeners()
socketServer.close()
let removeAllListenersDone = false
const removeAllListeners = () => {
if (removeAllListenersDone) {
return
}
removeAllListenersDone = true
webServer.removeAllListeners()
processWrapper.removeAllListeners()
done(code || 0)
}
const closeTimeout = setTimeout(removeAllListeners, webServerCloseTimeout)
webServer.close(() => {
clearTimeout(closeTimeout)
removeAllListeners()
})
})
}
stop () {
return this.emitAsync('stop')
}
}
Server.prototype._start.$inject = ['config', 'launcher', 'preprocess', 'fileList', 'capturedBrowsers', 'executor', 'done']
module.exports = Server

69
my-app/node_modules/karma/lib/stopper.js generated vendored Executable file
View file

@ -0,0 +1,69 @@
const http = require('http')
const cfg = require('./config')
const logger = require('./logger')
const helper = require('./helper')
const { lookup } = require('./utils/dns-utils')
exports.stop = function (cliOptionsOrConfig, done) {
cliOptionsOrConfig = cliOptionsOrConfig || {}
const log = logger.create('stopper')
done = helper.isFunction(done) ? done : process.exit
let config
if (cliOptionsOrConfig instanceof cfg.Config) {
config = cliOptionsOrConfig
} else {
logger.setupFromConfig({
colors: cliOptionsOrConfig.colors,
logLevel: cliOptionsOrConfig.logLevel
})
const deprecatedCliOptionsMessage =
'Passing raw CLI options to `stopper(config, done)` is deprecated. Use ' +
'`parseConfig(configFilePath, cliOptions, {promiseConfig: true, throwErrors: true})` ' +
'to prepare a processed `Config` instance and pass that as the ' +
'`config` argument instead.'
log.warn(deprecatedCliOptionsMessage)
try {
config = cfg.parseConfig(
cliOptionsOrConfig.configFile,
cliOptionsOrConfig,
{
promiseConfig: false,
throwErrors: true
}
)
} catch (parseConfigError) {
// TODO: change how `done` falls back to exit in next major version
// SEE: https://github.com/karma-runner/karma/pull/3635#discussion_r565399378
done(1)
}
}
const request = http.request({
hostname: config.hostname,
path: config.urlRoot + 'stop',
port: config.port,
method: 'GET',
lookup
})
request.on('response', function (response) {
if (response.statusCode === 200) {
log.info('Server stopped.')
done(0)
} else {
log.error(`Server returned status code: ${response.statusCode}`)
done(1)
}
})
request.on('error', function (e) {
if (e.code === 'ECONNREFUSED') {
log.error(`There is no server listening on port ${config.port}`)
done(1, e.code)
} else {
throw e
}
})
request.end()
}

31
my-app/node_modules/karma/lib/temp_dir.js generated vendored Executable file
View file

@ -0,0 +1,31 @@
'use strict'
const path = require('path')
const fs = require('graceful-fs')
const rimraf = require('rimraf')
const log = require('./logger').create('temp-dir')
const TEMP_DIR = require('os').tmpdir()
module.exports = {
getPath (suffix) {
return path.normalize(TEMP_DIR + suffix)
},
create (path) {
log.debug(`Creating temp dir at ${path}`)
try {
fs.mkdirSync(path)
} catch (e) {
log.warn(`Failed to create a temp dir at ${path}`)
}
return path
},
remove (path, done) {
log.debug(`Cleaning temp dir ${path}`)
rimraf(path, done)
}
}

31
my-app/node_modules/karma/lib/url.js generated vendored Executable file
View file

@ -0,0 +1,31 @@
'use strict'
const path = require('path')
const { URL } = require('url')
/**
* Url object used for tracking files in `file-list.js`.
*/
class Url {
constructor (path, type, integrity) {
this.path = path
this.originalPath = path
this.type = type
this.integrity = integrity
this.isUrl = true
}
/**
* Detect type from the file extension in the path part of the URL.
* @returns {string} detected file type or empty string
*/
detectType () {
return path.extname(new URL(this.path).pathname).slice(1)
}
toString () {
return this.path
}
}
module.exports = Url

14
my-app/node_modules/karma/lib/utils/crypto-utils.js generated vendored Executable file
View file

@ -0,0 +1,14 @@
'use strict'
const crypto = require('crypto')
const CryptoUtils = {
sha1 (data) {
return crypto
.createHash('sha1')
.update(data)
.digest('hex')
}
}
module.exports = CryptoUtils

11
my-app/node_modules/karma/lib/utils/dns-utils.js generated vendored Executable file
View file

@ -0,0 +1,11 @@
const dns = require('dns')
// Node >=17 has different DNS resolution (see
// https://github.com/nodejs/node/issues/40702), it resolves domains
// according to the OS settings instead of IPv4-address first. The Karma server
// only listens on IPv4 address (127.0.0.1) by default, but the requests are
// sent to `localhost` in several places and `localhost` is resolved into IPv6
// address (`::`). So the run/stop/proxy request is unable to reach the Karma
// server and produces an error. To mitigate this issue karma force the
// IPv4-address first approach in Node >=17 as well.
module.exports.lookup = (hostname, options, callback) => dns.lookup(hostname, { ...options, verbatim: false }, callback)

25
my-app/node_modules/karma/lib/utils/file-utils.js generated vendored Executable file
View file

@ -0,0 +1,25 @@
'use strict'
const fs = require('graceful-fs')
const FileUtils = {
readFile (path) {
return fs.readFileSync(path).toString()
},
saveFile (path, content) {
fs.writeFileSync(path, content)
},
copyFile (src, dest) {
FileUtils.saveFile(dest, FileUtils.readFile(src))
},
removeFileIfExists (src) {
if (fs.existsSync(src)) {
fs.unlinkSync(src)
}
}
}
module.exports = FileUtils

27
my-app/node_modules/karma/lib/utils/net-utils.js generated vendored Executable file
View file

@ -0,0 +1,27 @@
'use strict'
const net = require('net')
const NetUtils = {
bindAvailablePort (port, listenAddress) {
return new Promise((resolve, reject) => {
const server = net.createServer()
server
.on('error', (err) => {
server.close()
if (err.code === 'EADDRINUSE' || err.code === 'EACCES') {
server.listen(++port, listenAddress)
} else {
reject(new Error(`Failed to bind ${port}: ` + (err.stack || err)))
}
})
.on('listening', () => {
resolve(server)
})
.listen(port, listenAddress)
})
}
}
module.exports = NetUtils

16
my-app/node_modules/karma/lib/utils/path-utils.js generated vendored Executable file
View file

@ -0,0 +1,16 @@
'use strict'
const path = require('path')
const PathUtils = {
formatPathMapping (path, line, column) {
return path + (line ? `:${line}` : '') + (column ? `:${column}` : '')
},
calculateAbsolutePath (karmaRelativePath) {
return path.join(__dirname, '..', '..', karmaRelativePath)
}
}
module.exports = PathUtils

14
my-app/node_modules/karma/lib/utils/pattern-utils.js generated vendored Executable file
View file

@ -0,0 +1,14 @@
'use strict'
const path = require('path')
const PatternUtils = {
getBaseDir (pattern) {
return pattern
.replace(/[/\\][^/\\]*\*.*$/, '') // remove parts with *
.replace(/[/\\][^/\\]*[!+]\(.*$/, '') // remove parts with !(...) and +(...)
.replace(/[/\\][^/\\]*\)\?.*$/, '') || path.sep // remove parts with (...)?
}
}
module.exports = PatternUtils

85
my-app/node_modules/karma/lib/watcher.js generated vendored Executable file
View file

@ -0,0 +1,85 @@
'use strict'
const mm = require('minimatch')
const braces = require('braces')
const PatternUtils = require('./utils/pattern-utils')
const helper = require('./helper')
const log = require('./logger').create('watcher')
const DIR_SEP = require('path').sep
function watchPatterns (patterns, watcher) {
let expandedPatterns = []
patterns.map((pattern) => {
// expand ['a/{b,c}'] to ['a/b', 'a/c']
expandedPatterns = expandedPatterns.concat(braces.expand(pattern, { keepEscaping: true }))
})
expandedPatterns
.map(PatternUtils.getBaseDir)
.filter((path, index, paths) => paths.indexOf(path) === index) // filter unique values
.forEach((path, index, paths) => {
if (!paths.some((p) => path.startsWith(p + DIR_SEP))) {
watcher.add(path)
log.debug(`Watching "${path}"`)
}
})
}
function checkAnyPathMatch (patterns, path) {
return patterns.some((pattern) => mm(path, pattern, { dot: true }))
}
function createIgnore (patterns, excludes) {
return function (path, stat) {
if (stat && !stat.isDirectory()) {
return !checkAnyPathMatch(patterns, path) || checkAnyPathMatch(excludes, path)
} else {
return false
}
}
}
function getWatchedPatterns (patterns) {
return patterns
.filter((pattern) => pattern.watched)
.map((pattern) => pattern.pattern)
}
function watch (patterns, excludes, fileList, usePolling, emitter) {
const watchedPatterns = getWatchedPatterns(patterns)
// Lazy-load 'chokidar' to make the dependency optional. This is desired when
// third-party watchers are in use.
const chokidar = require('chokidar')
const watcher = new chokidar.FSWatcher({
usePolling: usePolling,
ignorePermissionErrors: true,
ignoreInitial: true,
ignored: createIgnore(watchedPatterns, excludes)
})
watchPatterns(watchedPatterns, watcher)
watcher
.on('add', (path) => fileList.addFile(helper.normalizeWinPath(path)))
.on('change', (path) => fileList.changeFile(helper.normalizeWinPath(path)))
.on('unlink', (path) => fileList.removeFile(helper.normalizeWinPath(path)))
.on('error', log.debug.bind(log))
emitter.on('exit', (done) => {
watcher.close()
done()
})
return watcher
}
watch.$inject = [
'config.files',
'config.exclude',
'fileList',
'config.usePolling',
'emitter'
]
module.exports = watch

118
my-app/node_modules/karma/lib/web-server.js generated vendored Executable file
View file

@ -0,0 +1,118 @@
'use strict'
const fs = require('graceful-fs')
const http = require('http')
const https = require('https')
const path = require('path')
const connect = require('connect')
const mimeType = require('mime')
const common = require('./middleware/common')
const runnerMiddleware = require('./middleware/runner')
const stopperMiddleware = require('./middleware/stopper')
const karmaMiddleware = require('./middleware/karma')
const sourceFilesMiddleware = require('./middleware/source_files')
const proxyMiddleware = require('./middleware/proxy')
const log = require('./logger').create('web-server')
function createCustomHandler (customFileHandlers, config) {
let warningDone = false
return function (request, response, next) {
const handler = customFileHandlers.find((handler) => handler.urlRegex.test(request.url))
if (customFileHandlers.length > 0 && !warningDone) {
warningDone = true
log.warn('The `customFileHandlers` is deprecated and will be removed in Karma 7. Please upgrade plugins relying on this provider.')
}
return handler
? handler.handler(request, response, 'fake/static', 'fake/adapter', config.basePath, 'fake/root')
: next()
}
}
createCustomHandler.$inject = ['customFileHandlers', 'config']
function createFilesPromise (emitter, fileList) {
// Set an empty list of files to avoid race issues with
// file_list_modified not having been emitted yet
let files = fileList.files
emitter.on('file_list_modified', (filesParam) => { files = filesParam })
return {
then (...args) {
return Promise.resolve(files).then(...args)
}
}
}
function createServeStaticFile (config) {
return common.createServeFile(fs, path.normalize(path.join(__dirname, '/../static')), config)
}
createServeStaticFile.$inject = ['config']
function createServeFile (config) {
return common.createServeFile(fs, null, config)
}
createServeFile.$inject = ['config']
function createWebServer (injector, config) {
const { mime = {} } = config
mimeType.define({ ...mime }, true)
const proxyMiddlewareInstance = injector.invoke(proxyMiddleware.create)
log.debug('Instantiating middleware')
const handler = connect()
if (config.beforeMiddleware) {
config.beforeMiddleware.forEach((middleware) => handler.use(injector.get('middleware:' + middleware)))
}
handler.use(injector.invoke(runnerMiddleware.create))
handler.use(injector.invoke(stopperMiddleware.create))
handler.use(injector.invoke(karmaMiddleware.create))
handler.use(injector.invoke(sourceFilesMiddleware.create))
// TODO(vojta): extract the proxy into a plugin
handler.use(proxyMiddlewareInstance)
// TODO: Deprecated. Remove in the next major
handler.use(injector.invoke(createCustomHandler))
if (config.middleware) {
config.middleware.forEach((middleware) => handler.use(injector.get('middleware:' + middleware)))
}
handler.use((request, response) => common.serve404(response, request.url))
let serverClass = http
const serverArguments = [handler]
if (config.protocol === 'https:') {
serverClass = https
serverArguments.unshift(config.httpsServerOptions || {})
}
if (config.httpModule) {
serverClass = config.httpModule
}
const server = serverClass.createServer.apply(null, serverArguments)
server.on('upgrade', function (req, socket, head) {
log.debug(`upgrade ${req.url}`)
proxyMiddlewareInstance.upgrade(req, socket, head)
})
return server
}
createWebServer.$inject = ['injector', 'config']
module.exports = {
createWebServer,
createServeFile,
createServeStaticFile,
createFilesPromise
}