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>Mount and Render</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 mount, render & unmount Functions</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="list-test"></div>
|
24 | <div id="alert-test"></div>
|
25 | <div id="render-test"></div>
|
26 | <div id="unmount"></div>
|
27 | <div id="lifecycle"></div>
|
28 | <div id="hydrate">
|
29 | <ul id="listToHydrate">
|
30 | <li>One</li>
|
31 | <li>Two</li>
|
32 | </ul>
|
33 | </div>
|
34 | </div>
|
35 | </section>
|
36 |
|
37 | <script src="https://unpkg.com/mocha@4.0.1/mocha.js"></script>
|
38 | <script src="https://unpkg.com/chai@4.1.2/chai.js"></script>
|
39 | <script src='/dist/composi.js'></script>
|
40 | <script>mocha.setup('bdd')</script>
|
41 | <script>
|
42 | const {h, mount, unmount, render} = composi
|
43 | let expect = chai.expect
|
44 |
|
45 | function H1(){
|
46 | return h('h1', {id: 'title'}, 'The Title')
|
47 | }
|
48 |
|
49 | mount(H1(), '#h1-test')
|
50 |
|
51 | function List() {
|
52 | return h('ul', {class: 'list'},[
|
53 | h('li', {}, 'one'),
|
54 | h('li', {}, 'two'),
|
55 | h('li', {}, 'three')
|
56 | ])
|
57 | }
|
58 | mount(List(), '#list-test')
|
59 |
|
60 | function Alert(message) {
|
61 | return h('h2', {style: {color: 'red'}} , `Alert: ${message}!`)
|
62 | }
|
63 | mount(Alert('this is a message'), '#alert-test')
|
64 |
|
65 | const things = [
|
66 | {name: 'Apple', key: 101},
|
67 | {name: 'Chair', key: 102},
|
68 | {name: 'Horse', key: 103}
|
69 | ]
|
70 | function List2(data) {
|
71 | return h(
|
72 | 'ul',
|
73 | {},
|
74 | data.map(item => h('li', {key: item.key}, item.name))
|
75 | )
|
76 | }
|
77 | let vNode = List2(things)
|
78 | let list2 = mount(List2(things), '#render-test')
|
79 |
|
80 | setTimeout(() => {
|
81 | things.push({name: 'Popcorn', key: 104})
|
82 | vNode = List2(things)
|
83 | list2 = render(List2(things), list2, '#render-test')
|
84 | }, 3000)
|
85 |
|
86 | describe('Create virtual node for list', function() {
|
87 | it('virtual node should have three children', function() {
|
88 | expect(vNode.children.length).to.equal(3)
|
89 | })
|
90 | it('virtual node children should equal "Apple", "Chair" and "Horse"', function() {
|
91 | expect(vNode.children[0].children[0].type).to.equal('Apple')
|
92 | expect(vNode.children[1].children[0].type).to.equal('Chair')
|
93 | expect(vNode.children[2].children[0].type).to.equal('Horse')
|
94 | })
|
95 | it('virtual node children should have following keys: "101", "102", "103"', function() {
|
96 | expect(vNode.children[0].key).to.equal(101)
|
97 | expect(vNode.children[1].key).to.equal(102)
|
98 | expect(vNode.children[2].key).to.equal(103)
|
99 | })
|
100 | })
|
101 |
|
102 | describe("Mount h1", function() {
|
103 | const title = document.querySelector('#title')
|
104 | it('title should be "h1"', function() {
|
105 | expect(title.nodeName).to.equal('H1')
|
106 | });
|
107 | it('title should have id equal to "title"', function() {
|
108 | expect(title.id).to.equal('title')
|
109 | })
|
110 | it('title content should be "The Title"', function() {
|
111 | expect(title.textContent).to.equal('The Title')
|
112 | })
|
113 | it('Mounted component element should have property "isMounted"', function() {
|
114 | expect(title.isMounted).to.equal(true)
|
115 | })
|
116 | })
|
117 | describe('Mount list', function() {
|
118 | const list = document.querySelector('ul')
|
119 | it('list should be of type "UL"', function() {
|
120 | expect(list.nodeName).to.equal('UL')
|
121 | })
|
122 | it('list should have class of "list"', function() {
|
123 | expect(list.className).to.equal('list')
|
124 | })
|
125 | it('list should have three children', function() {
|
126 | expect(list.childNodes).to.have.lengthOf(3)
|
127 | })
|
128 | it('list item one should be type "LI"', function() {
|
129 | expect(list.childNodes[0].nodeName).to.equal('LI')
|
130 | })
|
131 | it('list 1 item content should be "one"', function() {
|
132 | expect(list.childNodes[0].textContent).to.equal('one')
|
133 | })
|
134 | it('list 2 item content should be "two"', function() {
|
135 | expect(list.childNodes[1].textContent).to.equal('two')
|
136 | })
|
137 | it('list 3 item content should be "three"', function() {
|
138 | expect(list.childNodes[2].textContent).to.equal('three')
|
139 | })
|
140 | })
|
141 |
|
142 | describe('Mount alert', function() {
|
143 | const alert = document.querySelector('h2')
|
144 | it('alert should be of type "H2"', function() {
|
145 | expect(alert.nodeName).to.equal('H2')
|
146 | })
|
147 | it('alert content should be "Alert: this is a message!"', function() {
|
148 | expect(alert.textContent).to.equal("Alert: this is a message!")
|
149 | })
|
150 | it('alert should have style of "color: red"', function() {
|
151 | expect(alert.style.color).to.equal('red')
|
152 | })
|
153 | })
|
154 |
|
155 | describe('Hydrate existing DOM node using mount function', function() {
|
156 | const listToHydrate = document.querySelector('#listToHydrate')
|
157 | function hydrateTheList() {
|
158 | return (
|
159 | h(
|
160 | 'ul',
|
161 | {
|
162 | id: 'listToHydrate'
|
163 | },
|
164 | [
|
165 | h(
|
166 | 'li',
|
167 | {key: 101},
|
168 | ['Apple']
|
169 | ),
|
170 | h(
|
171 | 'li',
|
172 | {key: 102},
|
173 | ['Orange']
|
174 | ),
|
175 | h(
|
176 | 'li',
|
177 | {key: 103},
|
178 | ['Banana']
|
179 | )
|
180 | ]
|
181 | )
|
182 | )
|
183 | }
|
184 |
|
185 | it('The list to hydrate should have an id of "listToHydrate"', function() {
|
186 | expect(listToHydrate.id).to.equal('listToHydrate')
|
187 | })
|
188 |
|
189 | it('The list to hydrate should have two children', function() {
|
190 | expect(listToHydrate.children.length).to.equal(2)
|
191 | })
|
192 |
|
193 | it('The list to hydrate should have children with content of "One" and "Two"', function() {
|
194 | expect(listToHydrate.children[0].textContent).to.equal('One')
|
195 | expect(listToHydrate.children[1].textContent).to.equal('Two')
|
196 | })
|
197 |
|
198 | it('The hydrated list should have three children', function(done) {
|
199 | setTimeout(() => {
|
200 | mount(hydrateTheList(), '#hydrate', '#listToHydrate')
|
201 | const hydratedList = document.querySelector('#listToHydrate')
|
202 | expect(hydratedList.children.length).to.equal(3)
|
203 | }, 1500)
|
204 | done()
|
205 | })
|
206 |
|
207 | it('The hydrated list should have and id of "hydratedList"', function(done) {
|
208 | setTimeout(() => {
|
209 | const hydratedList = document.querySelector('#listToHydrate')
|
210 | expect(hydratedList.id).to.equal('listToHydrate')
|
211 | }, 1000)
|
212 | done()
|
213 | })
|
214 |
|
215 | it('The hydrated list should contain "Apple", "Orange", "Banana"', function(done) {
|
216 | setTimeout(() => {
|
217 | const hydratedList = document.querySelector('#listToHydrate')
|
218 | expect(hydratedList.children[0].textContent).to.equal('Apple')
|
219 | expect(hydratedList.children[1].textContent).to.equal('Orange')
|
220 | expect(hydratedList.children[2].textContent).to.equal('Banana')
|
221 | }, 2500)
|
222 | done()
|
223 | }, 2500)
|
224 | })
|
225 |
|
226 | describe('Mount list to update later', function() {
|
227 | const list = document.querySelector('#render-test ul')
|
228 |
|
229 | it('should have just three children', function() {
|
230 | expect(list.children.length).to.equal(3)
|
231 | })
|
232 | it('list items should contain "Apple", "Chair" and "Horse"', function() {
|
233 | expect(list.children[0].textContent).to.equal('Apple')
|
234 | expect(list.children[1].textContent).to.equal('Chair')
|
235 | expect(list.children[2].textContent).to.equal('Horse')
|
236 | })
|
237 |
|
238 | })
|
239 |
|
240 | describe('Update list with render function', function() {
|
241 | it('list virtual node should have four children', function(done) {
|
242 | setTimeout(() => {
|
243 | expect(vNode.children.length).to.equal(4)
|
244 | }, 3000)
|
245 | done()
|
246 | })
|
247 | it('list virtual node now have four items"', function(done) {
|
248 | setTimeout(() => {
|
249 | expect(vNode.children.length).to.equal(4)
|
250 | }, 3000)
|
251 | done()
|
252 | })
|
253 | const list = document.querySelector('#render-test ul')
|
254 | it('virtual node children should be "Apple", "Chair", "Horse" and "Popcorn', function(done) {
|
255 | setTimeout(() => {
|
256 | expect(vNode.children[0].children[0].type).to.equal('Apple')
|
257 | expect(vNode.children[1].children[0].type).to.equal('Chair')
|
258 | expect(vNode.children[2].children[0].type).to.equal('Horse')
|
259 | expect(vNode.children[3].children[0].type).to.equal('Popcorn')
|
260 | }, 3000)
|
261 | done()
|
262 | })
|
263 | it('virtual node children keys should be "101", "102", "103", "104"', function(done) {
|
264 | setTimeout(() => {
|
265 | expect(vNode.children[0].key).to.equal(101)
|
266 | expect(vNode.children[1].key).to.equal(102)
|
267 | expect(vNode.children[2].key).to.equal(103)
|
268 | expect(vNode.children[3].key).to.equal(104)
|
269 | }, 3000)
|
270 | done()
|
271 | })
|
272 | it('DOM list should have four list items', function(done) {
|
273 | setTimeout(() => {
|
274 | expect(list.children.length).to.equal(4)
|
275 | }, 3000)
|
276 | done()
|
277 | })
|
278 | it('DOM list items should contain "Apple", "Chair", "Horse" and "Popcorn"', function(done) {
|
279 | setTimeout(() => {
|
280 | expect(list.children[0].textContent).to.equal('Apple')
|
281 | expect(list.children[1].textContent).to.equal('Chair')
|
282 | expect(list.children[2].textContent).to.equal('Horse')
|
283 | expect(list.children[3].textContent).to.equal('Popcorn')
|
284 | }, 3000)
|
285 | done()
|
286 | })
|
287 | })
|
288 |
|
289 | describe('Component should execute thee lifecycle hooks', function() {
|
290 | let componentDidMount = false
|
291 | let componentDidUpdate = false
|
292 | let componentDidUnmount = false
|
293 | let unmountedComponents = 0
|
294 | function LifecycleTest(data) {
|
295 | function testMount() {
|
296 | componentDidMount = true
|
297 | }
|
298 | function testUpdate() {
|
299 | componentDidUpdate = true
|
300 | unmountedComponents += 1
|
301 | }
|
302 | function testUnmount(done, el) {
|
303 | componentDidUnmount = true
|
304 | done()
|
305 | }
|
306 | function listItems(items) {
|
307 | console.log(items)
|
308 | return items.map(item => h('li', {onunmount: (done, el) => testUnmount(done, el)}, item))
|
309 | }
|
310 | return (
|
311 | h(
|
312 | 'ul',
|
313 | {
|
314 | onmount: () => {
|
315 | testMount()
|
316 | },
|
317 | onupdate: () => {
|
318 | testUpdate()
|
319 | }
|
320 | },
|
321 | listItems(data)
|
322 | )
|
323 | )
|
324 | }
|
325 | let testComponent = mount(LifecycleTest([1,2]), '#lifecycle')
|
326 |
|
327 | it('Functional component should execute "onmount" when it is mounted', function(done) {
|
328 | setTimeout(() => {
|
329 | expect(componentDidMount).to.be.true
|
330 | expect(testComponent.children.length).to.equal(2)
|
331 | }, 1000)
|
332 | done()
|
333 | })
|
334 | it('Functional component should execute "onupdate" when it is updated', function(done) {
|
335 | setTimeout(() => {
|
336 | testComponent = render(LifecycleTest([1,2,3]), testComponent, '#lifecycle')
|
337 | expect(componentDidUpdate).to.be.true
|
338 | expect(testComponent.children.length).to.equal(3)
|
339 | }, 1500)
|
340 | done()
|
341 | })
|
342 | it('List component\'s list items should execute "onunmount" when they are deleted', function(done) {
|
343 | setTimeout(() => {
|
344 | testComponent = render(LifecycleTest([1]), testComponent, '#lifecycle')
|
345 | expect(componentDidUnmount).to.be.true
|
346 | expect(testComponent.children.length).to.equal(1)
|
347 | expect(unmountedComponents).to.equal(2)
|
348 | }, 2000)
|
349 | done()
|
350 | })
|
351 | })
|
352 |
|
353 | describe('Component should mount, unmount, mount again and update with render function', function() {
|
354 | function MountTest(props) {
|
355 | return (
|
356 | h(
|
357 | 'p',
|
358 | {
|
359 | id: 'unmountBase',
|
360 | },
|
361 | props.message
|
362 | )
|
363 | )
|
364 | }
|
365 | let mountTest = mount(MountTest({ id: 'unmountBase', message: 'whatever'}), '#unmount')
|
366 | let mountTestContainer = document.querySelector('#unmount')
|
367 |
|
368 | it('Component should be mounted.', function() {
|
369 | expect(mountTest.element.nodeType).to.equal(1)
|
370 | expect(mountTest.element.id).to.equal('unmountBase')
|
371 | expect(mountTest.element.isMounted).to.equal(true)
|
372 | expect(mountTestContainer.textContent).to.equal('whatever')
|
373 | })
|
374 | it('Unmount should remove component from DOM', function(done) {
|
375 | setTimeout(() => {
|
376 | unmount(mountTest)
|
377 | expect(mountTestContainer.children.length).to.equal(0)
|
378 | expect(mountTest.element).to.equal(null)
|
379 | }, 1000)
|
380 | done()
|
381 | })
|
382 | it('Should be able to re-mount unmounted component', function(done) {
|
383 | setTimeout(() => {
|
384 | mountTest = mount(MountTest({ id: 'unmountBase', message: 'new message' }), '#unmount')
|
385 | expect(mountTest.element.nodeType).to.equal(1)
|
386 | expect(mountTest.element.id).to.equal('unmountBase')
|
387 | expect(mountTest.element.isMounted).to.equal(true)
|
388 | expect(mountTestContainer.textContent).to.equal('new message')
|
389 | }, 2000)
|
390 | done()
|
391 | })
|
392 | it('Should be able to use render to update re-mounted component', function (done) {
|
393 | setTimeout(() => {
|
394 | mountTest = render(MountTest({ id: 'unmountBase', message: 'updated message' }), mountTest, '#unmount')
|
395 | expect(mountTestContainer.textContent).to.equal('updated message')
|
396 | }, 3000)
|
397 | done()
|
398 | })
|
399 | })
|
400 | mocha.run()
|
401 | </script>
|
402 | </body>
|
403 | </html> |
\ | No newline at end of file |