UNPKG

23 kBHTMLView Raw
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <meta http-equiv="X-UA-Compatible" content="ie=edge">
7 <title>Document</title>
8 <link href="https://unpkg.com/mocha@4.0.1/mocha.css" rel="stylesheet" />
9 <link rel="stylesheet" href="/test/styles.css">
10 <link rel="icon" type="image/png" href="/resources/favicon-16x16.png" sizes="16x16" />
11 <link rel="icon" type="image/png" href="/resources/favicon-32x32.png" sizes="32x32" />
12</head>
13<body>
14 <nav onclick="location.pathname='/test/index.html'">
15 <h1>Mocha Tests - Composi Component Class</h1>
16 </nav>
17 <section>
18 <div id="mocha"></div>
19 <div id="messages"></div>
20 <div id="fixtures"></div>
21 <div id="hide-tests">
22 <div id='h1-test'></div>
23 <div id="list1-test"></div>
24 <div id="list2-test"></div>
25 <div id="list3-test"></div>
26 <div id="dangerous-test"></div>
27 <div id="boolean-props"></div>
28 </div>
29 </section>
30
31 <script src='/dist/composi.js'></script>
32 <script src="https://unpkg.com/mocha@4.0.1/mocha.js"></script>
33 <script src="https://unpkg.com/chai@4.1.2/chai.js"></script>
34 <script>mocha.setup('bdd')</script>
35 <script>
36
37 const {h, Component} = composi
38 const should = chai.should()
39 const expect = chai.expect
40
41 describe('Create Component Instance', function() {
42 let componentDidMount = false;
43 const h1 = new Component({
44 render: data => h('h1', {style: {backgroundColor: '#000', color: '#fff'}}, `Hello, ${data}!`),
45 container: '#h1-test',
46 componentDidMount: () => {componentDidMount = true}
47 })
48 h1.update('World')
49 const h1El = document.querySelector('#h1-test h1')
50
51 it('Component container should be "#h1-test"', function() {
52 expect(h1.container.id).to.equal('h1-test')
53 })
54 it('Component element should exist', function() {
55 should.exist(h1.element)
56 })
57 it('Component element should be "h1"', function() {
58 expect(h1.element.nodeName).to.equal('H1')
59 })
60 it("Component render function should be \"data => h('h1', {style: {backgroundColor: '#000', color: '#fff'}}, `Hello, ${data}!`)\"", function() {
61 expect(h1.render.toString()).to.equal("data => h('h1', {style: {backgroundColor: '#000', color: '#fff'}}, `Hello, ${data}!`)")
62 })
63 it('Component lifecycle method "componentDidMount" should have run', function() {
64 expect(componentDidMount).to.equal(true)
65 })
66 it('Element created by component should be "h1"', function() {
67 expect(h1El.nodeName).to.equal('H1')
68 })
69 it('H1 element content should be "Hello, World!"', function() {
70 expect(h1El.textContent.trim()).to.equal('Hello, World!')
71 })
72 it('H1 element background color should be "#000"', function() {
73 expect(h1El.style.backgroundColor).to.equal('rgb(0, 0, 0)')
74 })
75 it('H1 element color should be "#fff"', function() {
76 expect(h1El.style.color).to.equal('rgb(255, 255, 255)')
77 })
78 it('Running update method on component with new data, H1 content should be "Hello, Joe Bodoni!"', function(done) {
79 setTimeout(function() {
80 h1.update('Joe Bodoni')
81 expect(h1El.textContent.trim()).to.equal('Hello, Joe Bodoni!')
82 },1000)
83 done()
84 })
85 })
86
87 describe('Create Extended Component without State', function() {
88 let componentDidMount = false;
89 class List extends Component {
90 render(data) {
91 return h('ul', {class:'list'},
92 data.map(item => h('li', {}, item))
93 )
94 }
95 componentDidMount() {
96 componentDidMount = true
97 }
98 }
99 const list = new List({
100 container: '#list1-test'
101 })
102 window.list = list
103 list.update(['Apples', 'Oranges', 'Bananas'])
104
105 it('Component isMounted property should be true', function() {
106 expect(list.isMounted).to.equal(true)
107 })
108 it('Component lifecycle method "componentDidMount" should have run', function() {
109 expect(componentDidMount).to.equal(true)
110 })
111 it('Component container should be "#list1-test"', function() {
112 expect(list.container.id).to.equal('list1-test')
113 })
114 it('Component element should be "ul"', function() {
115 expect(list.element.nodeName).to.equal('UL')
116 })
117 it('Component selector should be "#list1-test"', function() {
118 expect(list.selector).to.equal('#list1-test')
119 })
120 it('Component should have no state', function() {
121 expect(list.state).to.equal(undefined)
122 })
123 let listEl = document.querySelector('#list1-test ul')
124 it('Element created by component should be "ul"', function() {
125 expect(listEl.nodeName).to.equal('UL')
126 })
127 it('Element should have class of "list"', function() {
128 expect(listEl.className).to.equal('list')
129 })
130 it('Element should have three childen', function() {
131 expect(listEl.children).to.have.lengthOf(3)
132 })
133 it('First list item should contain "Apples"', function() {
134 expect(listEl.children[0].textContent.trim()).to.equal('Apples')
135 })
136 it('Last list item should contain "Bananas"', function() {
137 expect(listEl.children[2].textContent.trim()).to.equal('Bananas')
138 })
139 it('On update, list should have four children', function(done) {
140 setTimeout(function() {
141 list.update(['Apples', 'Oranges', 'Bananas', 'Grapes'])
142 expect(listEl.children).to.have.lengthOf(4)
143 }, 1000)
144 done()
145 })
146 it('On update, last list item should contain "Grapes"', function(done) {
147 setTimeout(function() {
148 expect(listEl.children[3].textContent.trim()).to.equal('Grapes')
149 }, 1000)
150 done()
151 })
152 it('On unmount, list should be removed from DOM', function(done) {
153 setTimeout(function() {
154 list.unmount()
155 const container = document.querySelector('#list1-test')
156 listEl = document.querySelector('#list1-test ul')
157 should.not.exist(listEl)
158 expect(container.children).to.have.lengthOf(0)
159 }, 1000)
160 done()
161 })
162 })
163
164 describe('Create Extended Component with State', function() {
165 let componentWillMount = false
166 let componentDidMount = false
167 let componentWillUpdate = false
168 let componentDidUpdate = false
169 let componentWillUnmount = false
170 const veggies = ['Potatoes', 'Tomatoes', 'Carrots', 'Peas']
171 class List extends Component {
172 constructor(props) {
173 super(props)
174 this.container = '#list2-test'
175 this.state = veggies
176 }
177 render(data) {
178 return h('ul', {class:'list'},
179 data.map(item => h('li', {title:item}, item))
180 )
181 }
182 componentWillMount(done) {
183 componentWillMount = true
184 done()
185 }
186 componentDidMount() {
187 componentDidMount = true
188 }
189 componentWillUpdate(done) {
190 componentWillUpdate = true
191 done()
192 }
193 componentDidUpdate() {
194 componentDidUpdate = true
195 }
196 componentWillUnmount(done) {
197 componentWillUnmount = true
198 done()
199 }
200 }
201 const list2 = new List()
202 window.list2 = list2
203 let listEl
204 setTimeout(() => {
205 listEl = document.querySelector('#list2-test ul')
206 }, 100)
207
208 it('Component lifecycle method "componentWillMount" should run before component is created', function(done) {
209 setTimeout(() => {
210 expect(componentWillMount).to.equal(true)
211 }, 100)
212 done()
213 })
214 it('Component should mount when instantiated because it has state', function() {
215 const listEl = document.querySelector('#list1-test ul')
216 should.exist(listEl)
217 })
218 it('Component lifecycle method "componentDidMount" should have run', function(done) {
219 setTimeout(function() {
220 expect(componentDidMount).to.equal(true)
221 }, 100)
222 done()
223 })
224 it('Component isMounted property should be true', function(done) {
225 setTimeout(() => {
226 expect(list2.isMounted).to.equal(true)
227 }, 100)
228 done()
229 })
230 it('Component container should be "#list2-test"', function(done) {
231 setTimeout(function() {
232 expect(list2.container.id).to.equal('list2-test')
233 }, 100)
234 done()
235 })
236 it('Component element should be "ul"', function(done) {
237 setTimeout(function() {
238 expect(list2.element.nodeName).to.equal('UL')
239 }, 100)
240 done()
241 })
242 it('Component selector should be "#list2-test"', function(done) {
243 setTimeout(function() {
244 expect(list2.selector).to.equal('#list2-test')
245 }, 100)
246 done()
247 })
248 it('Component should have state', function(done) {
249 setTimeout(function() {
250 should.exist(list2.state)
251 }, 100)
252 done()
253 })
254 it('Component state show have 4 items', function(done) {
255 setTimeout(function() {
256 expect(list2.state).to.have.lengthOf(4)
257 }, 100)
258 done()
259 })
260 it('Component state should equal "Potatoes Tomatoes Carrots Peas"', function(done) {
261 setTimeout(function() {
262 expect(list2.state.join(' ')).to.equal("Potatoes Tomatoes Carrots Peas")
263 }, 100)
264 done()
265 })
266 it('Element created by component should be "ul"', function(done) {
267 setTimeout(function() {
268 expect(listEl.nodeName).to.equal('UL')
269 }, 100)
270 done()
271 })
272 it('Element should have class of "list"', function(done) {
273 setTimeout(function() {
274 expect(listEl.className).to.equal('list')
275 }, 100)
276 done()
277 })
278 it('Element should have three childen', function(done) {
279 setTimeout(function() {
280 expect(listEl.children).to.have.lengthOf(4)
281 }, 100)
282 done()
283 })
284 it('First list item should contain "Potatoes"', function(done) {
285 setTimeout(function() {
286 expect(listEl.children[0].textContent.trim()).to.equal('Potatoes')
287 }, 100)
288 done()
289 })
290 it('Last list item should contain "Peas"', function(done) {
291 setTimeout(function() {
292 expect(listEl.children[3].textContent.trim()).to.equal('Peas')
293 }, 100)
294 done()
295 })
296 it('List items should have title attribute', function(done) {
297 setTimeout(function() {
298 const items = Array.prototype.slice.apply(listEl.children)
299 items.map((item, idx) => {
300 should.exist(item.title)
301 expect(item.title).to.equal(veggies[idx])
302 })
303 }, 100)
304 done()
305 })
306
307
308 it('After setting state, list should have four children', function(done) {
309 setTimeout(function() {
310 list2.setState(prevState => {
311 prevState.push('Onions')
312 return prevState
313 })
314 }, 300)
315 setTimeout(() => {
316 expect(listEl.children).to.have.lengthOf(5)
317 }, 500)
318 done()
319 })
320
321 it('After setting state, last list item should contain "Onions"', function(done) {
322 setTimeout(function() {
323 expect(listEl.children[4].textContent.trim()).to.equal('Onions')
324 }, 600)
325 done()
326 })
327
328 it('When setting state, original state should remain immutable.', function(done) {
329 setTimeout(function() {
330 // prevState should be a copy of the component's state.
331 // That means changes to it should not affect the component's state.
332 // Here we do not return prevState, preventing it from updating original state with changes.
333 let newState = []
334 list2.setState(prevState => {
335 prevState.push('new stuff')
336 newState = prevState
337 })
338 // Since we never returned prevState above, the component's original state should remain unchanged:
339 expect(JSON.stringify(list2.state)).to.equal(JSON.stringify(['Potatoes', 'Tomatoes', 'Carrots', 'Peas', 'Onions']))
340 // But the changes to prevState should be as follows:
341 expect(JSON.stringify(newState)).to.equal(JSON.stringify(['Potatoes', 'Tomatoes', 'Carrots', 'Peas', 'Onions', 'new stuff']))
342 }, 600)
343 done()
344 })
345
346
347 it('Component lifecycle methods "componentWillUpdate" and "componentDidUpdate" should run when component state is updated', function(done) {
348 setTimeout(function(){
349 list2.setState(prevState => {
350 prevState.push('Lettuce')
351 return prevState
352 })
353 setTimeout(() => {
354 expect(componentWillUpdate).to.equal(true)
355 expect(componentDidUpdate).to.equal(true)
356 expect(list2.state[5]).to.equal('Lettuce')
357 }, 1000)
358 }, 1100)
359 done()
360 })
361
362 it('On unmount, "componentWillUnmount" lifecyle method should run and list should be removed from DOM', function(done) {
363 setTimeout(function() {
364 // list2.unmount()
365 // const container = document.querySelector('#list1-test')
366 // listEl = document.querySelector('#list2-test ul')
367 // expect(componentWillUnmount).to.equal(true)
368 // should.not.exist(listEl)
369 // expect(container.children).to.have.lengthOf(0)
370 }, 3000)
371 done()
372 })
373
374 })
375
376 describe('Use property innerHTML on element to set props using innerHTML without encoding.', function() {
377
378 class Div extends Component {
379 constructor(props) {
380 super(props)
381 this.container = '#dangerous-test'
382 this.state = true
383 }
384 render(data) {
385 return h(
386 'div',
387 {innerHTML: '<div id="dangerous-div">This was set with innerHTML!</div>'}
388 )
389 }
390 componentDidMount() {
391 console.log(this.element.children[0].id)
392 }
393 }
394 const testDiv = new Div()
395
396 it('Test div should have one child', function(done) {
397 setTimeout(() => {
398 expect(testDiv.element.children.length).to.equal(1)
399 }, 100)
400 done()
401 })
402 it('Test div child should have id of "dangerous-div"', function(done) {
403 setTimeout(() => {
404 expect(testDiv.element.children[0].id).to.equal('dangerous-div')
405 }, 100)
406 done()
407 })
408 it('Test div child should have content of "This was set with innerHTML!"', function(done) {
409 setTimeout(() => {
410 expect(testDiv.element.children[0].textContent.trim()).to.equal('This was set with innerHTML!')
411 }, 100)
412 done()
413 })
414 })
415
416 describe('Set properties with boolean values', function() {
417 // #boolean-props
418 class BooleanPropsTest extends Component {
419 render() {
420 return (
421 h('div',
422 {},
423 [
424 h('p', {}, [h('button', {id: 'btn-1', disabled: false})], 'button'),
425 h('p', {}, [h('button', {id: 'btn-2', disabled: 'false'})], 'button'),
426 h('p', {}, [h('button', {id: 'btn-3', disabled: true})], 'button'),
427 h('p', {}, [h('button', {id: 'btn-4', disabled: 'true'})], 'button'),
428 h('p', {}, [h('button', {id: 'btn-5', disabled: 1})], 'button'),
429 h('p', {}, [h('button', {id: 'btn-6', disabled: '1'})], 'button'),
430 h('p', {}, [h('button', {id: 'btn-7', disabled: -1})], 'button'),
431 h('p', {}, [h('button', {id: 'btn-8', disabled: '-1'})], 'button'),
432 h('p', {}, [h('button', {id: 'btn-9', disabled: 0})], 'button'),
433 h('p', {}, [h('button', {id: 'btn-10', disabled: '0'})], 'button'),
434 h('p', {}, [h('button', {id: 'btn-11', disabled: null})], 'button'),
435 h('p', {}, [h('button', {id: 'btn-12', disabled: 'null'})], 'button'),
436 h('p', {}, [h('button', {id: 'btn-13', disabled: undefined})], 'button'),
437 h('p', {}, [h('button', {id: 'btn-14', disabled: 'undefined'})], 'button'),
438
439 h('p', {class: 'boolean-test', translate: true}, 'translate'),
440 h('p', {class: 'boolean-test', translate: 'true'}, 'translate'),
441 h('p', {class: 'boolean-test', translate: 'yes'}, 'translate'),
442 h('p', {class: 'boolean-test', translate: false}, 'translate'),
443 h('p', {class: 'boolean-test', translate: 'false'}, 'translate'),
444 h('p', {class: 'boolean-test', translate: 'no'}, 'translate'),
445
446 h('p', {}, [h('input', {class: 'input', autocomplete: 'on'})]),
447 h('p', {}, [h('input', {class: 'input', autocomplete: 'off'})])
448 ])
449 )
450 }
451 componentDidMount() {
452 this.buttons = this.element.querySelectorAll('button')
453 this.booleanTests = this.element.querySelectorAll('.boolean-test')
454 this.inputTests = this.element.querySelectorAll('.input')
455 }
456 }
457 let buttons
458 const booleanPropsTest = new BooleanPropsTest({
459 container: '#boolean-props',
460 state: true
461 })
462 window.booleanPropsTest = booleanPropsTest
463
464 // Disabled tests:
465 it('Button set to "disabled={false}" should not be disabled', function(done) {
466 setTimeout(() => {
467 const prop = booleanPropsTest.buttons[0].disabled
468 expect(prop).to.be.false
469 }, 1000)
470 done()
471 })
472
473 it('Button set to "disabled=\"false\" should be disabled', function(done) {
474 setTimeout(() => {
475 const prop = booleanPropsTest.buttons[1].disabled
476 expect(prop).to.be.true
477 }, 1000)
478 done()
479 })
480
481 it('Button set to "disabled={true}" should be disabled', function(done) {
482 setTimeout(() => {
483 const prop = booleanPropsTest.buttons[2].disabled
484 expect(prop).to.be.true
485 }, 1000)
486 done()
487 })
488
489 it('Button set to "disabled=\"true\" should be disabled', function(done) {
490 setTimeout(() => {
491 const prop = booleanPropsTest.buttons[3].disabled
492 expect(prop).to.be.true
493 }, 1000)
494 done()
495 })
496 it('Button set to "disabled={1} should be disabled', function(done) {
497 setTimeout(() => {
498 const prop = booleanPropsTest.buttons[4].disabled
499 expect(prop).to.be.true
500 }, 1000)
501 done()
502 })
503 it('Button set to "disabled=\"1\" should be disabled', function(done) {
504 setTimeout(() => {
505 const prop = booleanPropsTest.buttons[5].disabled
506 expect(prop).to.be.true
507 }, 1000)
508 done()
509 })
510 it('Button set to "disabled={-1} should be disabled', function(done) {
511 setTimeout(() => {
512 const prop = booleanPropsTest.buttons[6].disabled
513 expect(prop).to.be.true
514 }, 1000)
515 done()
516 })
517 it('Button set to "disabled=\"-1\" should be disabled', function(done) {
518 setTimeout(() => {
519 const prop = booleanPropsTest.buttons[7].disabled
520 expect(prop).to.be.true
521 }, 1000)
522 done()
523 })
524 it('Button set to "disabled={0} should not be disabled', function(done) {
525 setTimeout(() => {
526 const prop = booleanPropsTest.buttons[8].disabled
527 expect(prop).to.be.false
528 }, 1000)
529 done()
530 })
531 it('Button set to "disabled=\"0\" should be disabled', function(done) {
532 setTimeout(() => {
533 const prop = booleanPropsTest.buttons[9].disabled
534 expect(prop).to.be.true
535 }, 1200)
536 done()
537 })
538 it('Button set to "disabled={null} should not be disabled', function(done) {
539 setTimeout(() => {
540 const prop = booleanPropsTest.buttons[10].disabled
541 expect(prop).to.be.false
542 }, 1200)
543 done()
544 })
545 it('Button set to "disabled=\"null\" should be disabled', function(done) {
546 setTimeout(() => {
547 const prop = booleanPropsTest.buttons[11].disabled
548 expect(prop).to.be.true
549 }, 1200)
550 done()
551 })
552 it('Button set to "disabled={undefined} should not be disabled', function(done) {
553 setTimeout(() => {
554 const prop = booleanPropsTest.buttons[12].disabled
555 expect(prop).to.be.false
556 }, 1200)
557 done()
558 })
559 it('Button set to "disabled=\"undefined\" should be disabled', function(done) {
560 setTimeout(() => {
561 const prop = booleanPropsTest.buttons[13].disabled
562 expect(prop).to.be.true
563 }, 1200)
564 done()
565 })
566
567 // Translate tests:
568 it('Paragraph set to "translate={true} should be true', function(done) {
569 setTimeout(() => {
570 const prop = booleanPropsTest.booleanTests[0].translate
571 expect(prop).to.be.true
572 }, 1000)
573 done()
574 })
575 it('Paragraph set to "translate=\"true\" should be true', function(done) {
576 setTimeout(() => {
577 const prop = booleanPropsTest.booleanTests[1].translate
578 expect(prop).to.be.true
579 }, 1000)
580 done()
581 })
582 it('Paragraph set to "translate=\"yes\" should be true', function(done) {
583 setTimeout(() => {
584 const prop = booleanPropsTest.booleanTests[2].translate
585 expect(prop).to.be.true
586 }, 1000)
587 done()
588 })
589 it('Paragraph set to "translate={false} should be false', function(done) {
590 setTimeout(() => {
591 const prop = booleanPropsTest.booleanTests[3].hasAttribute('translate')
592 expect(prop).to.be.false
593 }, 1000)
594 done()
595 })
596 it('Paragraph set to "translate=\"false\" should not be false', function(done) {
597 setTimeout(() => {
598 const prop = booleanPropsTest.booleanTests[4].hasAttribute('translate')
599 expect(prop).to.be.true
600 }, 1000)
601 done()
602 })
603 it('Paragraph set to "translate=\"no\" should be false', function(done) {
604 setTimeout(() => {
605 const prop = booleanPropsTest.booleanTests[5].hasAttribute('translate')
606 expect(prop).to.be.false
607 }, 1000)
608 done()
609 })
610
611 // Autocomplete Tests
612 it('Paragraph set to "autocomplete=\"on\" should be true', function(done) {
613 setTimeout(() => {
614 const prop = booleanPropsTest.inputTests[0].hasAttribute('autocomplete')
615 expect(prop).to.be.true
616 }, 1000)
617 done()
618 })
619 it('Paragraph set to "autocomplete=\"off\" should be false', function(done) {
620 setTimeout(() => {
621 const prop = booleanPropsTest.inputTests[1].hasAttribute('autocomplete')
622 expect(prop).to.be.false
623 }, 1000)
624 done()
625 })
626 })
627
628
629
630 mocha.run()
631 </script>
632</body>
633</html>
\No newline at end of file