Skip to content

Commit 774b83a

Browse files
committed
get a good test for 04.01
1 parent 4dd50e0 commit 774b83a

File tree

4 files changed

+109
-3
lines changed

4 files changed

+109
-3
lines changed

exercises/04.image/01.problem.img/README.mdx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
- Set the playground to this exercise
99
- <LinkToApp to="/">Open the playground</LinkToApp> (in a separate tab)
1010
- Open the dev tools
11-
- Right-click the refresh button and select ["Empty Cache and Hard Reload"](https://stackoverflow.com/questions/14969315/whats-the-difference-between-normal-reload-hard-reload-and-empty-cache-a)
11+
- Notice that we've added a version query parameter to the images to simulate
12+
initial loading. This is why you see a different versions in the URL for
13+
each image.
1214
- [Throttle your network](https://developer.chrome.com/docs/devtools/network/reference#throttling) speed in the dev tools to "Slow 3G"
1315
- Click a separate ship
1416

@@ -24,3 +26,9 @@ Suspense, the `use` hook, and a `preloadImage` utility.
2426
The emoji will guide you through this one.
2527
Best to start in <InlineFile file="utils.tsx" />. Lots of this will feel similar
2628
to what we were doing with the `getShip` regarding the caching stuff!
29+
30+
<callout-warning>
31+
🚨 Note, this is extremely difficult to test, so the test may be unreliable.
32+
However, if you do throttle the network, then the test will be much more
33+
reliable.
34+
</callout-warning>

exercises/04.image/01.problem.img/utils.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,12 @@ async function getShipImpl(name: string, delay?: number) {
3838
// })
3939
// }
4040

41+
// added the version to prevent caching to make testing easier
42+
const version = Date.now()
43+
4144
export function getImageUrlForShip(
4245
shipName: string,
4346
{ size }: { size: number },
4447
) {
45-
return `/img/ships/${shipName.toLowerCase().replaceAll(' ', '-')}.webp?size=${size}`
48+
return `/img/ships/${shipName.toLowerCase().replaceAll(' ', '-')}.webp?size=${size}&v=${version}`
4649
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { expect, testStep, dtl } from '@epic-web/workshop-utils/test'
2+
const { screen, waitFor, fireEvent } = dtl
3+
4+
import './index.tsx'
5+
6+
function onLoad(img: HTMLElement, cb?: () => void) {
7+
return new Promise<void>((resolve) => {
8+
img.addEventListener(
9+
'load',
10+
() => {
11+
cb?.()
12+
resolve()
13+
},
14+
{ once: true },
15+
)
16+
})
17+
}
18+
19+
await testStep('Initial ship details are loaded', async () => {
20+
await screen.findByRole('heading', { name: /Dreadnought/i })
21+
await waitFor(
22+
() => expect(screen.queryAllByText('loading')).toHaveLength(0),
23+
{ timeout: 5000 },
24+
)
25+
await onLoad(screen.getByAltText('Dreadnought'))
26+
await new Promise((resolve) => setTimeout(resolve, 250))
27+
})
28+
29+
const img = await testStep('Initial image is loaded', async () => {
30+
const img = await screen.findByAltText('Dreadnought')
31+
expect(img, '🚨 Initial image should be present').toBeInTheDocument()
32+
return img
33+
})
34+
35+
const initialSrc = img.getAttribute('src')
36+
37+
let loadTime = 0,
38+
srcChangeTime = 0
39+
40+
const loadAndSrcChange = Promise.all([
41+
onLoad(img).then(() => {
42+
loadTime = Date.now()
43+
}),
44+
waitFor(
45+
() => {
46+
expect(img.getAttribute('src')).not.toBe(initialSrc)
47+
srcChangeTime = Date.now()
48+
},
49+
{ timeout: 4000 },
50+
),
51+
])
52+
53+
await testStep('Click on a different ship', async () => {
54+
fireEvent.click(screen.getByRole('button', { name: 'Interceptor' }))
55+
})
56+
57+
await testStep('New ship details are loaded', async () => {
58+
await screen.findByRole(
59+
'heading',
60+
{ name: /Interceptor/i },
61+
{ timeout: 4000 },
62+
)
63+
})
64+
65+
const newImg = await testStep('New image element is present', async () => {
66+
const img = await screen.findByAltText('Interceptor')
67+
expect(img, '🚨 New image element should be present').toBeInTheDocument()
68+
return img
69+
})
70+
71+
await testStep('Verify image src has changed', async () => {
72+
await waitFor(() => {
73+
expect(
74+
newImg.getAttribute('src'),
75+
'🚨 Image src should change after load event',
76+
).not.toBe(initialSrc)
77+
expect(
78+
newImg.getAttribute('src'),
79+
'🚨 New image src should contain "interceptor"',
80+
).toMatch(/interceptor/)
81+
})
82+
})
83+
84+
// put this last so it doesn't affect the other steps
85+
await testStep('img was loaded before the src changed.', async () => {
86+
await loadAndSrcChange
87+
console.log(loadTime - srcChangeTime)
88+
expect(
89+
loadTime - srcChangeTime,
90+
'🚨 the img should be loaded before the src changes. Make sure to suspend until the img is loaded.',
91+
).toBeLessThan(4)
92+
})

exercises/04.image/01.solution.img/utils.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,12 @@ function preloadImage(src: string) {
3838
})
3939
}
4040

41+
// added the version to prevent caching to make testing easier
42+
const version = Date.now()
43+
4144
export function getImageUrlForShip(
4245
shipName: string,
4346
{ size }: { size: number },
4447
) {
45-
return `/img/ships/${shipName.toLowerCase().replaceAll(' ', '-')}.webp?size=${size}`
48+
return `/img/ships/${shipName.toLowerCase().replaceAll(' ', '-')}.webp?size=${size}&v=${version}`
4649
}

0 commit comments

Comments
 (0)