Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 04042b1

Browse files
author
Peter Hozak
committedOct 17, 2019
exercise 02
1 parent b096353 commit 04042b1

File tree

7 files changed

+144
-80
lines changed

7 files changed

+144
-80
lines changed
 

‎08-testing-hooks/README.md

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ yarn test
2222
- https://reactjs.org/docs/hooks-intro.html
2323
- https://reactjs.org/docs/testing-recipes.html#events
2424

25+
Questions possible at any time.
26+
27+
2528
## 01 testing useState
2629
> [src/01](src/01)
2730
@@ -34,44 +37,28 @@ Starting with a stateless component with a test:
3437
> [src/02](src/02)
3538
3639
Starting with the above solution and boilerplate code, display the last valid color name:
37-
- add validation test
38-
- implement validation
39-
- update component tests
40-
- update component
41-
42-
## 03 low priority for unit-testing effects
43-
> [src/03](src/03)
40+
- add validation test + update component tests
41+
- implement validation + update component
4442

45-
- code+test without state or effect
46-
- add effect that modifies state after fetching data
47-
- test 2 states (initial render, with data) without unit-testing the effect itself
4843

49-
## 04 custom hooks
50-
> [src/04](src/04)
44+
## 03 custom hooks
45+
> [src/03](src/03)
5146
5247
- code of component with lots of logic + test for just initial render
5348
- move to a new custom hook
5449
- add test for the hook, using dummy component
5550

56-
## 05 testing libraries
57-
> [src/05](src/05)
51+
52+
## 04 testing libraries
53+
> [src/04](src/04)
5854
5955
- links to useful libraries (disclaimer whether or not I had time to try them)
6056

61-
## 06 react-redux
62-
> [src/06](src/06)
57+
58+
## 05 react-redux
59+
> [src/05](src/05)
6360
6461
- existing actions, reducer, ... and simple tests for them
6562
- add useDispatch, useSelector to component
6663
- mock the selectors, use dummy dispatch and connect
6764

68-
## 07 add a feature using redux
69-
> [src/07](src/07)
70-
71-
- working solution from 06
72-
- add new JSON property to data
73-
- update redux code
74-
- update component
75-
- extra challenge: TDD
76-
77-
Q&A possible at any time.

‎08-testing-hooks/src/02/02-exercise.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
import React, { useState } from 'react'
22

3+
export const validateColor = () => false
4+
35
const Main = () => {
46
const defaultColor = 'orange'
57

6-
const [color, setColor] = useState('')
8+
const [inputColor, setInputColor] = useState('')
79
const handleHange = (event) => {
8-
setColor(event.target.value)
10+
const { value } = event.target
11+
setInputColor(value)
12+
if (validateColor(value)) {
13+
// TODO
14+
}
915
}
1016

1117
return (
1218
<div className="Main">
1319
<h3>Adding State</h3>
14-
<input placeholder={defaultColor} value={color} onChange={handleHange} />
15-
<div className="Main-box" style={{ backgroundColor: color || defaultColor }} />
20+
<input placeholder={defaultColor} value={inputColor} onChange={handleHange} />
21+
<div className="Main-box" style={{ backgroundColor: inputColor || defaultColor }}>
22+
{'orange '}
23+
</div>
1624
</div>
1725
)
1826
}
Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
import React from 'react'
22
import { render, unmountComponentAtNode } from 'react-dom'
33
import { act } from "react-dom/test-utils"
4-
import Main from './02-exercise'
4+
import Main, { validateColor } from './02-exercise'
55

6-
describe('component', () => {
6+
describe('validateColor', () => {
7+
test('some colors', () => {
8+
expect(validateColor('')).toBeFalsy()
9+
expect(validateColor('orang')).toBeFalsy()
10+
// expect(validateColor('orange')).toBeTruthy()
11+
})
12+
})
13+
14+
// input.value = "green" does not work in React 16, see https://stackoverflow.com/a/46012210/1176601
15+
const inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value").set;
16+
const modify = (input, value) => {
17+
inputValueSetter.call(input, value);
18+
input.dispatchEvent(new Event('input', { bubbles: true }))
19+
}
20+
21+
describe('Main', () => {
722
let div
823
beforeEach(() => {
924
div = document.createElement('div')
@@ -15,25 +30,23 @@ describe('component', () => {
1530
})
1631

1732
test('default color', () => {
18-
act(() => {
19-
render(<Main />, div)
20-
})
21-
expect(div.querySelector('.Main-box').style.backgroundColor).toBe('orange')
33+
act(() => { render(<Main />, div) })
34+
35+
const box = div.querySelector('.Main-box')
36+
expect(box.style.backgroundColor).toBe('orange')
37+
// expect(box.textContent).toBe('orange')
2238
});
2339

2440
test('modified color', () => {
25-
act(() => {
26-
render(<Main />, div)
27-
})
41+
act(() => { render(<Main />, div) })
42+
2843
const input = div.querySelector('input')
44+
const box = div.querySelector('.Main-box')
2945
expect(input).toHaveProperty('value', '')
30-
act(() => {
31-
// input.value = "green" does not work in React 16, see https://stackoverflow.com/a/46012210/1176601
32-
const inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value").set;
33-
inputValueSetter.call(input, 'green');
34-
input.dispatchEvent(new Event('input', { bubbles: true }))
35-
})
46+
47+
act(() => { modify(input, 'green') })
48+
3649
expect(input).toHaveProperty('value', 'green')
37-
expect(div.querySelector('.Main-box').style.backgroundColor).toBe('green')
50+
expect(box.style.backgroundColor).toBe('green')
3851
})
3952
})

‎08-testing-hooks/src/02/02-solution.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
import React, { useState } from 'react'
22

3+
export const validateColor = (value) => {
4+
const div = document.createElement('div')
5+
div.style.color = value
6+
return !!div.style.color
7+
}
8+
39
const Main = () => {
410
const defaultColor = 'orange'
511

6-
const [color, setColor] = useState('')
12+
const [inputColor, setInputColor] = useState('')
13+
const [validColor, setValidColor] = useState(defaultColor)
714
const handleHange = (event) => {
8-
setColor(event.target.value)
15+
const { value } = event.target
16+
setInputColor(value)
17+
if (!value) {
18+
setValidColor(defaultColor)
19+
} else if (validateColor(value)) {
20+
setValidColor(value)
21+
}
922
}
1023

1124
return (
1225
<div className="Main">
1326
<h3>Adding State</h3>
14-
<input placeholder={defaultColor} value={color} onChange={handleHange} />
15-
<div className="Main-box" style={{ backgroundColor: color || defaultColor }} />
27+
<input placeholder={defaultColor} value={inputColor} onChange={handleHange} />
28+
<div className="Main-box" style={{ backgroundColor: validColor }}>
29+
{validColor}
30+
</div>
1631
</div>
1732
)
1833
}
Lines changed: 66 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,75 @@
11
import React from 'react'
22
import { render, unmountComponentAtNode } from 'react-dom'
33
import { act } from "react-dom/test-utils"
4-
import Main from './02-solution'
4+
import Main, { validateColor } from './02-solution'
55

6-
let div
7-
beforeEach(() => {
8-
div = document.createElement('div')
9-
document.body.appendChild(div)
10-
})
11-
afterEach(() => {
12-
unmountComponentAtNode(div)
13-
div.remove()
14-
})
6+
describe('validateColor', () => {
7+
test('some colors', () => {
8+
expect(validateColor('')).toBeFalsy()
9+
expect(validateColor('orang')).toBeFalsy()
10+
expect(validateColor('abc')).toBeFalsy()
1511

16-
test('default color', () => {
17-
act(() => {
18-
render(<Main />, div)
12+
expect(validateColor('orange')).toBeTruthy()
13+
expect(validateColor('green')).toBeTruthy()
14+
expect(validateColor('#abc')).toBeTruthy()
1915
})
20-
expect(div.querySelector('.Main-box').style.backgroundColor).toBe('orange')
21-
});
16+
})
2217

23-
test('modified color', () => {
24-
act(() => {
25-
render(<Main />, div)
18+
// input.value = "green" does not work in React 16, see https://stackoverflow.com/a/46012210/1176601
19+
const inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value").set;
20+
const modify = (input, value) => {
21+
inputValueSetter.call(input, value);
22+
input.dispatchEvent(new Event('input', { bubbles: true }))
23+
}
24+
25+
describe('Main', () => {
26+
let div
27+
beforeEach(() => {
28+
div = document.createElement('div')
29+
document.body.appendChild(div)
30+
})
31+
afterEach(() => {
32+
unmountComponentAtNode(div)
33+
div.remove()
2634
})
27-
const input = div.querySelector('input')
28-
expect(input).toHaveProperty('value', '')
29-
act(() => {
30-
// input.value = "green" does not work in React 16, see https://stackoverflow.com/a/46012210/1176601
31-
const inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value").set;
32-
inputValueSetter.call(input, 'green');
33-
input.dispatchEvent(new Event('input', { bubbles: true }))
35+
36+
test('default color', () => {
37+
act(() => { render(<Main />, div) })
38+
39+
const box = div.querySelector('.Main-box')
40+
expect(box.style.backgroundColor).toBe('orange')
41+
expect(box.textContent).toBe('orange')
42+
});
43+
44+
test('modified color', () => {
45+
act(() => { render(<Main />, div) })
46+
47+
const input = div.querySelector('input')
48+
const box = div.querySelector('.Main-box')
49+
expect(input).toHaveProperty('value', '')
50+
51+
act(() => { modify(input, 'gree') })
52+
53+
expect(input).toHaveProperty('value', 'gree')
54+
expect(box.style.backgroundColor).toBe('orange')
55+
expect(box.textContent).toBe('orange')
56+
57+
act(() => { modify(input, 'green') })
58+
59+
expect(input).toHaveProperty('value', 'green')
60+
expect(box.style.backgroundColor).toBe('green')
61+
expect(box.textContent).toBe('green')
62+
63+
act(() => { modify(input, 'g') })
64+
65+
expect(input).toHaveProperty('value', 'g')
66+
expect(box.style.backgroundColor).toBe('green')
67+
expect(box.textContent).toBe('green')
68+
69+
act(() => { modify(input, '') })
70+
71+
expect(input).toHaveProperty('value', '')
72+
expect(box.style.backgroundColor).toBe('orange')
73+
expect(box.textContent).toBe('orange')
3474
})
35-
expect(input).toHaveProperty('value', 'green')
36-
expect(div.querySelector('.Main-box').style.backgroundColor).toBe('green')
37-
});
75+
})

‎08-testing-hooks/src/App.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useEffect } from 'react';
22

3-
const prefixes = Array.from(Array(8)).map((_, i) => `0${i + 1}`)
3+
const prefixes = Array.from(Array(2)).map((_, i) => `0${i + 1}`)
44
const links = prefixes.map((i) =>
55
<li key={i}>
66
{i}: <a href={`#${i}-exercise`} id={`${i}-exercise`}>exercise</a>
@@ -9,7 +9,7 @@ const links = prefixes.map((i) =>
99
)
1010

1111
const components = {}
12-
prefixes.filter((i) => i <= '01').forEach((i) => {
12+
prefixes.forEach((i) => {
1313
import(`./${i}/${i}-exercise`).then((imported) => {
1414
components[`${i}-exercise`] = imported.default
1515
})

‎08-testing-hooks/src/index.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,7 @@ input {
6565
.Main-box {
6666
width: 200px;
6767
height: 200px;
68+
display: flex;
69+
justify-content: center;
70+
align-items: center;
6871
}

0 commit comments

Comments
 (0)
Please sign in to comment.