halfcab
Version:
A simple universal JavaScript framework focused on making use of es2015 template strings to build components.
375 lines (323 loc) • 19.3 kB
JavaScript
import chai from 'chai'
import dirtyChai from 'dirty-chai'
import sinon from 'sinon'
import sinonChai from 'sinon-chai'
import jsdomGlobal from 'jsdom-global'
import pelo from 'pelo'
const {expect} = chai
chai.use(dirtyChai)
chai.use(sinonChai)
chai.use(dirtyChai)
let serverHtml = (strings, ...values) => {
// this duplicates the halfcab html function but uses pelo instead of bel
values = values.map(value => {
if (value && value.hasOwnProperty('toString')) {
return value.toString()
}
return value
})
return pelo(strings, ...values)
}
let halfcab, ssr, html, defineRoute, gotoRoute, formField, cache, updateState, injectMarkdown, formIsValid, emptyBody, css, state, getRouteComponent
function intialData(dataInitial){
let el = document.createElement('div')
el.setAttribute('data-initial', dataInitial)
document.body.appendChild(el)
}
global.requestAnimationFrame = func => {
func()
}
describe('halfcab', () => {
before(async() => {
jsdomGlobal()
intialData('eyJjb250YWN0Rm9ybSI6eyJzZW5kRGlzYWJsZWQiOmZhbHNlLCJzaG93VGhhbmtzIjpmYWxzZX0sImxvZ2luIjp7ImRpc2FibGVkIjpmYWxzZX0sImxvYWRpbmciOmZhbHNlLCJyb3V0ZXIiOnsicGF0aG5hbWUiOiIvIn0sInNob3dDb250YWN0Ijp0cnVlLCJwcm9kdWN0cyI6W3sibmFtZSI6IlNlZU1vbnN0ZXIiLCJwcm9kdWN0VHlwZSI6IkRpZ2l0YWwgU2lnbmFnZSIsImRlc2NyaXB0aW9uIjoiRGlnaXRhbCBzaWduYWdlIGJ1aWx0IGZvciBza2kgYXJlYXMuIiwicHJpY2UiOiIkMywyMDAgVVNEIHBlciB3aW50ZXIiLCJsb2dvIjp7InVybCI6Ii8vaW1hZ2VzLmNvbnRlbnRmdWwuY29tLzZwOG9oeGZpa2FrMS82Z1pjUDY0bVRtMjJtMDJZYW9NR09RL2Q3ZmVmOTBlZWFmMjkyZDA0NzBjM2I2OWE4MmIyYzY1L3NlZW1vbnN0ZXIuc3ZnIiwibmFtZSI6IlNlZU1vbnN0ZXIgTG9nbyJ9LCJkZXRhaWxTZWN0aW9ucyI6W3sibmFtZSI6IldoYXQgaXMgU2VlTW9uc3RlciIsImRlc2NyaXB0aW9uIjoiIyMjIFNlZU1vbnN0ZXIgZW5hYmxlcyB5b3UgdG8gZGlzcGxheSBkeW5hbWljIG1lc3NhZ2VzIG9uIHNjcmVlbnMgYXJvdW5kIHlvdXIgc2tpIGFyZWEgYW5kIG9uIGhvdGVsIHJvb20gVFZzLCBhbGwgbWFuYWdlZCBvdmVyIHRoZSBJbnRlcm5ldC4iLCJsaXN0IjoiIiwibWVkaWEiOnsiZmlsZSI6Ii8vaW1hZ2VzLmNvbnRlbnRmdWwuY29tLzZwOG9oeGZpa2FrMS9iZm1BTlB0TWZRQ1F1UTRRa2FXVUUvMjQ5NjQyNTc4YmZhMGVjMTczYmUzOGNhOTMyNGFhMTMvc2VlbW9uc3Rlci0xLTItMy5wbmciLCJ3aWR0aCI6ODY2fSwibGluayI6IiJ9LHsibmFtZSI6IlNlZU1vbnN0ZXIgSW5jbHVkZXMiLCJkZXNjcmlwdGlvbiI6IiIsImxpc3QiOlsiUGxheXMgb24gYW55IGNvbXB1dGVyICYgVFYgY29tYm8iLCJCYW5kd2lkdGgsIHN0b3JhZ2UgJiBzdXBwb3J0IGluY2x1ZGVkIiwiRWFzeSBkcmFnIGFuZCBkcm9wIGFkbWluLiIsIkJ1aWx0IGluIGFuaW1hdGlvbi4iLCJVcGxvYWQgaW1hZ2VzIGFuZCB2aWRlbyBpbiBhbnkgZm9ybWF0IiwiVXNlIHdpdGggYm90aCBkaWdpdGFsIHNpZ25zIGFuZCBpbi1yb29tIFRWIHN5c3RlbXMiLCJVc2UgbGl2ZSBkYXRhIHRvIHBvcHVsYXRlIHRleHQgZmllbGRzICYgc3dhcCBvdXQgaW1hZ2VzIiwiUmVtb3RlbHkgY29udHJvbCB5b3VyIHNjcmVlbnMiLCJTY2hlZHVsZSBjb250ZW50IiwiU29jaWFsIG1lZGlhIGZlZWRzIiwiRGlzcGxheSB2aWRlb3MgYW5kIHBob3RvcyIsIk1hcHMsIGxpZnQgJiB0cmFpbCBzdGF0dXMiXSwibWVkaWEiOnsiZmlsZSI6Ii8vaW1hZ2VzLmNvbnRlbnRmdWwuY29tLzZwOG9oeGZpa2FrMS8zeTBBYVBQTXpDR0tpdUtjTXVlYTJRL2Y1MmI1NzlkYzlhMjA4MGU0ODQ5ZWU4NzIyNjEyNGMyL1FULXdlYXRoZXJmb3JlY2FzdC1zY3JlZW4uanBnIiwid2lkdGgiOjY2N30sImxpbmsiOiIifV19LHsibmFtZSI6InZpY29NYXAiLCJwcm9kdWN0VHlwZSI6IkludGVyYWN0aXZlIFRyYWlsIE1hcCIsImRlc2NyaXB0aW9uIjoiKlRoZSogaW50ZXJhY3RpdmUgbWFwIGZvciBza2kgYXJlYXMuIiwicHJpY2UiOiIkMiw4MDAgVVNEIHBlciB3aW50ZXIiLCJsb2dvIjp7InVybCI6Ii8vaW1hZ2VzLmNvbnRlbnRmdWwuY29tLzZwOG9oeGZpa2FrMS8xc0M5TjFXSFc4MkFXa29lSWNLUVkyLzY4OGNiYjk2ZTdiZTYwMmRkMWY5YmZiYWZmMjRlMjkwL3ZpY29tYXAuc3ZnIiwibmFtZSI6InZpY29NYXAgTG9nbyJ9LCJkZXRhaWxTZWN0aW9ucyI6W3sibmFtZSI6IkRlbW8iLCJkZXNjcmlwdGlvbiI6IipUaGUgYmVzdCB3YXkgdG8gY2hlY2sgb3V0IHZpY29NYXAsIGlzIHRvIGp1c3Qgc3RhcnQgdXNpbmcgaXQhIEhhdmUgYSBnbyB3aXRoIHRoaXMgb25lIGFuZCBsZXQgdXMga25vdyB3aGF0IHlvdSB0aGluay4qIiwibGlzdCI6IiIsIm1lZGlhIjoiIiwibGluayI6Imh0dHBzOi8vdmljb21hcC1jZG4ucmVzb3J0cy1pbnRlcmFjdGl2ZS5jb20vbWFwLzEyIn0seyJuYW1lIjoidmljb01hcCBpbmNsdWRlcyIsImRlc2NyaXB0aW9uIjoiIiwibGlzdCI6WyJSZXNwb25zaXZlICh3b3JrcyBvbiBkZXNrdG9wIGFuZCBtb2JpbGUgZGV2aWNlcykiLCJMaXZlIGxpZnQgYW5kIHRyYWlsIGRhdGEgKGZyZWUgYmFzaWMgUmVwb3J0IFBhbCBjb25uZWN0b3IgaW5jbHVkZWQpIiwiQ2xvdWQgaG9zdGVkIChBV1MpIiwiQmFuZHdpZHRoLCBzdG9yYWdlICYgc3VwcG9ydCBpbmNsdWRlZCIsIkVhc3kgd2Vic2l0ZSBlbWJlZCIsIk5vIHNldHVwIGNvc3QgLSBidWlsdCBmcm9tIHlvdXIgZXhpc3RpbmcgSWxsdXN0cmF0b3IgZmlsZSJdLCJtZWRpYSI6IiIsImxpbmsiOiIifV19LHsibmFtZSI6IlJlcG9ydCBQYWwiLCJwcm9kdWN0VHlwZSI6IlNub3cgUmVwb3J0aW5nIiwiZGVzY3JpcHRpb24iOiJFYXN5IHNub3cgcmVwb3J0aW5nIGluIHRoZSBjbG91ZC4iLCJwcmljZSI6IiQzLDAwMCBVU0QgcGVyIHdpbnRlciIsImxvZ28iOnsidXJsIjoiLy9pbWFnZXMuY29udGVudGZ1bC5jb20vNnA4b2h4ZmlrYWsxLzZKcHBHZEFXektjOG1NOHNtRTh3OG0vYWU1YTVkNDM5MjgwMjc4NjlmMzI0YWFhNDZiNmY5NjgvcmVwb3J0cGFsLnN2ZyIsIm5hbWUiOiJSZXBvcnQgUGFsIExvZ28ifSwiZGV0YWlsU2VjdGlvbnMiOlt7Im5hbWUiOiJSZXBvcnQgUGFsIFN1bW1hcnkiLCJkZXNjcmlwdGlvbiI6IlRoZSBpZGVhIGJlaGluZCBSZXBvcnQgcGFsIGlzIGEgc2ltcGxlIG9uZSAtIG1vdmUgc25vdyByZXBvcnRpbmcgYXdheSBmcm9tIHlvdXIgd2Vic2l0ZSBDTVMgYW5kIGludG8gdGhlIGNsb3VkLlxuXG5JbnN0ZWFkIG9mIGNvbnRyb2xsaW5nIHlvdXIgc25vdyByZXBvcnQgZnJvbSB5b3VyIHdlYnNpdGUgKHdoaWNoIGNhbiBjaGFuZ2UgZXZlcnkgY291cGxlIG9mIHllYXJzLCByZXN1bHRpbmcgaW4gbW9yZSBjb3N0cyB0byBidWlsZCwgdGltZSByZS10cmFpbmluZyBzdGFmZiBhbmQgaGF2aW5nIHRvIHJlLWludGVncmF0ZSB3aXRoIDNyZCBwYXJ0aWVzKSwgbW92ZSBpdCBpbnRvIHRoZSBjbG91ZCBhbmQgaGF2ZSBhIGNvbnNpc3RlbnQgcGxhdGZvcm0sIHNlYXNvbiBhZnRlciBzZWFzb24uXG5cblJlcG9ydCBQYWwgbWFrZXMgdXNlIG9mIHRoZSBsYXRlc3QgdGVjaG5vbG9naWVzIG9uIG9mZmVyIGZyb20gQW1hem9uIFdlYiBTZXJ2aWNlcywgZ2l2aW5nIHlvdSBhIHJvY2sgc29saWQsIGFsd2F5cyBvbiBzbm93IHJlcG9ydGluZyBwbGF0Zm9ybSB0aGF0J3MgbGlnaHRuaW5nIGZhc3QuXG5cbkV2ZXJ5IHNraSByZXNvcnQgaXMgZGlmZmVyZW50LCBzbyBSZXBvcnQgUGFsIGhhcyBiZWVuIGJ1aWx0IGZyb20gdGhlIGdyb3VuZCB1cCBzbyB0aGF0IHdlIGNhbiBjdXN0b21pc2UgaXQgdG8gc3VpdCB5b3UuIE5vIG1vcmUgd29ya2luZyB5b3VyIHdheSBhcm91bmQgbGltaXRhdGlvbnMgb2YgeW91ciB3ZWJzaXRlIENNUywgeW91IGNhbiBpbnB1dCBhbmQgb3V0cHV0IHdoYXQgeW91IGxpa2UuXG5cbldlJ2xsIHNldHVwIHlvdXIgb3V0cHV0IGluIFtNVE4uWE1MXShodHRwOi8vbXRueG1sLm9yZyBcIk1UTi5YTUxcIikgZm9ybWF0IC0gdGhlIGluZHVzdHJ5IHN0YW5kYXJkLiBZb3VyIGRhdGEgd2lsbCBiZSBlYXNpbHkgc2hhcmVkIHdpdGggM3JkIHBhcnRpZXMuIiwibGlzdCI6IiIsIm1lZGlhIjp7ImZpbGUiOiIvL2ltYWdlcy5jb250ZW50ZnVsLmNvbS82cDhvaHhmaWthazEvMVpQeUNUWGMwOHc2VThnQzJrNlNnbS82YjViMmE3NzM5NWVjMTk2NWUwMjQ2YmY4YmU4ZTc0YS9TY3JlZW4tU2hvdC0yMDE2LTEyLTExLWF0LTQuMTguMzQtcG0ucG5nIiwid2lkdGgiOjM4NX0sImxpbmsiOiIifSx7Im5hbWUiOiJSZXBvcnQgUGFsIEluY2x1ZGVzIiwiZGVzY3JpcHRpb24iOiIiLCJsaXN0IjpbIlVubGltaXRlZCB1c2VycyIsIkludGVsbGlnZW50IHJlcG9ydCBtZXJnaW5nIiwiU2NoZWR1bGVkIHJlcG9ydHMiLCJTb2NpYWwgbWVkaWEgaW50ZWdyYXRpb24iLCJNVE4uWE1MIG91dHB1dCIsIlJlcG9ydCBoaXN0b3J5IGFuZCByb2xsYmFjayIsIkF1dG9tYXRlZCBsaWZ0ICYgdHJhaWwgb3BlbiBjb3VudHMsIGFjcmVhZ2UgYW5kIGxlbmd0aCIsIlJvY2sgc29saWQgLSBjbG91ZCBob3N0ZWQgb24gQW1hem9uIFdlYiBTZXJ2aWNlcyJdLCJtZWRpYSI6IiIsImxpbmsiOiIifV19XSwiY29tcGFueSI6eyJuYW1lIjoiUmVzb3J0cyBJbnRlcmFjdGl2ZSIsImRlc2NyaXB0aW9uIjoiUmVzb3J0cyBJbnRlcmFjdGl2ZSBoYXMgYmVlbiBtYWtpbmcgY2xvdWQgc29mdHdhcmUgZm9yIHRoZSBza2kgaW5kdXN0cnkgZm9yIHNpbmNlIDIwMDQuIFRoZSB3YXkgb3VyIHNvZnR3YXJlIGlzIGJ1aWx0IGFsbG93cyB1cyB0byBldm9sdmUgb3ZlciB0aW1lIGFuZCBlbWJyYWNlIGNoYW5naW5nIHRlY2hub2xvZ2llcyDigJMgYSBtdXN0IGhhdmUgcXVhbGl0eSBvZiBhbnkgY2xvdWQgYmFzZWQgcGFydG5lci4gT3VyIGN1cnJlbnQgc3VpdGUgb2YgUmVwb3J0IFBhbCwgdmljb01hcCBhbmQgU2VlTW9uc3RlciBjb3ZlcnMgYSBicm9hZCByYW5nZSBvZiBza2kgYXJlYSBtYXJrZXRpbmcgYW5kIG9wZXJhdGlvbnMgYW5kIGFsbG93cyB5b3UgdG8gZ2V0IGJhY2sgdG8gd2hhdOKAmXMgaW1wb3J0YW50IChsaWtlIHRha2luZyBhIGZldyBydW5zIG9uIHlvdXIgbHVuY2ggYnJlYWshKSBHZXQgaW4gdG91Y2ggdG9kYXksIHdl4oCZZCBsb3ZlIHRvIHRhbGsuIiwibG9nbyI6eyJ1cmwiOiIvL2ltYWdlcy5jb250ZW50ZnVsLmNvbS82cDhvaHhmaWthazEvNnJ2MnRCcFk1eWlFVW95SUN1MEE0Vy80YWI5MTUxMzQzNjg3ODljMTM0M2MzNDQ0MDA1ZTNhYS9yZXNvcnRzaW50ZXJhY3RpdmUuc3ZnIiwibmFtZSI6IlJlc29ydHMgSW50ZXJhY3RpdmUgTG9nbyJ9LCJjb21wYW55RGV0YWlsU2VjdGlvbnMiOlt7ImltYWdlIjoiLy9pbWFnZXMuY29udGVudGZ1bC5jb20vNnA4b2h4ZmlrYWsxLzZJbVZ6bEJYU0VpS1NlZXFnRVFrc2cvYzc0OGFmNTc0OTFmNzgwNDg0NTAzOGI0YzZhMTc3YTgvcG93ZGVyX3Nob3QuanBnIiwidGl0bGUiOiJSZXNvcnRzIEludGVyYWN0aXZlIHdlYnNpdGUiLCJib2R5IjoiIn0seyJpbWFnZSI6Ii8vaW1hZ2VzLmNvbnRlbnRmdWwuY29tLzZwOG9oeGZpa2FrMS8zeTBBYVBQTXpDR0tpdUtjTXVlYTJRL2Y1MmI1NzlkYzlhMjA4MGU0ODQ5ZWU4NzIyNjEyNGMyL1FULXdlYXRoZXJmb3JlY2FzdC1zY3JlZW4uanBnIiwidGl0bGUiOiJXaGF0IHNldHMgdXMgYXBhcnQ/IiwiYm9keSI6IlJlc29ydHMgSW50ZXJhY3RpdmUgaGFzIGJlZW4gbWFraW5nIGNsb3VkIHNvZnR3YXJlIGZvciB0aGUgc2tpIGluZHVzdHJ5IHNpbmNlIDIwMDUgc28gd2Uga25vdyBhIHRoaW5nIG9yIHR3byBhYm91dCB0aGUgc3ViamVjdCEgVGhlIHdheSBvdXIgc29mdHdhcmUgaXMgYnVpbHQgYWxsb3dzIHVzIHRvIGV2b2x2ZSBvdmVyIHRpbWUgYW5kIGVtYnJhY2UgY2hhbmdpbmcgdGVjaG5vbG9naWVzIOKAkyBhIG11c3QgaGF2ZSBxdWFsaXR5IG9mIGFueSBjbG91ZCBiYXNlZCBwYXJ0bmVyLiBPdXIgY3VycmVudCBzdWl0ZSBvZiBSZXBvcnQgUGFsLCB2aWNvTWFwIGFuZCBTZWVNb25zdGVyIGNvdmVycyBhIGJyb2FkIHJhbmdlIG9mIHNraSBhcmVhIG1hcmtldGluZyBhbmQgb3BlcmF0aW9ucyBhbmQgYWxsb3dzIHlvdSB0byBnZXQgYmFjayB0byB3aGF04oCZcyBpbXBvcnRhbnQgKGxpa2UgdGFraW5nIGEgZmV3IHJ1bnMgb24geW91ciBsdW5jaCBicmVhayEpIFtHZXQgaW4gdG91Y2ggdG9kYXksIHdl4oCZZCBsb3ZlIHRvIHRhbGsuXShtYWlsdG86aW5mb0ByZXNvcnRzLWludGVyYWN0aXZlLmNvbSkifSx7ImltYWdlIjoiLy9pbWFnZXMuY29udGVudGZ1bC5jb20vNnA4b2h4ZmlrYWsxLzRlUndkOTJnb3dvbU1LQVlPZ2djdzAvOWY4M2MyZjJiMmE3ZWFlYjEzMmE5ZGZlNjA1MDliY2EvRGV2aWNlcy5qcGciLCJ0aXRsZSI6IkNsZXZlciBTb2Z0d2FyZSBNYWtpbmcgTGlmZSBFYXN5IiwiYm9keSI6Ii0gWW91IHdvcmsgaW4gdGhlIHNraSBpbmR1c3RyeSBiZWNhdXNlIHlvdSBsb3ZlIGl0LCBzbyB3ZSBidWlsZCBzb2Z0d2FyZSB0byBzYXZlIHlvdSB0aW1lIGFuZCBnZXQgeW91IGJhY2sgb24gdGhlIGhpbGxcbi0gQ2xvdWQgYmFzZWQgc29mdHdhcmUgaXMgZGVzaWduZWQgdG8gYmUgdXNlZCBhbnl3aGVyZSDigJMgZGVza3RvcCwgbW9iaWxlLCBDb2xvcmFkbywgVGltYnVrdHUuIElmIHlvdSBjYW4gZ2V0IGFuIEludGVybmV0IGNvbm5lY3Rpb24sIHdl4oCZdmUgZ290IHlvdSBjb3ZlcmVkXG4tIFNpbXBsaWNpdHkgYW5kIHN0YWJpbGl0eSBmb3JtIGEgY29yZSBwYXJ0IG9mIG91ciBzb2Z0d2FyZSBhcmNoaXRlY3R1cmUuIE91ciBwcm9kdWN0cyBhcmUgaG9zdGVkIG9uIEFtYXpvbiBXZWIgU2VydmljZXMgYW5kIG1ha2UgdXNlIG9mIHRoZWlyIGJlc3QgYW5kIGxhdGVzdCB0ZWNobm9sb2dpZXMgbGlrZSBDbG91ZEZyb250LCBBdXJvcmEsIGFuZCBFbGFzdGljIEJlYW5zdGFsayB0byBtYWtlIHN1cmUgd2XigJlyZSBhbHdheXMgZmFzdCBhbmQgYXZhaWxhYmxlXG4tIEluY2x1ZGUgbGl2ZSBkYXRhIGFuZCBpbWFnZXMgZnJvbSBzb2NpYWwgbWVkaWEsIHdlYXRoZXIsIG5ld3MgYW5kIG90aGVyIHdlYnNpdGVzXG4tIFVwbG9hZCB2aWRlbyBpbiBhbnkgZm9ybWF0IGFuZCBpdOKAmWxsIGJlIGNvbnZlcnRlZCBmb3IgeW91In1dLCJpY29uIjp7InN5cyI6eyJzcGFjZSI6eyJzeXMiOnsidHlwZSI6IkxpbmsiLCJsaW5rVHlwZSI6IlNwYWNlIiwiaWQiOiI2cDhvaHhmaWthazEifX0sImlkIjoia21HMFgzZkZRY0VzZWltY2VVa0lzIiwidHlwZSI6IkFzc2V0IiwiY3JlYXRlZEF0IjoiMjAxNy0wNi0xOFQxMDoyNDo1NC41ODBaIiwidXBkYXRlZEF0IjoiMjAxNy0wNi0xOFQxMDoyNDo1NC41ODBaIiwicmV2aXNpb24iOjEsImxvY2FsZSI6ImVuLU5aIn0sImZpZWxkcyI6eyJ0aXRsZSI6IlNlbWktZmxha2UtcG5nIiwiZGVzY3JpcHRpb24iOiJQTkcgdmVyc2lvbiBvZiBzZW1pLWZsYWtlIiwiZmlsZSI6eyJ1cmwiOiIvL2ltYWdlcy5jb250ZW50ZnVsLmNvbS82cDhvaHhmaWthazEva21HMFgzZkZRY0VzZWltY2VVa0lzLzk0M2MwNDc5MWEyZDQ0MmYxZjUwODAyYTM4NjhlMjllL3NlbWlmbGFrZS5wbmciLCJkZXRhaWxzIjp7InNpemUiOjI0MTkwLCJpbWFnZSI6eyJ3aWR0aCI6NTEyLCJoZWlnaHQiOjUxMn19LCJmaWxlTmFtZSI6InNlbWlmbGFrZS5wbmciLCJjb250ZW50VHlwZSI6ImltYWdlL3BuZyJ9fX19fQ=='
)
let halfcabModule = await import('./halfcab')
;({ssr, html, defineRoute, gotoRoute, formField, cache, updateState, injectMarkdown, formIsValid, emptyBody, css, state, getRouteComponent} = halfcabModule)
halfcab = halfcabModule.default
})
describe('Server', () => {
it('Produces a string when doing SSR', () => {
let style = css`
.myStyle {
width: 100px;
}
`
let {componentsString, stylesString} = ssr(serverHtml`
<div class="${style.myStyle}" oninput=${() => {}}></div>
`)
expect(typeof componentsString === 'string').to.be.true()
})
})
describe('Client', () => {
it('has initial data with router property to be available', async () => {
expect(state.router).to.exist()
})
it('Produces an HTML element when rendering', () => {
let el = html`
<div oninput=${() => {}}></div>
`
expect(el instanceof HTMLDivElement).to.be.true()
})
it('Produces an HTML element wrapping as a reusable component', () => {
let el = cache(() => html`
<div oninput=${() => {}}></div>
`, {})
expect(el instanceof HTMLDivElement).to.be.true()
})
it('Runs halfcab function without error', () => {
return halfcab({
el: '#root',
baseName: 'Resorts Interactive',
baseApiPath: '/api/webroutes',
components () {
return html `<div></div>`
}
})
.then(rootEl => {
expect(typeof rootEl === 'object').to.be.true()
})
})
it('updating state causes a rerender with state', () => {
return halfcab({
baseName: 'Resorts Interactive',
baseApiPath: '/api/webroutes',
components (args) {
return html`<div>${args.testing || ''}</div>`
}
})
.then(rootEl => {
updateState({testing: 'works'})
expect(rootEl.innerHTML.includes('works')).to.be.true()
})
})
it('updates state without merging arrays when told to', () => {
updateState({
myArray: ['1', '2', '3']
})
updateState({
myArray: ['4']
}, {
arrayMerge: false
})
expect(state.myArray.length).to.equal(1)
})
it('updating state without deepmerge overwrites objects', () => {
var style = css`
.myStyle {
width: 100px;
}
`
return halfcab({
baseName: 'Resorts Interactive',
baseApiPath: '/api/webroutes',
components (args) {
return html `<div class="${style.myStyle}">${args.testing.inner || ''}</div>`
}
})
.then(rootEl => {
updateState({testing: {inner: 'works'}})
updateState({testing: {inner2: 'works'}}, {
deepMerge: false
})
expect(rootEl.innerHTML.indexOf('works')).to.equal(-1)
})
})
it('injects external content without error', () => {
return halfcab({
baseName: 'Resorts Interactive',
baseApiPath: '/api/webroutes',
components (args) {
return html `<div>${injectMarkdown('### Heading')}</div>`
}
})
.then(rootEl => {
emptyBody()
expect(rootEl.innerHTML.indexOf('###')).to.equal(-1)
expect(rootEl.innerHTML.indexOf('<h3')).not.to.equal(-1)
})
})
it('injects markdown without wrapper without error', () => {
return halfcab({
baseName: 'Resorts Interactive',
baseApiPath: '/api/webroutes',
components (args) {
return html `<div>${injectMarkdown('### Heading', {wrapper: false})}</div>`
}
})
.then(rootEl => {
emptyBody()
expect(rootEl.innerHTML.indexOf('###')).to.equal(-1)
expect(rootEl.innerHTML.indexOf('<h3')).not.to.equal(-1)
})
})
describe('formField', () => {
it('Returns a function', () => {
var holdingPen = {}
var output = formField(holdingPen, 'test')
expect(typeof output === 'function').to.be.true()
})
it('Sets a property within the valid object of the same name', () => {
var holdingPen = {}
var output = formField(holdingPen, 'test')
var e = {
currentTarget: {
type: 'text',
validity: {
valid: false
}
}
}
output(e)
expect(holdingPen.valid.test).to.exist()
})
it('Runs OK if a valid object is already present', () => {
var holdingPen = {valid: {}}
var output = formField(holdingPen, 'test')
var e = {
currentTarget: {
type: 'text',
validity: {
valid: false
}
}
}
output(e)
expect(holdingPen.valid.test).to.exist()
})
it('Sets checkboxes without error', () => {
var holdingPen = {}
var output = formField(holdingPen, 'test')
var e = {
currentTarget: {
type: 'checkbox',
validity: {
valid: false
},
checked: true
}
}
output(e)
expect(holdingPen.valid.test).to.exist()
})
it('Sets radio buttons without error', () => {
var holdingPen = {}
var output = formField(holdingPen, 'test')
var e = {
currentTarget: {
type: 'radio',
validity: {
valid: false
},
checked: true
}
}
output(e)
expect(holdingPen.valid.test).to.exist()
})
it('Validates a form without error', () => {
var holdingPen = {
test: '',
[Symbol('valid')]: {
test: false
}
}
var output = formField(holdingPen, 'test')
var e = {
currentTarget: {
type: 'radio',
validity: {
valid: true
},
checked: true
}
}
output(e)
expect(formIsValid(holdingPen)).to.be.true()
})
it('Validates when valid object already present', () => {
var holdingPen = {
test: '',
[Symbol('valid')]: {
test: false
},
valid: {}
}
var output = formField(holdingPen, 'test')
var e = {
currentTarget: {
type: 'radio',
validity: {
valid: true
},
checked: true
}
}
output(e)
expect(formIsValid(holdingPen)).to.be.true()
})
})
describe('routing', () => {
let windowStub
after(() => {
windowStub.restore()
})
before(() => {
windowStub = sinon.stub(window.history, 'pushState')
})
it('Makes the route available when using defineRoute', () => {
defineRoute({
path: '/testFakeRoute', title: 'Report Pal', callback: output => {
updateState({
showContact: true
})
}
})
return halfcab({
baseName: 'Resorts Interactive',
components () {
return html `<div></div>`
}
})
.then(rootEl => {
let routing = () => {
gotoRoute('/testFakeRoute')
}
expect(routing).to.not.throw()//made it out of the try catch, must be fine
})
})
it(`Throws an error when a route doesn't exist`, () => {
return halfcab({
baseName: 'Resorts Interactive',
components () {
return html `<div></div>`
}
})
.then(rootEl => {
let routing = () => {
gotoRoute('/thisIsAFakeRoute')
}
expect(routing).to.throw()//made it out of the try catch, must be fine
})
})
it(`postUpdate is called after an update`, async () => {
let postUpdate = sinon.spy()
let hc = halfcab({
baseName: 'Resorts Interactive',
components () {
return html `<div></div>`
},
postUpdate
})
updateState({
nothing: 'something'
})
expect(postUpdate).to.have.been.calledOnce()
})
})
it('has initial data injects router when its not there to start with', () => {
defineRoute({path: '/routeWithComponent', component: {fakeComponent: true}})
expect(getRouteComponent('/routeWithComponent').fakeComponent).to.be.true()
})
})
})