Skip to content

Commit d2eaccf

Browse files
committed
finish all tests
1 parent f86ec0f commit d2eaccf

File tree

15 files changed

+404
-7
lines changed

15 files changed

+404
-7
lines changed

exercises/05.portals/01.solution.create/portal.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import './index.tsx'
55

66
await testStep('The portal is rendered to the body', async () => {
77
const [heartButton] = await screen.findAllByText('🤍')
8-
heartButton.focus()
8+
fireEvent.focusIn(heartButton)
99

1010
const tooltip = await screen.findByText('Add favorite')
1111
expect(tooltip).toBeTruthy()
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test'
2+
const { screen, fireEvent, waitFor } = dtl
3+
4+
import './index.tsx'
5+
6+
await testStep('The portal is rendered to the body', async () => {
7+
const [heartButton] = await screen.findAllByText('🤍')
8+
9+
const tooltipPromise = waitFor(
10+
() => {
11+
const tooltip = screen.getByText('Add favorite')
12+
return { tooltip, position: tooltip.getBoundingClientRect() }
13+
},
14+
{ interval: 0 },
15+
)
16+
17+
fireEvent.focusIn(heartButton)
18+
19+
const { tooltip, position } = await tooltipPromise
20+
21+
await new Promise((resolve) => setTimeout(resolve, 250))
22+
const newPosition = tooltip.getBoundingClientRect()
23+
24+
expect(
25+
{ x: newPosition.x, y: newPosition.y },
26+
'🚨 The tooltip is not correctly positioned initially. Use useLayoutEffect to prevent the incorrect position from being rendered.',
27+
).toEqual({
28+
x: position.x,
29+
y: position.y,
30+
})
31+
})
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test'
2+
const { screen, fireEvent, waitFor } = dtl
3+
4+
import './index.tsx'
5+
6+
await testStep(
7+
'Scrollable component handles scroll to top and bottom',
8+
async () => {
9+
// Find the scroll buttons
10+
const scrollTopButton = await screen.findByText(/Scroll to Top/i)
11+
const scrollBottomButton = await screen.findByText(/Scroll to Bottom/i)
12+
13+
// Find the scrollable container
14+
const scrollableContainer = screen.getByRole('log')
15+
16+
// Scroll to bottom
17+
fireEvent.click(scrollBottomButton)
18+
await waitFor(() => {
19+
expect(
20+
scrollableContainer.scrollTop,
21+
'🚨 Scrollable container should be scrolled to the bottom when the scroll to bottom button is clicked',
22+
).toBe(
23+
scrollableContainer.scrollHeight - scrollableContainer.clientHeight,
24+
)
25+
})
26+
27+
// Scroll to top
28+
fireEvent.click(scrollTopButton)
29+
await waitFor(() => {
30+
expect(
31+
scrollableContainer.scrollTop,
32+
'🚨 Scrollable container should be scrolled to the top when the scroll to top button is clicked',
33+
).toBe(0)
34+
})
35+
},
36+
)

exercises/08.focus/01.problem.flush-sync/README.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,8 @@ test tab focus with. Good luck!
2929
This example was uses code from
3030
[trellix](https://github.com/remix-run/example-trellix/blob/3379b3d5e9c0173381031e4f062877e8a3696b2e/app/routes/board.%24id/components.tsx).
3131
</callout-info>
32+
33+
<callout-warning>
34+
🚨 Because this deals with focus, you'll need to expand the test and then run
35+
it for it to pass.
36+
</callout-warning>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test'
2+
const { screen, fireEvent, waitFor } = dtl
3+
4+
import './index.tsx'
5+
6+
await testStep('EditableText component renders', async () => {
7+
const editButton = await screen.findByRole('button', {
8+
name: /Edit project name/i,
9+
})
10+
expect(editButton).toBeTruthy()
11+
return editButton
12+
})
13+
14+
await testStep(
15+
'Clicking edit button focuses input and selects text',
16+
async () => {
17+
const editButton = await screen.findByRole('button', {
18+
name: /Edit project name/i,
19+
})
20+
fireEvent.click(editButton)
21+
22+
const input = screen.getByRole('textbox', { name: /Edit project name/i })
23+
await waitFor(() => {
24+
expect(
25+
input,
26+
'🚨 Input should be focused after clicking edit button',
27+
).toHaveFocus()
28+
if (!(input instanceof HTMLInputElement)) {
29+
throw new Error('Input is not an HTMLInputElement')
30+
}
31+
expect(
32+
input.selectionStart,
33+
'🚨 Input text should be fully selected',
34+
).toBe(0)
35+
expect(input.selectionEnd, '🚨 Input text should be fully selected').toBe(
36+
input.value.length,
37+
)
38+
})
39+
return input
40+
},
41+
)
42+
43+
await testStep('Submitting form focuses button', async () => {
44+
const input = await screen.findByRole('textbox', {
45+
name: /Edit project name/i,
46+
})
47+
fireEvent.keyDown(input, { key: 'Enter' })
48+
fireEvent.submit(input.closest('form')!)
49+
50+
await waitFor(() => {
51+
const newButton = screen.getByRole('button', { name: /Edit project name/i })
52+
expect(
53+
newButton,
54+
'🚨 Button should be focused after submitting',
55+
).toHaveFocus()
56+
})
57+
})
58+
59+
await testStep('Canceling edit focuses button', async () => {
60+
const editButton = screen.getByRole('button', { name: /Edit project name/i })
61+
fireEvent.click(editButton)
62+
63+
const input = screen.getByRole('textbox', { name: /Edit project name/i })
64+
fireEvent.keyDown(input, { key: 'Escape' })
65+
66+
await waitFor(() => {
67+
const newButton = screen.getByRole('button', { name: /Edit project name/i })
68+
expect(
69+
newButton,
70+
'🚨 Button should be focused after canceling',
71+
).toHaveFocus()
72+
})
73+
})
74+
75+
await testStep('Blurring input focuses button', async () => {
76+
const editButton = screen.getByRole('button', { name: /Edit project name/i })
77+
fireEvent.click(editButton)
78+
79+
const input = screen.getByRole('textbox', { name: /Edit project name/i })
80+
fireEvent.blur(input)
81+
input.blur()
82+
83+
await waitFor(() => {
84+
const newButton = screen.getByRole('button', { name: /Edit project name/i })
85+
expect(
86+
newButton,
87+
'🚨 Button should be focused after blurring input',
88+
).toHaveFocus()
89+
})
90+
})

exercises/09.sync-external/01.problem.sub/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,8 @@ function App() {
2222

2323
const rootEl = document.createElement('div')
2424
document.body.append(rootEl)
25-
ReactDOM.createRoot(rootEl).render(<App />)
25+
const root = ReactDOM.createRoot(rootEl)
26+
root.render(<App />)
27+
28+
// @ts-expect-error 🚨 this is for the test
29+
window.__epicReactRoot = root

exercises/09.sync-external/01.solution.sub/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,8 @@ function App() {
2525

2626
const rootEl = document.createElement('div')
2727
document.body.append(rootEl)
28-
ReactDOM.createRoot(rootEl).render(<App />)
28+
const root = ReactDOM.createRoot(rootEl)
29+
root.render(<App />)
30+
31+
// @ts-expect-error 🚨 this is for the test
32+
window.__epicReactRoot = root
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test'
2+
const { screen } = dtl
3+
4+
import './index.tsx'
5+
6+
let mediaQueryCallbacks: Array<(e: { matches: boolean }) => void> = []
7+
let currentMatches = false
8+
9+
const originalMatchMedia = window.matchMedia
10+
// @ts-expect-error - meh it's free javascript
11+
window.matchMedia = (query: string) => ({
12+
...originalMatchMedia(query),
13+
matches: currentMatches,
14+
media: query,
15+
addEventListener: (
16+
event: string,
17+
callback: (e: { matches: boolean }) => void,
18+
) => {
19+
mediaQueryCallbacks.push(callback)
20+
},
21+
removeEventListener: (
22+
event: string,
23+
callback: (e: { matches: boolean }) => void,
24+
) => {
25+
mediaQueryCallbacks = mediaQueryCallbacks.filter((cb) => cb !== callback)
26+
},
27+
})
28+
29+
function triggerMediaQueryChange(matches: boolean) {
30+
currentMatches = matches
31+
mediaQueryCallbacks.forEach((callback) => callback({ matches }))
32+
}
33+
34+
await testStep(
35+
'NarrowScreenNotifier renders wide screen message initially',
36+
async () => {
37+
const message = await screen.findByText('You are on a wide screen')
38+
expect(message).toBeTruthy()
39+
},
40+
)
41+
42+
await testStep(
43+
'NarrowScreenNotifier updates when media query changes to narrow',
44+
async () => {
45+
triggerMediaQueryChange(true)
46+
const message = await screen.findByText('You are on a narrow screen')
47+
expect(message).toBeTruthy()
48+
},
49+
)
50+
51+
await testStep(
52+
'NarrowScreenNotifier updates when media query changes back to wide',
53+
async () => {
54+
triggerMediaQueryChange(false)
55+
const message = await screen.findByText('You are on a wide screen')
56+
expect(message).toBeTruthy()
57+
},
58+
)
59+
60+
await testStep(
61+
'NarrowScreenNotifier removes event listener on unmount',
62+
async () => {
63+
const initialCallbackCount = mediaQueryCallbacks.length
64+
// @ts-expect-error 🚨 this is for the test
65+
window.__epicReactRoot.unmount()
66+
expect(mediaQueryCallbacks.length).toBe(initialCallbackCount - 1)
67+
},
68+
)
69+
70+
// Cleanup
71+
window.matchMedia = originalMatchMedia

exercises/09.sync-external/02.problem.util/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,8 @@ function App() {
3434

3535
const rootEl = document.createElement('div')
3636
document.body.append(rootEl)
37-
ReactDOM.createRoot(rootEl).render(<App />)
37+
const root = ReactDOM.createRoot(rootEl)
38+
root.render(<App />)
39+
40+
// @ts-expect-error 🚨 this is for the test
41+
window.__epicReactRoot = root

exercises/09.sync-external/02.solution.util/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,8 @@ function App() {
3232

3333
const rootEl = document.createElement('div')
3434
document.body.append(rootEl)
35-
ReactDOM.createRoot(rootEl).render(<App />)
35+
const root = ReactDOM.createRoot(rootEl)
36+
root.render(<App />)
37+
38+
// @ts-expect-error 🚨 this is for the test
39+
window.__epicReactRoot = root

0 commit comments

Comments
 (0)