From 5082dcb52d611e310881ddd249dbdce78ffadb14 Mon Sep 17 00:00:00 2001
From: "Kent C. Dodds"
Date: Sat, 9 Jan 2021 12:32:06 -0700
Subject: [PATCH 1/3] migrate to TypeScript
---
.github/workflows/validate.yml | 2 +
package-lock.json | 3 +-
package.json | 10 +-
scripts/remove-ts | 2 +
src/__tests__/{05.js => 06.tsx} | 4 +-
.../{06.extra-2.js => 07.extra-2.tsx} | 11 +-
.../{06.extra-3.js => 07.extra-3.tsx} | 11 +-
src/__tests__/{06.js => 07.tsx} | 11 +-
src/__tests__/{07.js => 08.tsx} | 12 +-
src/exercise/01.html | 15 +-
src/exercise/01.md | 8 +-
src/exercise/02.html | 7 +-
src/exercise/02.md | 71 +++-
src/exercise/03.md | 68 +++-
src/exercise/04.extra-4.html | 41 ++
src/exercise/04.md | 191 +++++-----
src/exercise/05.md | 351 ++++++++++++++----
src/exercise/05.tsx | 40 ++
src/exercise/06.md | 191 +++++-----
src/exercise/{05.js => 06.tsx} | 2 +-
src/exercise/07.md | 188 ++++++----
src/exercise/{06.js => 07.tsx} | 11 +-
src/exercise/08.md | 97 +++++
src/exercise/{07.js => 08.tsx} | 24 +-
src/final/01.extra-1.html | 26 +-
src/final/01.html | 24 +-
src/final/02.extra-1.html | 14 +-
src/final/02.extra-2.html | 24 ++
src/final/03.extra-3.html | 22 ++
src/final/03.extra-4.html | 22 ++
src/final/04.extra-3.html | 36 +-
src/final/04.extra-4.html | 32 +-
src/final/04.extra-5.html | 33 --
src/final/05.extra-1.tsx | 41 ++
src/final/05.extra-2.tsx | 41 ++
src/final/05.extra-3.tsx | 41 ++
src/final/05.extra-4.tsx | 43 +++
src/final/05.extra-5.tsx | 47 +++
src/final/05.tsx | 40 ++
src/final/{05.extra-1.js => 06.extra-1.tsx} | 8 +-
src/final/{05.extra-2.js => 06.extra-2.tsx} | 11 +-
src/final/06.js | 28 --
src/final/{05.js => 06.tsx} | 3 +-
src/final/{06.extra-1.js => 07.extra-1.tsx} | 19 +-
src/final/{06.extra-2.js => 07.extra-2.tsx} | 28 +-
src/final/{06.extra-3.js => 07.extra-3.tsx} | 30 +-
src/final/07.tsx | 40 ++
src/final/{07.extra-1.js => 08.extra-1.tsx} | 14 +-
src/final/{07.js => 08.tsx} | 24 +-
src/{index.js => index.tsx} | 0
src/react-app-env.d.ts | 1 +
src/{setupTests.js => setupTests.ts} | 0
tsconfig.json | 20 +
53 files changed, 1496 insertions(+), 587 deletions(-)
create mode 100755 scripts/remove-ts
rename src/__tests__/{05.js => 06.tsx} (95%)
rename src/__tests__/{06.extra-2.js => 07.extra-2.tsx} (79%)
rename src/__tests__/{06.extra-3.js => 07.extra-3.tsx} (69%)
rename src/__tests__/{06.js => 07.tsx} (69%)
rename src/__tests__/{07.js => 08.tsx} (72%)
create mode 100644 src/exercise/04.extra-4.html
create mode 100644 src/exercise/05.tsx
rename src/exercise/{05.js => 06.tsx} (97%)
rename src/exercise/{06.js => 07.tsx} (83%)
create mode 100644 src/exercise/08.md
rename src/exercise/{07.js => 08.tsx} (71%)
create mode 100644 src/final/02.extra-2.html
create mode 100644 src/final/03.extra-3.html
create mode 100644 src/final/03.extra-4.html
delete mode 100644 src/final/04.extra-5.html
create mode 100644 src/final/05.extra-1.tsx
create mode 100644 src/final/05.extra-2.tsx
create mode 100644 src/final/05.extra-3.tsx
create mode 100644 src/final/05.extra-4.tsx
create mode 100644 src/final/05.extra-5.tsx
create mode 100644 src/final/05.tsx
rename src/final/{05.extra-1.js => 06.extra-1.tsx} (85%)
rename src/final/{05.extra-2.js => 06.extra-2.tsx} (81%)
delete mode 100644 src/final/06.js
rename src/final/{05.js => 06.tsx} (92%)
rename src/final/{06.extra-1.js => 07.extra-1.tsx} (53%)
rename src/final/{06.extra-2.js => 07.extra-2.tsx} (53%)
rename src/final/{06.extra-3.js => 07.extra-3.tsx} (50%)
create mode 100644 src/final/07.tsx
rename src/final/{07.extra-1.js => 08.extra-1.tsx} (85%)
rename src/final/{07.js => 08.tsx} (70%)
rename src/{index.js => index.tsx} (100%)
create mode 100644 src/react-app-env.d.ts
rename src/{setupTests.js => setupTests.ts} (100%)
create mode 100644 tsconfig.json
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index d89a0ccd2..d169dac6b 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -3,9 +3,11 @@ on:
push:
branches:
- 'main'
+ - 'next'
pull_request:
branches:
- 'main'
+ - 'next'
jobs:
setup:
# ignore all-contributors PRs
diff --git a/package-lock.json b/package-lock.json
index bc8c98bc8..9facb4c10 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18196,8 +18196,7 @@
"typescript": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
- "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
- "dev": true
+ "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw=="
},
"typographic-apostrophes": {
"version": "1.1.1",
diff --git a/package.json b/package.json
index b603206c5..bc1136b9b 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"version": "1.0.0",
"private": true,
"keywords": [],
- "homepage": "http://react-fundamentals.netlify.app/",
+ "homepage": "http://react-fundamentals-next.netlify.app/",
"license": "GPL-3.0-only",
"main": "src/index.js",
"engines": {
@@ -17,12 +17,15 @@
"@kentcdodds/react-workshop-app": "^4.0.0",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^12.8.1",
+ "@types/jest": "^26.0.20",
+ "@types/node": "^14.14.31",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.1",
"chalk": "^4.1.0",
"codegen.macro": "^4.1.0",
"react": "^17.0.1",
- "react-dom": "^17.0.1"
+ "react-dom": "^17.0.1",
+ "typescript": "^4.1.3"
},
"devDependencies": {
"husky": "^4.3.8",
@@ -40,7 +43,8 @@
"setup": "node setup",
"lint": "eslint .",
"format": "prettier --write \"./src\"",
- "validate": "npm-run-all --parallel build test:coverage lint"
+ "typecheck": "tsc",
+ "validate": "npm-run-all --parallel build test:coverage lint typecheck"
},
"husky": {
"hooks": {
diff --git a/scripts/remove-ts b/scripts/remove-ts
new file mode 100755
index 000000000..ebfeedaf8
--- /dev/null
+++ b/scripts/remove-ts
@@ -0,0 +1,2 @@
+npx https://gist.github.com/kentcdodds/e49b9b8da0dd467149d8d67258251585
+./scripts/fix-links
diff --git a/src/__tests__/05.js b/src/__tests__/06.tsx
similarity index 95%
rename from src/__tests__/05.js
rename to src/__tests__/06.tsx
index dde4875d8..14d116575 100644
--- a/src/__tests__/05.js
+++ b/src/__tests__/06.tsx
@@ -1,8 +1,8 @@
import * as React from 'react'
import chalk from 'chalk'
import {render, screen, prettyDOM} from '@testing-library/react'
-import App from '../final/05'
-// import App from '../exercise/05'
+import {App} from '../final/06'
+// import {App} from '../exercise/06'
test('renders the correct styles new', () => {
const {container} = render()
diff --git a/src/__tests__/06.extra-2.js b/src/__tests__/07.extra-2.tsx
similarity index 79%
rename from src/__tests__/06.extra-2.js
rename to src/__tests__/07.extra-2.tsx
index 4bc2c8c48..77edd01c9 100644
--- a/src/__tests__/06.extra-2.js
+++ b/src/__tests__/07.extra-2.tsx
@@ -2,20 +2,21 @@ import * as React from 'react'
import {alfredTip} from '@kentcdodds/react-workshop-app/test-utils'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
-import App from '../final/06.extra-2'
-// import App from '../exercise/06'
+import {App} from '../final/07.extra-2'
+// import {App} from '../exercise/07'
+let alert = jest.spyOn(global, 'alert')
beforeAll(() => {
- jest.spyOn(global, 'alert').mockImplementation(() => {})
+ alert.mockImplementation(() => {})
})
beforeEach(() => {
- global.alert.mockClear()
+ alert.mockClear()
})
test('calls the onSubmitUsername handler when the submit is fired', () => {
render()
- const input = screen.getByLabelText(/username/i)
+ const input = screen.getByLabelText(/username/i) as HTMLInputElement
const submit = screen.getByText(/submit/i)
let value = 'A'
diff --git a/src/__tests__/06.extra-3.js b/src/__tests__/07.extra-3.tsx
similarity index 69%
rename from src/__tests__/06.extra-3.js
rename to src/__tests__/07.extra-3.tsx
index e09413535..f33709ca8 100644
--- a/src/__tests__/06.extra-3.js
+++ b/src/__tests__/07.extra-3.tsx
@@ -1,20 +1,21 @@
import * as React from 'react'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
-import App from '../final/06.extra-3'
-// import App from '../exercise/06'
+import {App} from '../final/07.extra-3'
+// import {App} from '../exercise/07'
+let alert = jest.spyOn(global, 'alert')
beforeAll(() => {
- jest.spyOn(global, 'alert').mockImplementation(() => {})
+ alert.mockImplementation(() => {})
})
beforeEach(() => {
- global.alert.mockClear()
+ alert.mockClear()
})
test('calls the onSubmitUsername handler when the submit is fired', () => {
render()
- const input = screen.getByLabelText(/username/i)
+ const input = screen.getByLabelText(/username/i) as HTMLInputElement
const submit = screen.getByText(/submit/i)
const value = 'A'
diff --git a/src/__tests__/06.js b/src/__tests__/07.tsx
similarity index 69%
rename from src/__tests__/06.js
rename to src/__tests__/07.tsx
index 74f66515e..dbd271e8a 100644
--- a/src/__tests__/06.js
+++ b/src/__tests__/07.tsx
@@ -1,20 +1,21 @@
import * as React from 'react'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
-import App from '../final/06'
-// import App from '../exercise/06'
+import {App} from '../final/07'
+// import {App} from '../exercise/07'
+let alert = jest.spyOn(global, 'alert')
beforeAll(() => {
- jest.spyOn(global, 'alert').mockImplementation(() => {})
+ alert.mockImplementation(() => {})
})
beforeEach(() => {
- global.alert.mockClear()
+ alert.mockClear()
})
test('calls the onSubmitUsername handler when the submit is fired', () => {
render()
- const input = screen.getByLabelText(/username/i)
+ const input = screen.getByLabelText(/username/i) as HTMLInputElement
const submit = screen.getByText(/submit/i)
const username = 'jenny'
diff --git a/src/__tests__/07.js b/src/__tests__/08.tsx
similarity index 72%
rename from src/__tests__/07.js
rename to src/__tests__/08.tsx
index 7bc83340a..9040b2159 100644
--- a/src/__tests__/07.js
+++ b/src/__tests__/08.tsx
@@ -1,8 +1,8 @@
import * as React from 'react'
import {render, screen, within} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
-import App from '../final/07'
-// import App from '../exercise/07'
+import {App} from '../final/08'
+// import {App} from '../exercise/08'
test('renders', () => {
const {container} = render()
@@ -14,6 +14,9 @@ test('renders', () => {
const orangeInput = screen.getByLabelText(/orange/i)
const orangeContainer = screen.getByText(/orange/i).closest('li')
+ if (!orangeContainer) {
+ throw new Error(`🚨 Can't find the li for "orange"`)
+ }
const inOrange = within(orangeContainer)
userEvent.type(orangeInput, 'sup dawg')
userEvent.click(inOrange.getByText('remove'))
@@ -22,6 +25,11 @@ test('renders', () => {
Array.from(allLis).forEach(li => {
const label = li.querySelector('label')
const input = li.querySelector('input')
+ if (!label || !input) {
+ throw new Error(
+ '🚨 Please make sure to not remove the label and input in the li elements',
+ )
+ }
expect(label.textContent).toBe(input.value)
})
})
diff --git a/src/exercise/01.html b/src/exercise/01.html
index 834757f37..31aca293e 100644
--- a/src/exercise/01.html
+++ b/src/exercise/01.html
@@ -1,16 +1,19 @@
-
+
-
-
+
+
+
-
-
+
+
+
+
+
-
diff --git a/src/exercise/01.md b/src/exercise/01.md
index f9f4ab1da..d3528bc3a 100644
--- a/src/exercise/01.md
+++ b/src/exercise/01.md
@@ -56,6 +56,8 @@ going to use React at all. Instead we're going to use JavaScript to create a
`div` DOM node with the text "Hello World" and insert that DOM node into the
document.
+Now, open `exercise/01.html` and follow the instructions in there.
+
## Extra Credit
### 1. 💯 generate the root node
@@ -63,7 +65,11 @@ document.
[Production deploy](http://react-fundamentals.netlify.app/isolated/final/01.extra-1.html)
Rather than having the `root` node in the HTML, see if you can create that one
-using JavaScript as well.
+using JavaScript as well. Remove the `` from the HTML and
+instead of trying to find it with `document.getElementById('root')`, create it
+and append it to the `document.body`.
+
+Do this in `exercise/01.html`, building on top of the work you've already done.
## 🦉 Feedback
diff --git a/src/exercise/02.html b/src/exercise/02.html
index 31ff2bea3..4ac8a3c31 100644
--- a/src/exercise/02.html
+++ b/src/exercise/02.html
@@ -15,14 +15,15 @@
// You're going to re-implement this code using React!
// 💣 So go ahead and delete this implementation (or comment it out for now)
// These three lines are similar to React.createElement
+ // 📜 https://reactjs.org/docs/react-api.html#createelement
const element = document.createElement('div')
- element.textContent = 'Hello World' // 💰 in React, you set this with the "children" prop
element.className = 'container' // 💰 in React, this is also called the "className" prop
+ element.append('Hello World') // 💰 in React, you set this with the "children" prop
// This is similar to ReactDOM.render
+ // 📜 https://reactjs.org/docs/react-dom.html#render
rootElement.append(element)
- // 🐨 Please re-implement the regular document.createElement code above
- // with these React API calls
+ // 🐨 Please replace all the DOM-related code above with React API calls
// 💰 The example in the markdown file should be a good hint for you.
-
-