source: trip-planner-front/node_modules/karma-jasmine/lib/adapter.js@ 1ad8e64

Last change on this file since 1ad8e64 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 15.6 KB
RevLine 
[6a3a178]1(function(window) {
2
3/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "(createSpecFilter|createStartFn)" }] */
4
5'use strict'
6
7// Save link to native Date object
8// before it might be mocked by the user
9var _Date = Date
10
11/**
12 * Decision maker for whether a stack entry is considered external to jasmine and karma.
13 * @param {String} entry Error stack entry.
14 * @return {Boolean} True if external, False otherwise.
15 */
16function isExternalStackEntry (entry) {
17 return !!entry &&
18 // entries related to jasmine and karma-jasmine:
19 !/\/(jasmine-core|karma-jasmine)\//.test(entry) &&
20 // karma specifics, e.g. "at http://localhost:7018/karma.js:185"
21 !/\/(karma.js|context.html):/.test(entry)
22}
23
24/**
25 * Returns relevant stack entries.
26 * @param {Array} stack frames
27 * @return {Array} A list of relevant stack entries.
28 */
29function getRelevantStackFrom (stack) {
30 var filteredStack = []
31 var relevantStack = []
32
33 for (var i = 0; i < stack.length; i += 1) {
34 if (isExternalStackEntry(stack[i])) {
35 filteredStack.push(stack[i])
36 }
37 }
38
39 // If the filtered stack is empty, i.e. the error originated entirely from within jasmine or karma, then the whole stack
40 // should be relevant.
41 if (filteredStack.length === 0) {
42 filteredStack = stack
43 }
44
45 for (i = 0; i < filteredStack.length; i += 1) {
46 if (filteredStack[i]) {
47 relevantStack.push(filteredStack[i])
48 }
49 }
50
51 return relevantStack
52}
53
54/**
55 * Custom formatter for a failed step.
56 *
57 * Different browsers report stack trace in different ways. This function
58 * attempts to provide a concise, relevant error message by removing the
59 * unnecessary stack traces coming from the testing framework itself as well
60 * as possible repetition.
61 *
62 * @see https://github.com/karma-runner/karma-jasmine/issues/60
63 * @param {Object} step Step object with stack and message properties.
64 * @return {String} Formatted step.
65 */
66function formatFailedStep (step) {
67 var relevantMessage = []
68 var relevantStack = []
69
70 // Safari/Firefox seems to have no stack trace,
71 // so we just return the error message and if available
72 // construct a stacktrace out of filename and lineno:
73 if (!step.stack) {
74 if (step.filename) {
75 var stackframe = step.filename
76 if (step.lineno) {
77 stackframe = stackframe + ':' + step.lineno
78 }
79 relevantStack.push(stackframe)
80 }
81 relevantMessage.push(step.message)
82 return relevantMessage.concat(relevantStack).join('\n')
83 }
84
85 // Remove the message prior to processing the stack to prevent issues like
86 // https://github.com/karma-runner/karma-jasmine/issues/79
87 var stackframes = step.stack.split('\n')
88 var messageOnStack = null
89 if (stackframes[0].indexOf(step.message) !== -1) {
90 // Remove the message if it is in the stack string (eg Chrome)
91 messageOnStack = stackframes.shift()
92 }
93 // Filter frames
94 var relevantStackFrames = getRelevantStackFrom(stackframes)
95 if (messageOnStack) {
96 // Put the message back if we removed it.
97 relevantStackFrames.unshift(messageOnStack)
98 } else {
99 // The stack did not have the step.message so add it.
100 relevantStackFrames.unshift(step.message)
101 }
102
103 return relevantStackFrames.join('\n')
104}
105
106function debugUrl (description) {
107 // A link to re-run just one failed test case.
108 return window.location.origin + '/debug.html?spec=' + encodeURIComponent(description)
109}
110
111function SuiteNode (name, parent) {
112 this.name = name
113 this.parent = parent
114 this.children = []
115
116 this.addChild = function (name) {
117 var suite = new SuiteNode(name, this)
118 this.children.push(suite)
119 return suite
120 }
121}
122
123function processSuite (suite, pointer) {
124 var child
125 var childPointer
126
127 for (var i = 0; i < suite.children.length; i++) {
128 child = suite.children[i]
129
130 if (child.children) {
131 childPointer = pointer[child.description] = { _: [] }
132 processSuite(child, childPointer)
133 } else {
134 if (!pointer._) {
135 pointer._ = []
136 }
137 pointer._.push(child.description)
138 }
139 }
140}
141
142function getAllSpecNames (topSuite) {
143 var specNames = {}
144
145 processSuite(topSuite, specNames)
146
147 return specNames
148}
149
150/**
151 * Very simple reporter for Jasmine.
152 */
153function KarmaReporter (tc, jasmineEnv) {
154 var currentSuite = new SuiteNode()
155
156 var startTimeCurrentSpec = new _Date().getTime()
157
158 function handleGlobalErrors (result) {
159 if (result.failedExpectations && result.failedExpectations.length) {
160 var message = 'An error was thrown in afterAll'
161 var steps = result.failedExpectations
162 for (var i = 0, l = steps.length; i < l; i++) {
163 message += '\n' + formatFailedStep(steps[i])
164 }
165
166 tc.error(message)
167 }
168 }
169
170 /**
171 * Jasmine 2.0 dispatches the following events:
172 *
173 * - jasmineStarted
174 * - jasmineDone
175 * - suiteStarted
176 * - suiteDone
177 * - specStarted
178 * - specDone
179 */
180
181 this.jasmineStarted = function (data) {
182 // TODO(vojta): Do not send spec names when polling.
183 tc.info({
184 event: 'jasmineStarted',
185 total: data.totalSpecsDefined,
186 specs: getAllSpecNames(jasmineEnv.topSuite())
187 })
188 }
189
190 this.jasmineDone = function (result) {
191 result = result || {}
192
193 // Any errors in top-level afterAll blocks are given here.
194 handleGlobalErrors(result)
195
196 // Remove functions from called back results to avoid IPC errors in Electron
197 // https://github.com/twolfson/karma-electron/issues/47
198 var cleanedOrder
199 if (result.order) {
200 cleanedOrder = {}
201 var orderKeys = Object.getOwnPropertyNames(result.order)
202 for (var i = 0; i < orderKeys.length; i++) {
203 var orderKey = orderKeys[i]
204 if (typeof result.order[orderKey] !== 'function') {
205 cleanedOrder[orderKey] = result.order[orderKey]
206 }
207 }
208 }
209
210 tc.complete({
211 order: cleanedOrder,
212 coverage: window.__coverage__
213 })
214 }
215
216 this.suiteStarted = function (result) {
217 currentSuite = currentSuite.addChild(result.description)
218 tc.info({
219 event: 'suiteStarted',
220 result: result
221 })
222 }
223
224 this.suiteDone = function (result) {
225 // In the case of xdescribe, only "suiteDone" is fired.
226 // We need to skip that.
227 if (result.description !== currentSuite.name) {
228 return
229 }
230
231 // Any errors in afterAll blocks are given here, except for top-level
232 // afterAll blocks.
233 handleGlobalErrors(result)
234
235 currentSuite = currentSuite.parent
236
237 tc.info({
238 event: 'suiteDone',
239 result: result
240 })
241 }
242
243 this.specStarted = function () {
244 startTimeCurrentSpec = new _Date().getTime()
245 }
246
247 this.specDone = function (specResult) {
248 var skipped = specResult.status === 'disabled' || specResult.status === 'pending' || specResult.status === 'excluded'
249 var result = {
250 fullName: specResult.fullName,
251 description: specResult.description,
252 id: specResult.id,
253 log: [],
254 skipped: skipped,
255 disabled: specResult.status === 'disabled' || specResult.status === 'excluded',
256 pending: specResult.status === 'pending',
257 success: specResult.failedExpectations.length === 0,
258 suite: [],
259 time: skipped ? 0 : new _Date().getTime() - startTimeCurrentSpec,
260 executedExpectationsCount: specResult.failedExpectations.length + specResult.passedExpectations.length,
261 passedExpectations: specResult.passedExpectations,
262 properties: specResult.properties
263 }
264
265 // generate ordered list of (nested) suite names
266 var suitePointer = currentSuite
267 while (suitePointer.parent) {
268 result.suite.unshift(suitePointer.name)
269 suitePointer = suitePointer.parent
270 }
271
272 if (!result.success) {
273 var steps = specResult.failedExpectations
274 for (var i = 0, l = steps.length; i < l; i++) {
275 result.log.push(formatFailedStep(steps[i]))
276 }
277
278 if (typeof window !== 'undefined' && window.location && window.location.origin) {
279 // Report the name of fhe failing spec so the reporter can emit a debug url.
280 result.debug_url = debugUrl(specResult.fullName)
281 }
282 }
283
284 // When failSpecWithNoExpectations is true, Jasmine will report specs without expectations as failed
285 if (result.executedExpectationsCount === 0 && specResult.status === 'failed') {
286 result.success = false
287 result.log.push('Spec has no expectations')
288 }
289
290 tc.result(result)
291 delete specResult.startTime
292 }
293}
294
295/**
296 * Extract grep option from karma config
297 * @param {[Array|string]} clientArguments The karma client arguments
298 * @return {string} The value of grep option by default empty string
299 */
300var getGrepOption = function (clientArguments) {
301 var grepRegex = /^--grep=(.*)$/
302
303 if (Object.prototype.toString.call(clientArguments) === '[object Array]') {
304 var indexOfGrep = indexOf(clientArguments, '--grep')
305
306 if (indexOfGrep !== -1) {
307 return clientArguments[indexOfGrep + 1]
308 }
309
310 return map(filter(clientArguments, function (arg) {
311 return grepRegex.test(arg)
312 }), function (arg) {
313 return arg.replace(grepRegex, '$1')
314 })[0] || ''
315 } else if (typeof clientArguments === 'string') {
316 var match = /--grep=([^=]+)/.exec(clientArguments)
317
318 return match ? match[1] : ''
319 }
320}
321
322var createRegExp = function (filter) {
323 filter = filter || ''
324 if (filter === '') {
325 return new RegExp() // to match all
326 }
327
328 var regExp = /^[/](.*)[/]([gmixXsuUAJD]*)$/ // pattern to check whether the string is RegExp pattern
329
330 var parts = regExp.exec(filter)
331 if (parts === null) {
332 return new RegExp(filter.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')) // escape functional symbols
333 }
334
335 var patternExpression = parts[1]
336 var patternSwitches = parts[2]
337 return new RegExp(patternExpression, patternSwitches)
338}
339
340function getGrepSpecsToRun (clientConfig, specs) {
341 var grepOption = getGrepOption(clientConfig.args)
342 if (grepOption) {
343 var regExp = createRegExp(grepOption)
344 return filter(specs, function specFilter (spec) {
345 return regExp.test(spec.getFullName())
346 })
347 }
348}
349
350function parseQueryParams (location) {
351 var params = {}
352 if (location && Object.prototype.hasOwnProperty.call(location, 'search')) {
353 var pairs = location.search.substr(1).split('&')
354 for (var i = 0; i < pairs.length; i++) {
355 var keyValue = pairs[i].split('=')
356 params[decodeURIComponent(keyValue[0])] =
357 decodeURIComponent(keyValue[1])
358 }
359 }
360 return params
361}
362
363function getId (s) {
364 return s.id
365}
366
367function getSpecsByName (specs, name) {
368 specs = specs.filter(function (s) {
369 return s.name.indexOf(name) !== -1
370 })
371 if (specs.length === 0) {
372 throw new Error('No spec found with name: "' + name + '"')
373 }
374 return specs
375}
376
377function getDebugSpecToRun (location, specs) {
378 var queryParams = parseQueryParams(location)
379 var spec = queryParams.spec
380 if (spec) {
381 // A single spec has been requested by name for debugging.
382 return getSpecsByName(specs, spec)
383 }
384}
385
386function getSpecsToRunForCurrentShard (specs, shardIndex, totalShards) {
387 if (specs.length < totalShards) {
388 throw new Error(
389 'More shards (' + totalShards + ') than test specs (' + specs.length +
390 ')')
391 }
392
393 // Just do a simple sharding strategy of dividing the number of specs
394 // equally.
395 var firstSpec = Math.floor(specs.length * shardIndex / totalShards)
396 var lastSpec = Math.floor(specs.length * (shardIndex + 1) / totalShards)
397 return specs.slice(firstSpec, lastSpec)
398}
399
400function getShardedSpecsToRun (specs, clientConfig) {
401 var shardIndex = clientConfig.shardIndex
402 var totalShards = clientConfig.totalShards
403 if (shardIndex != null && totalShards != null) {
404 // Sharded mode - Run only the subset of the specs corresponding to the
405 // current shard.
406 return getSpecsToRunForCurrentShard(
407 specs, Number(shardIndex), Number(totalShards))
408 }
409}
410
411/**
412 * Create jasmine spec filter
413 * @param {Object} clientConfig karma config
414 * @param {!Object} jasmineEnv
415 */
416var KarmaSpecFilter = function (clientConfig, jasmineEnv) {
417 /**
418 * Walk the test suite tree depth first and collect all test specs
419 * @param {!Object} jasmineEnv
420 * @return {!Array<string>} All possible tests.
421 */
422 function getAllSpecs (jasmineEnv) {
423 var specs = []
424 var stack = [jasmineEnv.topSuite()]
425 var currentNode
426 while ((currentNode = stack.pop())) {
427 if (currentNode.children) {
428 // jasmine.Suite
429 stack = stack.concat(currentNode.children)
430 } else if (currentNode.id) {
431 // jasmine.Spec
432 specs.unshift(currentNode)
433 }
434 }
435
436 return specs
437 }
438
439 /**
440 * Filter the specs with URL search params and config.
441 * @param {!Object} location property 'search' from URL.
442 * @param {!Object} clientConfig karma client config
443 * @param {!Object} jasmineEnv
444 * @return {!Array<string>}
445 */
446 function getSpecsToRun (location, clientConfig, jasmineEnv) {
447 var specs = getAllSpecs(jasmineEnv).map(function (spec) {
448 spec.name = spec.getFullName()
449 return spec
450 })
451
452 if (!specs || !specs.length) {
453 return []
454 }
455
456 return getGrepSpecsToRun(clientConfig, specs) ||
457 getDebugSpecToRun(location, specs) ||
458 getShardedSpecsToRun(specs, clientConfig) ||
459 specs
460 }
461
462 this.specIdsToRun =
463 getSpecsToRun(window.location, clientConfig, jasmineEnv).map(getId)
464
465 this.matches = function (spec) {
466 return this.specIdsToRun.indexOf(spec.id) !== -1
467 }
468}
469
470/**
471 * Configure jasmine specFilter
472 *
473 * This function is invoked from the wrapper.
474 * @see adapter.wrapper
475 *
476 * @param {Object} config The karma config
477 * @param {Object} jasmineEnv jasmine environment object
478 */
479var createSpecFilter = function (config, jasmineEnv) {
480 var karmaSpecFilter = new KarmaSpecFilter(config, jasmineEnv)
481
482 var specFilter = function (spec) {
483 return karmaSpecFilter.matches(spec)
484 }
485
486 return specFilter
487}
488
489/**
490 * Karma starter function factory.
491 *
492 * This function is invoked from the wrapper.
493 * @see adapter.wrapper
494 *
495 * @param {Object} karma Karma runner instance.
496 * @param {Object} [jasmineEnv] Optional Jasmine environment for testing.
497 * @return {Function} Karma starter function.
498 */
499function createStartFn (karma, jasmineEnv) {
500 // This function will be assigned to `window.__karma__.start`:
501 return function () {
502 var clientConfig = karma.config || {}
503 var jasmineConfig = clientConfig.jasmine || {}
504
505 jasmineEnv = jasmineEnv || window.jasmine.getEnv()
506
507 jasmineConfig.specFilter = createSpecFilter(clientConfig, jasmineEnv)
508
509 jasmineEnv.configure(jasmineConfig)
510
511 window.jasmine.DEFAULT_TIMEOUT_INTERVAL = jasmineConfig.timeoutInterval ||
512 window.jasmine.DEFAULT_TIMEOUT_INTERVAL
513 jasmineEnv.addReporter(new KarmaReporter(karma, jasmineEnv))
514 jasmineEnv.execute()
515 }
516}
517
518function indexOf (collection, find, i /* opt */) {
519 if (collection.indexOf) {
520 return collection.indexOf(find, i)
521 }
522
523 if (i === undefined) { i = 0 }
524 if (i < 0) { i += collection.length }
525 if (i < 0) { i = 0 }
526 for (var n = collection.length; i < n; i++) {
527 if (i in collection && collection[i] === find) {
528 return i
529 }
530 }
531 return -1
532}
533
534function filter (collection, filter, that /* opt */) {
535 if (collection.filter) {
536 return collection.filter(filter, that)
537 }
538
539 var other = []
540 var v
541 for (var i = 0, n = collection.length; i < n; i++) {
542 if (i in collection && filter.call(that, v = collection[i], i, collection)) {
543 other.push(v)
544 }
545 }
546 return other
547}
548
549function map (collection, mapper, that /* opt */) {
550 if (collection.map) {
551 return collection.map(mapper, that)
552 }
553
554 var other = new Array(collection.length)
555 for (var i = 0, n = collection.length; i < n; i++) {
556 if (i in collection) {
557 other[i] = mapper.call(that, collection[i], i, collection)
558 }
559 }
560 return other
561}
562
563window.__karma__.start = createStartFn(window.__karma__)
564
565})(typeof window !== 'undefined' ? window : global);
Note: See TracBrowser for help on using the repository browser.