miniLockLib/window_test_harness.coffee

module.exports = require("tape").createHarness()

testTemplate = document.getElementById("test_template")
failureTemplate = document.getElementById("failure_template")
assertionTemplate = document.getElementById("assertion_template")
numberOfTests = document.getElementById("number_of_tests")
numberOfFailedTests = document.getElementById("number_of_failed_tests")
idOfCurrentlyRunningTest = undefined
untouched = yes
failedTests = []

module.exports.createStream(objectMode:yes).on "data", (data) ->
  switch
    when data.type is "test"
      idOfCurrentlyRunningTest = data.id
      insertTestElement(data)
      renderBodyElement(data)
    when data.operator?
      fixBrokenThrowsOperatorData(data)
      if data.ok is false
        failedTests.push(idOfCurrentlyRunningTest) unless idOfCurrentlyRunningTest in failedTests
      element = findElementForTest(idOfCurrentlyRunningTest)
      renderTestElementUpdate(element, data)
      insertTestAssertion(element, data)
      insertFailure(element, data) unless data.ok
    when data.type is "end"
      idOfCurrentlyRunningTest = undefined
      renderTestElementEnded(findElementForTest(data.test), data)
      numberOfFailedTests.innerText = failedTests.length if failedTests.length isnt 0
      numberOfTests.innerText = data.test
      renderBodyElement(data)
    else
      console.error("Unhandled", data)

window.onmousewheel = ->
  delete window.onmousewheel
  untouched = no

renderBodyElement = (data) ->
  body = document.body
  body.className = body.className.replace("undefined", "")
  body.className = switch
    when data.type is "test"
      body.className.replace("stopped", "running")
    when data.type is "end"
      body.className.replace("running", "stopped")
    else
      body.className
  if failedTests.length is 1 and body.className.indexOf("fail") is -1
    body.className += " failures"

insertTestElement = (data) ->
  element = testTemplate.cloneNode(true)
  element.id = "test_#{data.id}"
  element.querySelector(".name").innerText = data.name
  element.className += " started"
  element.startedAt = Date.now()
  element.querySelector("div.id").innerText = (data.id / 1000).toFixed(3).replace("0.", "#")
  container = document.getElementById('tests')
  container.appendChild(element)
  containerHeight = parseInt getComputedStyle(container)['height']
  bodyHeight = parseInt getComputedStyle(document.body)['height']
  if (containerHeight > bodyHeight)
    document.body.style.height = "#{containerHeight}px"
  element.scrollIntoView() if untouched

renderTestElementUpdate = (element, data) ->
  className = if data.ok then "ok" else "failed"
  element.className = element.className.replace(className,"").trim() + " " + className

renderTestElementEnded = (element, data) ->
  element.className = element.className.replace("started", "ended")
  element.querySelector("div.duration").innerText = "#{((Date.now() - element.startedAt) / 1000).toFixed(2)}s"

insertTestAssertion = (element, data) ->
  assertionEl = assertionTemplate.cloneNode(true)
  assertionEl.id = "test_#{idOfCurrentlyRunningTest}_assertion_#{data.id}"
  element.className = element.className.replace('empty', '').trim()
  element.querySelector('.assertions').appendChild(assertionEl)

insertFailure = (element, data) ->
  failureEl = failureTemplate.cloneNode("true")
  failureEl.id = ""
  if typeof data.expected is "function"
    failureEl.querySelector("pre.expected").innerHTML += data.expected
  else
    failureEl.querySelector("pre.expected").innerHTML += JSON.stringify(data.expected, undefined, "  ")
  if typeof data.actual is "function"
    failureEl.querySelector("pre.received").innerHTML += data.actual
  else
    failureEl.querySelector("pre.received").innerHTML += JSON.stringify(data.actual, undefined, "  ")
  if data.error?
    failureEl.querySelector("pre.error_stack").innerText = data.error.stack
  element.appendChild(failureEl)

Scroll the first error into view unless the page has already been touched.

  if (failedTests.length is 1) and untouched
    untouched = false
    setTimeout (-> element.scrollIntoView(true)), 1

fixBrokenThrowsOperatorData = (data) ->
  if (data.operator is "throws") and (data.name isnt data.actual)
    data.ok = no
    data.expected = data.name
    data.name = undefined
    data.fixedForThrowsOperator = yes

findElementForTest = (id) ->
  document.getElementById("test_#{id}")