├── .codesandbox └── workspace.json ├── .gitignore ├── .prettierrc ├── README.md ├── package-lock.json ├── package.json └── src ├── __tests__ ├── form.enzyme.js ├── form.react-dom.js └── form.react-testing-library.js ├── form.js └── index.js /.codesandbox/workspace.json: -------------------------------------------------------------------------------- 1 | { 2 | "preview": [ 3 | { 4 | "views": [ 5 | { 6 | "id": "codesandbox.tests" 7 | }, 8 | { 9 | "id": "codesandbox.browser" 10 | } 11 | ] 12 | }, 13 | { 14 | "views": [ 15 | { 16 | "id": "codesandbox.console" 17 | }, 18 | { 19 | "id": "codesandbox.problems" 20 | }, 21 | { 22 | "id": "codesandbox.react-devtools" 23 | } 24 | ] 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSpacing": false, 4 | "embeddedLanguageFormatting": "auto", 5 | "htmlWhitespaceSensitivity": "css", 6 | "insertPragma": false, 7 | "jsxBracketSameLine": false, 8 | "jsxSingleQuote": false, 9 | "printWidth": 80, 10 | "proseWrap": "never", 11 | "quoteProps": "as-needed", 12 | "requirePragma": false, 13 | "semi": false, 14 | "singleQuote": true, 15 | "tabWidth": 2, 16 | "trailingComma": "all", 17 | "useTabs": false, 18 | "vueIndentScriptAndStyle": false 19 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Confident React (examples) 2 | 3 | This repo is some examples that I'm using for my talk ["Confident React"](https://kentcdodds.com/talks/#confident-react) 4 | 5 | [Slides](https://slides.com/kentcdodds/confident-react) 6 | 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "confident-react-examples", 3 | "version": "1.0.0", 4 | "description": "This repo is some examples that I'm using for my talk \"Confident React\"", 5 | "main": "src/index.js", 6 | "dependencies": { 7 | "@testing-library/react": "^11.2.5", 8 | "@testing-library/user-event": "^13.0.7", 9 | "babel-preset-react-app": "^9.1.2", 10 | "enzyme": "^3.11.0", 11 | "enzyme-adapter-react-16": "^1.15.6", 12 | "jest": "^26.6.3", 13 | "react": "^16.14.0", 14 | "react-dom": "^16.14.0" 15 | }, 16 | "devDependencies": {}, 17 | "scripts": { 18 | "test": "jest --watchAll" 19 | }, 20 | "babel": { 21 | "presets": [ 22 | "react-app" 23 | ] 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/kentcdodds/confident-react-examples.git" 28 | }, 29 | "keywords": [], 30 | "author": "Kent C. Dodds (https://kentcdodds.com/)", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/kentcdodds/confident-react-examples/issues" 34 | }, 35 | "homepage": "https://github.com/kentcdodds/confident-react-examples#readme" 36 | } 37 | -------------------------------------------------------------------------------- /src/__tests__/form.enzyme.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Enzyme, {mount} from 'enzyme' 3 | import Adapter from 'enzyme-adapter-react-16' 4 | import {Login} from '../form' 5 | 6 | Enzyme.configure({adapter: new Adapter()}) 7 | 8 | test('enzyme version', () => { 9 | const handleSubmit = jest.fn() 10 | 11 | const wrapper = mount() 12 | const usernameInput = wrapper.find('input').first().hostNodes().instance() 13 | usernameInput.value = 'chucknorris' 14 | const passwordInput = wrapper.find('input').at(1).hostNodes().instance() 15 | passwordInput.value = 'I need no password' 16 | const form = wrapper.find('Form').simulate('submit') 17 | 18 | expect(handleSubmit).toHaveBeenCalledTimes(1) 19 | expect(handleSubmit).toHaveBeenCalledWith( 20 | expect.objectContaining({ 21 | username: 'chucknorris', 22 | password: 'I need no password', 23 | }), 24 | ) 25 | }) 26 | -------------------------------------------------------------------------------- /src/__tests__/form.react-dom.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import {Login} from '../form' 4 | 5 | test('raw ReactDOM version', () => { 6 | // setup 7 | const container = document.createElement('div') 8 | document.body.append(container) 9 | 10 | const handleSubmit = jest.fn() 11 | ReactDOM.render(, container) 12 | 13 | const inputs = container.querySelectorAll('input') 14 | const usernameInput = inputs[0] 15 | usernameInput.value = 'chucknorris' 16 | const passwordInput = inputs[1] 17 | passwordInput.value = 'I need no password' 18 | 19 | const form = container.querySelector('form') 20 | const submitEvent = new Event('submit', { 21 | bubbles: true, 22 | cancelable: true, 23 | }) 24 | form.dispatchEvent(submitEvent) 25 | 26 | expect(handleSubmit).toHaveBeenCalledTimes(1) 27 | expect(handleSubmit).toHaveBeenCalledWith( 28 | expect.objectContaining({ 29 | username: 'chucknorris', 30 | password: 'I need no password', 31 | }), 32 | ) 33 | 34 | // cleanup 35 | container.remove() 36 | }) 37 | -------------------------------------------------------------------------------- /src/__tests__/form.react-testing-library.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render, screen} from '@testing-library/react' 3 | import userEvent from '@testing-library/user-event' 4 | import {Login} from '../form' 5 | 6 | test('react-testing-library version', () => { 7 | const handleSubmit = jest.fn() 8 | 9 | render() 10 | 11 | const usernameInput = screen.getByRole('textbox', {name: /username/i}) 12 | userEvent.type(usernameInput, 'chucknorris') 13 | const passwordInput = screen.getByLabelText(/password/i) 14 | userEvent.type(passwordInput, 'I need no password') 15 | 16 | userEvent.click(screen.getByText(/submit/i)) 17 | 18 | expect(handleSubmit).toHaveBeenCalledTimes(1) 19 | expect(handleSubmit).toHaveBeenCalledWith( 20 | expect.objectContaining({ 21 | username: 'chucknorris', 22 | password: 'I need no password', 23 | }), 24 | ) 25 | }) 26 | -------------------------------------------------------------------------------- /src/form.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function Login({onSubmit}) { 4 | return ( 5 |
6 |
7 | 8 | 9 | 10 | 11 |
12 | ) 13 | } 14 | 15 | function Form({onSubmit, children}) { 16 | return ( 17 |
{ 19 | event.preventDefault() 20 | const elementValues = getElementValues(event.target) 21 | onSubmit(elementValues) 22 | }} 23 | > 24 | {children} 25 |
26 | ) 27 | } 28 | 29 | function getElementValues(formNode) { 30 | return Object.getOwnPropertyNames(formNode.elements).reduce((obj, key) => { 31 | obj[key] = formNode.elements[key].value 32 | return obj 33 | }, {}) 34 | } 35 | 36 | function LabeledInput({label, type = 'text'}) { 37 | return ( 38 | 39 | 40 | 41 | 42 | ) 43 | } 44 | 45 | export {Login} 46 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | function App() { 5 | return 'checkout the tests...' 6 | } 7 | 8 | ReactDOM.render(, document.getElementById('root')) 9 | --------------------------------------------------------------------------------