pulsar/spec/atom-reporter.coffee

318 lines
11 KiB
CoffeeScript
Raw Normal View History

2014-02-11 06:40:49 +04:00
path = require 'path'
process = require 'process'
_ = require 'underscore-plus'
2014-06-17 22:28:01 +04:00
grim = require 'grim'
listen = require '../src/delegated-listener'
ipcHelpers = require '../src/ipc-helpers'
2014-02-19 23:12:58 +04:00
formatStackTrace = (spec, message='', stackTrace) ->
return stackTrace unless stackTrace
2017-11-22 01:35:26 +03:00
# at ... (.../jasmine.js:1:2)
jasminePattern = /^\s*at\s+.*\(?.*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/
2017-11-22 01:35:26 +03:00
# at jasmine.Something... (.../jasmine.js:1:2)
firstJasmineLinePattern = /^\s*at\s+jasmine\.[A-Z][^\s]*\s+\(?.*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/
lines = []
for line in stackTrace.split('\n')
break if firstJasmineLinePattern.test(line)
2017-11-22 01:35:26 +03:00
lines.push(line) unless jasminePattern.test(line)
# Remove first line of stack when it is the same as the error message
errorMatch = lines[0]?.match(/^Error: (.*)/)
lines.shift() if message.trim() is errorMatch?[1]?.trim()
2017-11-22 01:35:26 +03:00
lines = lines.map (line) ->
# Only format actual stacktrace lines
if /^\s*at\s/.test(line)
# Needs to occur before path relativization
if process.platform is 'win32' and /file:\/\/\//.test(line)
# file:///C:/some/file -> C:\some\file
line = line.replace('file:///', '').replace(///#{path.posix.sep}///g, path.win32.sep)
line = line.trim()
2017-11-22 02:02:42 +03:00
# at jasmine.Spec.<anonymous> (path:1:2) -> at path:1:2
.replace(/^at jasmine\.Spec\.<anonymous> \(([^)]+)\)/, 'at $1')
2018-07-02 00:18:16 +03:00
# at jasmine.Spec.it (path:1:2) -> at path:1:2
.replace(/^at jasmine\.Spec\.f*it \(([^)]+)\)/, 'at $1')
2017-11-22 02:02:42 +03:00
# at it (path:1:2) -> at path:1:2
.replace(/^at f*it \(([^)]+)\)/, 'at $1')
# at spec/file-test.js -> at file-test.js
.replace(spec.specDirectory + path.sep, '')
2014-02-19 23:12:58 +04:00
2017-11-22 02:02:42 +03:00
return line
2017-11-22 01:35:26 +03:00
2014-02-19 23:07:02 +04:00
lines.join('\n').trim()
2013-02-12 06:00:42 +04:00
module.exports =
2015-09-05 18:28:12 +03:00
class AtomReporter
constructor: ->
@element = document.createElement('div')
2016-06-11 04:46:10 +03:00
@element.classList.add('spec-reporter-container')
2015-09-05 18:28:12 +03:00
@element.innerHTML = """
<div class="spec-reporter">
<div class="padded pull-right">
<button outlet="reloadButton" class="btn btn-small reload-button">Reload Specs</button>
</div>
<div outlet="coreArea" class="symbol-area">
<div outlet="coreHeader" class="symbol-header"></div>
<ul outlet="coreSummary"class="symbol-summary list-unstyled"></ul>
</div>
<div outlet="bundledArea" class="symbol-area">
<div outlet="bundledHeader" class="symbol-header"></div>
<ul outlet="bundledSummary"class="symbol-summary list-unstyled"></ul>
</div>
<div outlet="userArea" class="symbol-area">
<div outlet="userHeader" class="symbol-header"></div>
<ul outlet="userSummary"class="symbol-summary list-unstyled"></ul>
</div>
<div outlet="status" class="status alert alert-info">
<div outlet="time" class="time"></div>
<div outlet="specCount" class="spec-count"></div>
<div outlet="message" class="message"></div>
</div>
<div outlet="results" class="results"></div>
<div outlet="deprecations" class="status alert alert-warning" style="display: none">
<span outlet="deprecationStatus">0 deprecations</span>
<div class="deprecation-toggle"></div>
</div>
<div outlet="deprecationList" class="deprecation-list"></div>
</div>
"""
for element in @element.querySelectorAll('[outlet]')
this[element.getAttribute('outlet')] = element
2014-06-17 22:28:01 +04:00
2013-02-12 06:00:42 +04:00
startedAt: null
runningSpecCount: 0
completeSpecCount: 0
passedCount: 0
failedCount: 0
skippedCount: 0
totalSpecCount: 0
2014-06-17 22:28:01 +04:00
deprecationCount: 0
2013-02-12 06:00:42 +04:00
@timeoutId: 0
reportRunnerStarting: (runner) ->
2013-02-12 08:23:42 +04:00
@handleEvents()
2014-02-11 08:52:35 +04:00
@startedAt = Date.now()
2013-02-12 06:00:42 +04:00
specs = runner.specs()
@totalSpecCount = specs.length
@addSpecs(specs)
2015-09-05 18:28:12 +03:00
document.body.appendChild(@element)
2014-12-06 02:03:06 +03:00
2013-02-12 06:00:42 +04:00
reportRunnerResults: (runner) ->
@updateSpecCounts()
2015-09-05 18:28:12 +03:00
if @failedCount is 0
@status.classList.add('alert-success')
@status.classList.remove('alert-info')
2014-02-11 21:23:12 +04:00
if @failedCount is 1
2015-09-05 18:28:12 +03:00
@message.textContent = "#{@failedCount} failure"
2013-02-12 06:00:42 +04:00
else
@message.textContent = "#{@failedCount} failures"
2013-02-12 06:00:42 +04:00
reportSuiteResults: (suite) ->
2013-02-12 06:00:42 +04:00
reportSpecResults: (spec) ->
@completeSpecCount++
2014-02-11 08:52:35 +04:00
spec.endedAt = Date.now()
2013-02-12 06:00:42 +04:00
@specComplete(spec)
@updateStatusView(spec)
reportSpecStarting: (spec) ->
@specStarted(spec)
2013-02-12 08:23:42 +04:00
handleEvents: ->
2015-09-05 18:28:12 +03:00
listen document, 'click', '.spec-toggle', (event) ->
specFailures = event.currentTarget.parentElement.querySelector('.spec-failures')
if specFailures.style.display is 'none'
specFailures.style.display = ''
event.currentTarget.classList.remove('folded')
else
specFailures.style.display = 'none'
event.currentTarget.classList.add('folded')
event.preventDefault()
listen document, 'click', '.deprecation-list', (event) ->
deprecationList = event.currentTarget.parentElement.querySelector('.deprecation-list')
if deprecationList.style.display is 'none'
deprecationList.style.display = ''
event.currentTarget.classList.remove('folded')
else
deprecationList.style.display = 'none'
event.currentTarget.classList.add('folded')
event.preventDefault()
listen document, 'click', '.stack-trace', (event) ->
event.currentTarget.classList.toggle('expanded')
@reloadButton.addEventListener('click', -> ipcHelpers.call('window-method', 'reload'))
2015-09-05 18:28:12 +03:00
updateSpecCounts: ->
if @skippedCount
specCount = "#{@completeSpecCount - @skippedCount}/#{@totalSpecCount - @skippedCount} (#{@skippedCount} skipped)"
else
specCount = "#{@completeSpecCount}/#{@totalSpecCount}"
2015-09-05 18:28:12 +03:00
@specCount.textContent = specCount
2013-02-12 06:00:42 +04:00
updateStatusView: (spec) ->
if @failedCount > 0
2015-09-05 18:28:12 +03:00
@status.classList.add('alert-danger')
@status.classList.remove('alert-info')
@updateSpecCounts()
2013-02-12 06:00:42 +04:00
rootSuite = spec.suite
rootSuite = rootSuite.parentSuite while rootSuite.parentSuite
2015-09-05 18:28:12 +03:00
@message.textContent = rootSuite.description
2013-02-12 06:00:42 +04:00
2014-02-11 08:52:35 +04:00
time = "#{Math.round((spec.endedAt - @startedAt) / 10)}"
2013-02-13 02:48:16 +04:00
time = "0#{time}" if time.length < 3
2015-09-05 18:28:12 +03:00
@time.textContent = "#{time[0...-2]}.#{time[-2..]}s"
2013-02-12 06:00:42 +04:00
specTitle: (spec) ->
parentDescs = []
s = spec.suite
while s
parentDescs.unshift(s.description)
s = s.parentSuite
suiteString = ""
indent = ""
for desc in parentDescs
suiteString += indent + desc + "\n"
indent += " "
"#{suiteString} #{indent} it #{spec.description}"
2013-02-12 06:00:42 +04:00
addSpecs: (specs) ->
coreSpecs = 0
bundledPackageSpecs = 0
userPackageSpecs = 0
2013-02-12 06:00:42 +04:00
for spec in specs
2015-09-05 18:28:12 +03:00
symbol = document.createElement('li')
symbol.setAttribute('id', "spec-summary-#{spec.id}")
symbol.setAttribute('title', @specTitle(spec))
2015-09-05 18:28:12 +03:00
symbol.className = "spec-summary pending"
switch spec.specType
when 'core'
coreSpecs++
2015-09-05 18:28:12 +03:00
@coreSummary.appendChild symbol
when 'bundled'
bundledPackageSpecs++
2015-09-05 18:28:12 +03:00
@bundledSummary.appendChild symbol
when 'user'
userPackageSpecs++
2015-09-05 18:28:12 +03:00
@userSummary.appendChild symbol
if coreSpecs > 0
2015-09-05 18:28:12 +03:00
@coreHeader.textContent = "Core Specs (#{coreSpecs})"
else
2015-09-05 18:28:12 +03:00
@coreArea.style.display = 'none'
if bundledPackageSpecs > 0
2015-09-05 18:28:12 +03:00
@bundledHeader.textContent = "Bundled Package Specs (#{bundledPackageSpecs})"
else
2015-09-05 18:28:12 +03:00
@bundledArea.style.display = 'none'
if userPackageSpecs > 0
2014-02-11 06:40:49 +04:00
if coreSpecs is 0 and bundledPackageSpecs is 0
2014-02-11 07:12:54 +04:00
# Package specs being run, show a more descriptive label
{specDirectory} = specs[0]
packageFolderName = path.basename(path.dirname(specDirectory))
2014-02-11 06:40:49 +04:00
packageName = _.undasherize(_.uncamelcase(packageFolderName))
2015-09-05 18:28:12 +03:00
@userHeader.textContent = "#{packageName} Specs"
2014-02-11 06:40:49 +04:00
else
2015-09-05 18:28:12 +03:00
@userHeader.textContent = "User Package Specs (#{userPackageSpecs})"
else
2015-09-05 18:28:12 +03:00
@userArea.style.display = 'none'
2013-02-12 06:00:42 +04:00
specStarted: (spec) ->
@runningSpecCount++
specComplete: (spec) ->
2015-09-05 18:28:12 +03:00
specSummaryElement = document.getElementById("spec-summary-#{spec.id}")
specSummaryElement.classList.remove('pending')
2013-02-12 06:00:42 +04:00
results = spec.results()
if results.skipped
2015-09-05 18:28:12 +03:00
specSummaryElement.classList.add("skipped")
2013-02-12 06:00:42 +04:00
@skippedCount++
else if results.passed()
2015-09-05 18:28:12 +03:00
specSummaryElement.classList.add("passed")
2013-02-12 06:00:42 +04:00
@passedCount++
else
2015-09-05 18:28:12 +03:00
specSummaryElement.classList.add("failed")
2013-02-12 06:00:42 +04:00
specView = new SpecResultView(spec)
specView.attach()
@failedCount++
2015-09-05 18:28:12 +03:00
class SuiteResultView
constructor: (@suite) ->
@element = document.createElement('div')
@element.className = 'suite'
@element.setAttribute('id', "suite-view-#{@suite.id}")
@description = document.createElement('div')
@description.className = 'description'
@description.textContent = @suite.description
@element.appendChild(@description)
2013-02-12 06:00:42 +04:00
attach: ->
2015-09-05 18:28:12 +03:00
(@parentSuiteView() or document.querySelector('.results')).appendChild(@element)
2013-02-12 06:00:42 +04:00
parentSuiteView: ->
return unless @suite.parentSuite
2015-09-05 18:28:12 +03:00
unless suiteViewElement = document.querySelector("#suite-view-#{@suite.parentSuite.id}")
2013-02-12 06:00:42 +04:00
suiteView = new SuiteResultView(@suite.parentSuite)
suiteView.attach()
2015-09-05 18:28:12 +03:00
suiteViewElement = suiteView.element
2013-02-12 06:00:42 +04:00
2015-09-05 18:28:12 +03:00
suiteViewElement
2013-02-12 06:00:42 +04:00
2015-09-05 18:28:12 +03:00
class SpecResultView
constructor: (@spec) ->
@element = document.createElement('div')
@element.className = 'spec'
@element.innerHTML = """
<div class='spec-toggle'></div>
<div outlet='description' class='description'></div>
<div outlet='specFailures' class='spec-failures'></div>
"""
@description = @element.querySelector('[outlet="description"]')
@specFailures = @element.querySelector('[outlet="specFailures"]')
2013-02-12 06:00:42 +04:00
2015-09-05 18:28:12 +03:00
@element.classList.add("spec-view-#{@spec.id}")
2014-02-11 06:53:06 +04:00
description = @spec.description
description = "it #{description}" if description.indexOf('it ') isnt 0
2015-09-05 18:28:12 +03:00
@description.textContent = description
2013-02-12 06:00:42 +04:00
for result in @spec.results().getItems() when not result.passed()
2014-02-19 23:12:58 +04:00
stackTrace = formatStackTrace(@spec, result.message, result.trace.stack)
2015-09-05 18:28:12 +03:00
resultElement = document.createElement('div')
resultElement.className = 'result-message fail'
resultElement.textContent = result.message
@specFailures.appendChild(resultElement)
if stackTrace
traceElement = document.createElement('pre')
traceElement.className = 'stack-trace padded'
traceElement.textContent = stackTrace
@specFailures.appendChild(traceElement)
2013-02-12 06:00:42 +04:00
attach: ->
2015-09-05 18:28:12 +03:00
@parentSuiteView().appendChild(@element)
2013-02-12 06:00:42 +04:00
parentSuiteView: ->
2015-09-05 18:28:12 +03:00
unless suiteViewElement = document.querySelector("#suite-view-#{@spec.suite.id}")
2013-02-12 06:00:42 +04:00
suiteView = new SuiteResultView(@spec.suite)
suiteView.attach()
2015-09-05 18:28:12 +03:00
suiteViewElement = suiteView.element
2013-02-12 06:00:42 +04:00
2015-09-05 18:28:12 +03:00
suiteViewElement