Skip to content

Instantly share code, notes, and snippets.

@davidchase
Last active October 14, 2016 15:17
Show Gist options
  • Save davidchase/1c33d7c26eeefc98f0cfbf45a5d31106 to your computer and use it in GitHub Desktop.
Save davidchase/1c33d7c26eeefc98f0cfbf45a5d31106 to your computer and use it in GitHub Desktop.
Browser Test Runner Example
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<link href="style.css" rel="stylesheet"/>
</head>
<body>
<div class="app"></div>
<script src="index.js"></script>
</body>
</html>
import {fromEvent, from, fromPromise} from 'most'
import {tests} from './test'
import {renderView} from './view'
import {map, merge as assign, lift, useWith, identity,
ifElse, eqBy, prop, flip, sort, partial,
equals, compose} from 'ramda'
const promisify = run => new Promise(resolve => run(resolve))
const setStatus = status => ({status: status === true ? 'Passed' : status === 'Running' ? 'Running' : 'Failed'})
const statusUpdate = (test, status) => assign(test, setStatus(status))
const runTests = test => fromPromise(promisify(test.run)).startWith('Running').map(partial(statusUpdate, [test]))
const updateUnit = flip(lift(ifElse(eqBy(prop('description')), assign, identity)))
const updateModel = (data, unit) => updateUnit([unit], data)
const runningPassingFailing = (x, y) => x.status < y.status
const startButton = events => events.target.matches('.start-tests')
const click$ = fromEvent('click', document.body).filter(startButton)
const startTests = model => from(model).chain(runTests).scan(updateModel, model).map(sort(runningPassingFailing))
const main = model => click$
.chain(() => startTests(model))
.startWith(model)
.observe(renderView)
main(tests)
.container {
padding: 10%;
}
.test {
list-style: none;
margin: 15px 0;
}
.status {
float:right;
}
hr {
clear:both;
content: ' '
}
.name {
float:left
}
.tests {
margin: 0;
padding:0
}
button {
margin-top: 15px;
}
.finished-running {
font-weight:bold;
margin: 10px 0;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.running {
position: relative;
}
.running:before {
content: '';
position:absolute;
right: -20px;
border-radius: 50%;
width: 10px;
height: 10px;
border: 0.25rem solid #ddd;
border-top-color: #000;
animation: spin 1s infinite linear;
}
import Random from "random-js"
const randomTest = function() {
const random = new Random(Random.engines.mt19937().autoSeed())
const delay = random.integer(5000, 12000)
const testPassed = Math.random() > 0.5
return function(callback) {
setTimeout(function() {
callback(testPassed)
}, delay)
}
}
export const tests = [{
description: "commas are rotated properly",
run: randomTest()
}, {
description: "exclamation points stand up straight",
run: randomTest()
}, {
description: "run-on sentences don't run forever",
run: randomTest()
}, {
description: "question marks curl down, not up",
run: randomTest()
}, {
description: "semicolons are adequately waterproof",
run: randomTest()
}, {
description: "capital letters can do yoga",
run: randomTest()
}]
import {createBlueprint} from 'inferno'
import {render} from 'inferno-dom'
import {map, reject, compose, equals, tap,
filter, identity, partition, pluck} from 'ramda'
const bluePrintElement = function(tag, klass = true) {
return createBlueprint(Object.assign({}, {
tag: tag,
children: {
arg: 1
}
}, klass ? {
className: {
arg: 0
}
} : {}))
}
const div = bluePrintElement('div')
const hr = bluePrintElement('hr', false)
const ul = bluePrintElement('ul')
const button = bluePrintElement('button')
const span = bluePrintElement('span')
const li = bluePrintElement('li')
const getStatus = compose(map(filter(identity)), partition(equals('Passed')), reject(equals('Running')), pluck('status'))
const doneDiv = (done, model) => div('finished-running', `${done === model.length ? 'Finished!' : ''}`)
export const renderView = function(model) {
const [passed, failed] = getStatus(model)
const done = passed.concat(failed).length
render(div('container', [
div('name', 'Test Descriptions'),
div('status', 'Status'),
hr(),
ul('tests', map(test => li('test', [
span('description', test.description),
span(`status ${test.status && test.status.toLowerCase()}`, test.status || 'Not Started')
]), model)),
div('passed-count', `Passed: ${passed.length || 0}`),
div('failed-count', `Failed: ${failed.length || 0}`),
button('start-tests', 'Start Tests'),
doneDiv(done, model)
]), document.querySelector('.app'))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment