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