-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f86ec0f
commit d2eaccf
Showing
15 changed files
with
404 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
exercises/06.layout-computation/01.solution.layout-effect/layout-effect.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test' | ||
const { screen, fireEvent, waitFor } = dtl | ||
|
||
import './index.tsx' | ||
|
||
await testStep('The portal is rendered to the body', async () => { | ||
const [heartButton] = await screen.findAllByText('🤍') | ||
|
||
const tooltipPromise = waitFor( | ||
() => { | ||
const tooltip = screen.getByText('Add favorite') | ||
return { tooltip, position: tooltip.getBoundingClientRect() } | ||
}, | ||
{ interval: 0 }, | ||
) | ||
|
||
fireEvent.focusIn(heartButton) | ||
|
||
const { tooltip, position } = await tooltipPromise | ||
|
||
await new Promise((resolve) => setTimeout(resolve, 250)) | ||
const newPosition = tooltip.getBoundingClientRect() | ||
|
||
expect( | ||
{ x: newPosition.x, y: newPosition.y }, | ||
'🚨 The tooltip is not correctly positioned initially. Use useLayoutEffect to prevent the incorrect position from being rendered.', | ||
).toEqual({ | ||
x: position.x, | ||
y: position.y, | ||
}) | ||
}) |
36 changes: 36 additions & 0 deletions
36
exercises/07.imperative-handle/01.solution.ref/scroll.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test' | ||
const { screen, fireEvent, waitFor } = dtl | ||
|
||
import './index.tsx' | ||
|
||
await testStep( | ||
'Scrollable component handles scroll to top and bottom', | ||
async () => { | ||
// Find the scroll buttons | ||
const scrollTopButton = await screen.findByText(/Scroll to Top/i) | ||
const scrollBottomButton = await screen.findByText(/Scroll to Bottom/i) | ||
|
||
// Find the scrollable container | ||
const scrollableContainer = screen.getByRole('log') | ||
|
||
// Scroll to bottom | ||
fireEvent.click(scrollBottomButton) | ||
await waitFor(() => { | ||
expect( | ||
scrollableContainer.scrollTop, | ||
'🚨 Scrollable container should be scrolled to the bottom when the scroll to bottom button is clicked', | ||
).toBe( | ||
scrollableContainer.scrollHeight - scrollableContainer.clientHeight, | ||
) | ||
}) | ||
|
||
// Scroll to top | ||
fireEvent.click(scrollTopButton) | ||
await waitFor(() => { | ||
expect( | ||
scrollableContainer.scrollTop, | ||
'🚨 Scrollable container should be scrolled to the top when the scroll to top button is clicked', | ||
).toBe(0) | ||
}) | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test' | ||
const { screen, fireEvent, waitFor } = dtl | ||
|
||
import './index.tsx' | ||
|
||
await testStep('EditableText component renders', async () => { | ||
const editButton = await screen.findByRole('button', { | ||
name: /Edit project name/i, | ||
}) | ||
expect(editButton).toBeTruthy() | ||
return editButton | ||
}) | ||
|
||
await testStep( | ||
'Clicking edit button focuses input and selects text', | ||
async () => { | ||
const editButton = await screen.findByRole('button', { | ||
name: /Edit project name/i, | ||
}) | ||
fireEvent.click(editButton) | ||
|
||
const input = screen.getByRole('textbox', { name: /Edit project name/i }) | ||
await waitFor(() => { | ||
expect( | ||
input, | ||
'🚨 Input should be focused after clicking edit button', | ||
).toHaveFocus() | ||
if (!(input instanceof HTMLInputElement)) { | ||
throw new Error('Input is not an HTMLInputElement') | ||
} | ||
expect( | ||
input.selectionStart, | ||
'🚨 Input text should be fully selected', | ||
).toBe(0) | ||
expect(input.selectionEnd, '🚨 Input text should be fully selected').toBe( | ||
input.value.length, | ||
) | ||
}) | ||
return input | ||
}, | ||
) | ||
|
||
await testStep('Submitting form focuses button', async () => { | ||
const input = await screen.findByRole('textbox', { | ||
name: /Edit project name/i, | ||
}) | ||
fireEvent.keyDown(input, { key: 'Enter' }) | ||
fireEvent.submit(input.closest('form')!) | ||
|
||
await waitFor(() => { | ||
const newButton = screen.getByRole('button', { name: /Edit project name/i }) | ||
expect( | ||
newButton, | ||
'🚨 Button should be focused after submitting', | ||
).toHaveFocus() | ||
}) | ||
}) | ||
|
||
await testStep('Canceling edit focuses button', async () => { | ||
const editButton = screen.getByRole('button', { name: /Edit project name/i }) | ||
fireEvent.click(editButton) | ||
|
||
const input = screen.getByRole('textbox', { name: /Edit project name/i }) | ||
fireEvent.keyDown(input, { key: 'Escape' }) | ||
|
||
await waitFor(() => { | ||
const newButton = screen.getByRole('button', { name: /Edit project name/i }) | ||
expect( | ||
newButton, | ||
'🚨 Button should be focused after canceling', | ||
).toHaveFocus() | ||
}) | ||
}) | ||
|
||
await testStep('Blurring input focuses button', async () => { | ||
const editButton = screen.getByRole('button', { name: /Edit project name/i }) | ||
fireEvent.click(editButton) | ||
|
||
const input = screen.getByRole('textbox', { name: /Edit project name/i }) | ||
fireEvent.blur(input) | ||
input.blur() | ||
|
||
await waitFor(() => { | ||
const newButton = screen.getByRole('button', { name: /Edit project name/i }) | ||
expect( | ||
newButton, | ||
'🚨 Button should be focused after blurring input', | ||
).toHaveFocus() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
exercises/09.sync-external/01.solution.sub/sync-media-query.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test' | ||
const { screen } = dtl | ||
|
||
import './index.tsx' | ||
|
||
let mediaQueryCallbacks: Array<(e: { matches: boolean }) => void> = [] | ||
let currentMatches = false | ||
|
||
const originalMatchMedia = window.matchMedia | ||
// @ts-expect-error - meh it's free javascript | ||
window.matchMedia = (query: string) => ({ | ||
...originalMatchMedia(query), | ||
matches: currentMatches, | ||
media: query, | ||
addEventListener: ( | ||
event: string, | ||
callback: (e: { matches: boolean }) => void, | ||
) => { | ||
mediaQueryCallbacks.push(callback) | ||
}, | ||
removeEventListener: ( | ||
event: string, | ||
callback: (e: { matches: boolean }) => void, | ||
) => { | ||
mediaQueryCallbacks = mediaQueryCallbacks.filter((cb) => cb !== callback) | ||
}, | ||
}) | ||
|
||
function triggerMediaQueryChange(matches: boolean) { | ||
currentMatches = matches | ||
mediaQueryCallbacks.forEach((callback) => callback({ matches })) | ||
} | ||
|
||
await testStep( | ||
'NarrowScreenNotifier renders wide screen message initially', | ||
async () => { | ||
const message = await screen.findByText('You are on a wide screen') | ||
expect(message).toBeTruthy() | ||
}, | ||
) | ||
|
||
await testStep( | ||
'NarrowScreenNotifier updates when media query changes to narrow', | ||
async () => { | ||
triggerMediaQueryChange(true) | ||
const message = await screen.findByText('You are on a narrow screen') | ||
expect(message).toBeTruthy() | ||
}, | ||
) | ||
|
||
await testStep( | ||
'NarrowScreenNotifier updates when media query changes back to wide', | ||
async () => { | ||
triggerMediaQueryChange(false) | ||
const message = await screen.findByText('You are on a wide screen') | ||
expect(message).toBeTruthy() | ||
}, | ||
) | ||
|
||
await testStep( | ||
'NarrowScreenNotifier removes event listener on unmount', | ||
async () => { | ||
const initialCallbackCount = mediaQueryCallbacks.length | ||
// @ts-expect-error 🚨 this is for the test | ||
window.__epicReactRoot.unmount() | ||
expect(mediaQueryCallbacks.length).toBe(initialCallbackCount - 1) | ||
}, | ||
) | ||
|
||
// Cleanup | ||
window.matchMedia = originalMatchMedia |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
exercises/09.sync-external/02.solution.util/sync-media-query.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test' | ||
const { screen } = dtl | ||
|
||
import './index.tsx' | ||
|
||
let mediaQueryCallbacks: Array<(e: { matches: boolean }) => void> = [] | ||
let currentMatches = false | ||
|
||
const originalMatchMedia = window.matchMedia | ||
// @ts-expect-error - meh it's free javascript | ||
window.matchMedia = (query: string) => ({ | ||
...originalMatchMedia(query), | ||
matches: currentMatches, | ||
media: query, | ||
addEventListener: ( | ||
event: string, | ||
callback: (e: { matches: boolean }) => void, | ||
) => { | ||
mediaQueryCallbacks.push(callback) | ||
}, | ||
removeEventListener: ( | ||
event: string, | ||
callback: (e: { matches: boolean }) => void, | ||
) => { | ||
mediaQueryCallbacks = mediaQueryCallbacks.filter((cb) => cb !== callback) | ||
}, | ||
}) | ||
|
||
function triggerMediaQueryChange(matches: boolean) { | ||
currentMatches = matches | ||
mediaQueryCallbacks.forEach((callback) => callback({ matches })) | ||
} | ||
|
||
await testStep( | ||
'NarrowScreenNotifier renders wide screen message initially', | ||
async () => { | ||
const message = await screen.findByText('You are on a wide screen') | ||
expect(message).toBeTruthy() | ||
}, | ||
) | ||
|
||
await testStep( | ||
'NarrowScreenNotifier updates when media query changes to narrow', | ||
async () => { | ||
triggerMediaQueryChange(true) | ||
const message = await screen.findByText('You are on a narrow screen') | ||
expect(message).toBeTruthy() | ||
}, | ||
) | ||
|
||
await testStep( | ||
'NarrowScreenNotifier updates when media query changes back to wide', | ||
async () => { | ||
triggerMediaQueryChange(false) | ||
const message = await screen.findByText('You are on a wide screen') | ||
expect(message).toBeTruthy() | ||
}, | ||
) | ||
|
||
await testStep( | ||
'NarrowScreenNotifier removes event listener on unmount', | ||
async () => { | ||
const initialCallbackCount = mediaQueryCallbacks.length | ||
// @ts-expect-error 🚨 this is for the test | ||
window.__epicReactRoot.unmount() | ||
expect(mediaQueryCallbacks.length).toBe(initialCallbackCount - 1) | ||
}, | ||
) | ||
|
||
// Cleanup | ||
window.matchMedia = originalMatchMedia |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.