Skip to content

Commit

Permalink
add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kentcdodds committed Sep 18, 2024
1 parent 89c64c6 commit 9490a7e
Show file tree
Hide file tree
Showing 14 changed files with 163 additions and 7 deletions.
5 changes: 5 additions & 0 deletions exercises/03.custom-hooks/01.problem.function/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ For the types of that tuple, you may find this article helpful:
going!
</callout-info>

<callout-info class="aside">
🚨 this is just a refactor so the tests are passing already, you just need to
make sure they don't fail!
</callout-info>

Good luck!
2 changes: 1 addition & 1 deletion exercises/03.custom-hooks/01.problem.function/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { setGlobalSearchParams } from '#shared/utils'
const getQueryParam = (params: URLSearchParams) => params.get('query') ?? ''

// 🐨 create a function called useSearchParams here and move much of what's
// below into this hook
// below into this hook.

function App() {
// 🐨 move everything from here to the next 🐨 into the new function
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test'
const { screen, fireEvent } = dtl

window.history.pushState({}, '', '?query=dog')

await import('./index.tsx')

await testStep(
'The search box is initialized with URL query parameter',
async () => {
const searchBox = await screen.findByRole('searchbox', { name: /search/i })
expect(searchBox).toHaveValue('dog')
},
)

await testStep(
'Updating the search box updates the URL search params',
async () => {
const searchBox = screen.getByRole('searchbox', { name: /search/i })
fireEvent.change(searchBox, { target: { value: 'cat' } })

expect(searchBox).toHaveValue('cat')
expect(window.location.search).toBe('?query=cat')
},
)
2 changes: 1 addition & 1 deletion exercises/03.custom-hooks/02.problem.callback/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { setGlobalSearchParams } from '#shared/utils'

const getQueryParam = (params: URLSearchParams) => params.get('query') ?? ''

function useSearchParams() {
export function useSearchParams() {
const [searchParams, setSearchParamsState] = useState(
() => new URLSearchParams(window.location.search),
)
Expand Down
25 changes: 25 additions & 0 deletions exercises/03.custom-hooks/02.solution.callback/callback.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { expect, testStep } from '@epic-web/workshop-utils/test'
import { useReducer } from 'react'
import { createRoot } from 'react-dom/client'
import { useSearchParams } from './index'

let setSearchParams: ReturnType<typeof useSearchParams>[1]
let rerender: () => void
function TestComponent() {
const reducerTuple = useReducer((state) => state + 1, 0)
const searchParamsTuple = useSearchParams()
setSearchParams = searchParamsTuple[1]
rerender = reducerTuple[1]
return null
}

await testStep('setSearchParams is memoized', async () => {
const container = document.createElement('div')
const root = createRoot(container)
root.render(<TestComponent />)
await new Promise((resolve) => setTimeout(resolve, 100))
const firstSetSearchParams = setSearchParams
rerender()
await new Promise((resolve) => setTimeout(resolve, 100))
expect(firstSetSearchParams).toBe(setSearchParams)
})
2 changes: 1 addition & 1 deletion exercises/03.custom-hooks/02.solution.callback/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { setGlobalSearchParams } from '#shared/utils'

const getQueryParam = (params: URLSearchParams) => params.get('query') ?? ''

function useSearchParams() {
export function useSearchParams() {
const [searchParams, setSearchParamsState] = useState(
() => new URLSearchParams(window.location.search),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test'
const { screen, fireEvent } = dtl

window.history.pushState({}, '', '?query=dog')

await import('./index.tsx')

await testStep(
'The search box is initialized with URL query parameter',
async () => {
const searchBox = await screen.findByRole('searchbox', { name: /search/i })
expect(searchBox).toHaveValue('dog')
},
)

await testStep(
'Updating the search box updates the URL search params',
async () => {
const searchBox = screen.getByRole('searchbox', { name: /search/i })
fireEvent.change(searchBox, { target: { value: 'cat' } })

expect(searchBox).toHaveValue('cat')
expect(window.location.search).toBe('?query=cat')
},
)
2 changes: 1 addition & 1 deletion exercises/04.context/01.problem.provider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { setGlobalSearchParams } from '#shared/utils'
// [new URLSearchParams(window.location.search), setGlobalSearchParams]

// 🐨 change this to SearchParamsProvider and accept children
function useSearchParams() {
export function useSearchParams() {
const [searchParams, setSearchParamsState] = useState(
() => new URLSearchParams(window.location.search),
)
Expand Down
30 changes: 30 additions & 0 deletions exercises/04.context/01.solution.provider/filtering.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test'
const { screen, fireEvent } = dtl

import './index.tsx'

const searchBox = await testStep(
'The user can see the search box',
async () => {
const result = await screen.findByRole('searchbox', { name: /search/i })
expect(result).toHaveValue('')
return result
},
)

const catResult = await testStep('The user can see the results', async () => {
const result = screen.getByText(/caring for your feline friend/i)
expect(result).toBeInTheDocument()
return result
})

await testStep('The user can search for a term', async () => {
fireEvent.change(searchBox, { target: { value: 'dog' } })
})

await testStep('The results are filtered', async () => {
await dtl.waitFor(() => {
expect(catResult).not.toBeInTheDocument()
})
await screen.findByText(/the joy of owning a dog/i)
})
2 changes: 1 addition & 1 deletion exercises/04.context/01.solution.provider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function SearchParamsProvider({ children }: { children: React.ReactNode }) {
)
}

function useSearchParams() {
export function useSearchParams() {
return use(SearchParamsContext)
}

Expand Down
2 changes: 1 addition & 1 deletion exercises/04.context/02.problem.hook/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function SearchParamsProvider({ children }: { children: React.ReactNode }) {
)
}

function useSearchParams() {
export function useSearchParams() {
const context = use(SearchParamsContext)
// 🐨 if there's no context value, the throw an error with a helpful error message
return context
Expand Down
30 changes: 30 additions & 0 deletions exercises/04.context/02.solution.hook/filtering.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test'
const { screen, fireEvent } = dtl

import './index.tsx'

const searchBox = await testStep(
'The user can see the search box',
async () => {
const result = await screen.findByRole('searchbox', { name: /search/i })
expect(result).toHaveValue('')
return result
},
)

const catResult = await testStep('The user can see the results', async () => {
const result = screen.getByText(/caring for your feline friend/i)
expect(result).toBeInTheDocument()
return result
})

await testStep('The user can search for a term', async () => {
fireEvent.change(searchBox, { target: { value: 'dog' } })
})

await testStep('The results are filtered', async () => {
await dtl.waitFor(() => {
expect(catResult).not.toBeInTheDocument()
})
await screen.findByText(/the joy of owning a dog/i)
})
2 changes: 1 addition & 1 deletion exercises/04.context/02.solution.hook/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function SearchParamsProvider({ children }: { children: React.ReactNode }) {
)
}

function useSearchParams() {
export function useSearchParams() {
const context = use(SearchParamsContext)
if (!context) {
throw new Error(
Expand Down
16 changes: 16 additions & 0 deletions exercises/05.portals/01.solution.create/portal.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test'
const { screen, fireEvent } = dtl

import './index.tsx'

await testStep('The portal is rendered to the body', async () => {
const [heartButton] = await screen.findAllByText('🤍')
heartButton.focus()

const tooltip = await screen.findByText('Add favorite')
expect(tooltip).toBeTruthy()
expect(
tooltip.closest('li'),
'🚨 The tooltip is still rendered inside the li',
).toBe(null)
})

0 comments on commit 9490a7e

Please sign in to comment.