UNPKG

impera-js

Version:

Tiny, Proxy based App State Managment for custom-elements

258 lines (204 loc) 10.1 kB
import {statesMixin, StateVariable, StateTransition, Message, litStatesMixin} from "../build/impera.js" import {LitElement, html} from 'https://unpkg.com/lit-element?module'; export default function(){ localStorage.clear(); describe('State Mixin',()=>{ let c_tr =0; let c_n =0; let c_s =0; let c_obj =0; let b_tr =0; let b_n =0; let b_s =0; let b_obj =0; let message2 = ""; let message = ""; var sv_n = new StateVariable("num", 7); var sv_s = new StateVariable("str", "ciao"); var sv_obj = new StateVariable("obj", {ciao:"bella", hey:[1,2,3]}); sv_n.addTransition("SubTransition",()=>{ sv_n.value = 78; }) sv_n.allowStandaloneAssign = true; var st_count = new StateTransition("count"); st_count.usrDefined_transition = (input)=>{ if(input) c_tr = input.val; else c_tr++; }; it('Init: initialize wc correctly with all property',()=>{ let obj = {bellapete:42}; sv_n.attachWatcher(obj,()=>{c_n++;}); sv_s.attachWatcher(obj,()=>{c_s++;}); sv_obj.attachWatcher(obj,()=>{c_obj++;}); var m_me = new Message("mess"); m_me.attachWatcher(obj,(input)=>{message = input.message;}); var lista = [sv_n,sv_s,sv_obj,st_count,m_me]; customElements.define("t-uno", class t1 extends statesMixin(lista, HTMLElement){ on_num_update(){ b_n++; } on_obj_update(){b_obj++;} on_str_update(){b_s++;} on_count(){b_tr++} gotMessage_mess(input){message2 = input.message;} } ); var ist = document.createElement('t-uno'); document.ist =ist; chai.assert.equal(ist.num, 7, "State var properties"); chai.assert.equal(ist.str, "ciao", "State var properties"); chai.assert.deepEqual(ist.obj,{ciao:"bella", hey:[1,2,3]} , "State var properties"); chai.assert.hasAllKeys(ist._transitionMap, ["count", "SubTransition"], "maps"); chai.assert.hasAllKeys(ist._messageMap, ["mess"], "maps"); chai.assert.typeOf(ist.applyTransition, "function"); chai.assert.typeOf(ist.sendMessageOnChannel, "function"); chai.assert.containsAllKeys(sv_n.callbackMap, [obj]); chai.assert.equal(sv_n.callbackMap.size, 1); }); it('State modification trough transition and proxy variable works',()=>{ var ist = document.createElement('t-uno'); ist.applyTransition("count"); chai.assert.equal(c_tr ,1, "transition "); ist.applyTransition("count",{val:7}); chai.assert.equal(c_tr ,7, "transition "); chai.assert.equal(b_tr ,0, "transition not connected shouldnot run"); let func = ()=>{ ist.num = 23 }; let func2 = ()=>{ ist.obj = {hey:"dude"}; }; let func3 = ()=>{ ist.str = "po"; }; let func4 = ()=>{ let t = ist.obj.hey ; t.push(6); }; chai.assert.Throw(func, "num cannot be assigned from a custom element"); chai.assert.Throw(func2, "obj cannot be assigned from a custom element"); chai.assert.Throw(func3, "str cannot be assigned from a custom element"); chai.assert.deepEqual(ist.obj,{ciao:"bella", hey:[1,2,3]} , "xcheck"); chai.assert.Throw(func4, "obj cannot be assigned from a custom element"); ist.sendMessageOnChannel("mess",{message:"ciao"}); chai.assert.equal(message,"ciao", "message is sent"); chai.assert.equal(message2,"", "not connected mesage call back should not run"); }); it('On connection sets the watchers',()=>{ c_tr =0; c_n =0; c_s =0; c_obj =0; b_tr =0; b_n =0; b_s =0; b_obj =0; message2 = ""; message = ""; var ist = document.createElement('t-uno'); document.body.appendChild(ist); ist.applyTransition("count"); chai.assert.equal(c_tr ,1, "transition fake"); chai.assert.equal(b_tr ,1, "transition "); ist.applyTransition("count",{val:7}); chai.assert.equal(c_tr ,7, "transition fake2"); // it is two because if it is stateVariable on attachment needs to run the side effects of element chai.assert.equal(b_tr ,2, "transition "); sv_n.value = 23; chai.assert.equal(c_n ,1, "var num fake watcher"); // it is two because if it is stateVariable on attachment needs to run the side effects of element chai.assert.equal(b_n ,2, "var num: "); sv_s.value = "po"; chai.assert.equal(c_s ,1, "var str fake watcher"); // it is two because if it is stateVariable on attachment needs to run the side effects of element chai.assert.equal(b_s ,2, "var str"); sv_obj.value = {hey:"dude"}; chai.assert.equal(c_obj ,1, "var obj fake watcher"); // it is two because if it is stateVariable on attachment needs to run the side effects of element chai.assert.equal(b_obj ,2, "var obj "); ist.sendMessageOnChannel("mess",{message:"ciao"}); chai.assert.equal(message,"ciao", "message is sent"); chai.assert.equal(message2,"ciao", "message"); }); it('Disconnects',()=>{ c_tr =0; c_n =0; c_s =0; c_obj =0; b_tr =0; b_n =0; b_s =0; b_obj =0; message2 = ""; message = ""; let ist = document.body.querySelector("t-uno"); document.body.removeChild(ist); ist.applyTransition("count"); chai.assert.equal(c_tr ,1, "transition fake"); chai.assert.equal(b_tr ,0, "transition "); ist.applyTransition("count",{val:7}); chai.assert.equal(c_tr ,7, "transition fake2"); chai.assert.equal(b_tr ,0, "transition "); sv_n.value = 28; chai.assert.equal(c_n ,1, "var num fake watcher"); chai.assert.equal(b_n ,0, "var num: "); sv_s.value = "poi"; chai.assert.equal(c_s ,1, "var str fake watcher"); chai.assert.equal(b_s ,0, "var str"); sv_obj.value = {hey:"dudo"}; chai.assert.equal(c_obj ,1, "var obj fake watcher"); chai.assert.equal(b_obj ,0, "var obj "); ist.sendMessageOnChannel("mess",{message:"ciao"}); chai.assert.equal(message,"ciao", "message is sent"); chai.assert.equal(message2,"", "message"); }); describe('LitElement Mixin',()=>{ var lista = [sv_n]; it('Does a render update',async function(){ sv_n.value = 1 let lit_counter = 0; class MyFoo extends litStatesMixin(lista,LitElement) { render() { return html` <div id="num"> This is Lit element ${this.num}</div> `; } on_num_update(){ lit_counter++; } } customElements.define('my-foo', MyFoo); let lit = document.createElement('my-foo'); document.body.appendChild(lit); let update = await lit.updateComplete let div0 = lit.shadowRoot.querySelector("#num") chai.assert.equal(div0.innerText, "This is Lit element 1","lit element gets initialized correctly") //chai.assert.equal(lit_counter, 1,"counter change"); sv_n.value = 6 update = await lit.updateComplete div0 = lit.shadowRoot.querySelector("#num") chai.assert.equal(div0.innerText, "This is Lit element 6","lit element gets modified correctly") chai.assert.equal(lit_counter, 1,"counter change "); sv_n.applyTransition("SubTransition") update = await lit.updateComplete div0 = lit.shadowRoot.querySelector("#num") chai.assert.equal(div0.innerText, "This is Lit element 78","lit element respond to transitions") chai.assert.equal(lit_counter, 2,"counter does not change"); document.body.removeChild(lit); }); }); describe('Performance',()=>{ it('Update of a 1000 element takes < 200mus',()=>{ let n_cycles = 1000; let n_elements = 1000; st_count.usrDefined_transition = (input)=>{ if(input) c_tr = input.val; else c_tr++; sv_n.value = c_tr; }; for(let i=0; i < n_elements; i++){ let tmp = document.createElement('t-uno'); document.body.appendChild(tmp); } let motherfucker = document.createElement('t-uno'); b_n = 0; let start = performance.now(); for(let i=0; i < n_cycles; i++){ motherfucker.applyTransition("count",{val:i}); } let time_avg = (performance.now() - start) / n_cycles; console.log("Performance time per cycle in mus: ", time_avg * 1000); chai.assert.isBelow(time_avg * 1000 , 200, "take too much time"); chai.assert.equal(b_n, n_cycles*n_elements, "something fishy :***"); }); }); }); }