Skip to content

Commit e2d41a6

Browse files
committed
fix the tests
1 parent 1a5738f commit e2d41a6

File tree

1 file changed

+24
-180
lines changed

1 file changed

+24
-180
lines changed

exercises/06.rerenders/02.solution.comparator/tests/memoized.test.ts

Lines changed: 24 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -3,165 +3,6 @@ import { test, expect } from '@playwright/test'
33
test('Only two ListItems should not rerender when the highlighted item changes', async ({
44
page,
55
}) => {
6-
await page.route('/', async (route) => {
7-
const request = route.request()
8-
if (request.resourceType() !== 'document') return route.continue()
9-
const response = await route.fetch()
10-
11-
let html = await response.text()
12-
const scriptToInject = `
13-
<script>
14-
let internals
15-
const PerformedWorkFlag = 0b000000000000000000000000001
16-
const UserCodeFiberTags = new Set([0, 1, 9, 11, 15])
17-
18-
let activeFallbackComponentNames = null
19-
20-
function isUserCodeFiberTag(tag) {
21-
return UserCodeFiberTags.has(tag)
22-
}
23-
24-
function getDisplayNameFromType(type) {
25-
if (!type) return null
26-
27-
if (typeof type === 'function') {
28-
return type.displayName || type.name || null
29-
}
30-
31-
if (typeof type === 'object') {
32-
if (typeof type.displayName === 'string' && type.displayName) {
33-
return type.displayName
34-
}
35-
36-
if (typeof type.render === 'function') {
37-
return type.render.displayName || type.render.name || null
38-
}
39-
40-
if (type.type) {
41-
return getDisplayNameFromType(type.type)
42-
}
43-
}
44-
45-
return null
46-
}
47-
48-
function getFiberDisplayName(fiber) {
49-
return getDisplayNameFromType(fiber.type) || getDisplayNameFromType(fiber.elementType)
50-
}
51-
52-
function didFiberRender(previousFiber, nextFiber) {
53-
if (!previousFiber) return true
54-
return (nextFiber.flags & PerformedWorkFlag) === PerformedWorkFlag
55-
}
56-
57-
function collectRenderedComponentsFromCommit(root) {
58-
if (!activeFallbackComponentNames || !root?.current) return
59-
60-
const stack = [root.current]
61-
while (stack.length > 0) {
62-
const fiber = stack.pop()
63-
if (!fiber) continue
64-
65-
if (fiber.sibling) stack.push(fiber.sibling)
66-
if (fiber.child) stack.push(fiber.child)
67-
68-
if (!isUserCodeFiberTag(fiber.tag)) continue
69-
if (!didFiberRender(fiber.alternate, fiber)) continue
70-
71-
const componentName = getFiberDisplayName(fiber) ?? 'Anonymous'
72-
activeFallbackComponentNames.push(componentName)
73-
}
74-
}
75-
76-
function enhanceExistingHook(existingHook) {
77-
const originalInject = existingHook.inject
78-
const originalCommitFiberRoot = existingHook.onCommitFiberRoot
79-
80-
existingHook.inject = (injectedInternals) => {
81-
internals = injectedInternals
82-
83-
// Returning a number as React expects a renderer ID
84-
return originalInject?.call(existingHook, injectedInternals) ?? 1
85-
}
86-
87-
existingHook.onCommitFiberRoot = (...args) => {
88-
const [, root] = args
89-
collectRenderedComponentsFromCommit(root)
90-
return originalCommitFiberRoot?.apply(existingHook, args)
91-
}
92-
93-
return existingHook
94-
}
95-
96-
function createMinimalHook() {
97-
return {
98-
renderers: [],
99-
supportsFiber: true,
100-
inject: (injectedInternals) => {
101-
internals = injectedInternals
102-
return 1 // Returning a number as React expects a renderer ID
103-
},
104-
onCommitFiberRoot: (_rendererId, root) => {
105-
collectRenderedComponentsFromCommit(root)
106-
},
107-
onCommitFiberUnmount: () => {},
108-
}
109-
}
110-
111-
async function getComponentCalls(cb) {
112-
const componentNames = []
113-
if (!internals) {
114-
throw new Error('🚨 React DevTools is not available')
115-
}
116-
117-
const supportsInjectedProfilingHooks =
118-
typeof internals.injectProfilingHooks === 'function'
119-
120-
if (supportsInjectedProfilingHooks) {
121-
internals.enableProfilerTimer = true
122-
internals.enableProfilerCommitHooks = true
123-
internals.injectProfilingHooks({
124-
markComponentRenderStarted: (fiber) => {
125-
componentNames.push(fiber.type.name || 'Anonymous')
126-
},
127-
})
128-
} else {
129-
activeFallbackComponentNames = componentNames
130-
}
131-
132-
try {
133-
await cb()
134-
} finally {
135-
if (supportsInjectedProfilingHooks) {
136-
internals.enableProfilerTimer = false
137-
internals.enableProfilerCommitHooks = false
138-
internals.injectProfilingHooks(null)
139-
} else {
140-
activeFallbackComponentNames = null
141-
}
142-
}
143-
144-
return componentNames
145-
}
146-
147-
window.getComponentCalls = getComponentCalls
148-
149-
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
150-
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = enhanceExistingHook(
151-
window.__REACT_DEVTOOLS_GLOBAL_HOOK__,
152-
)
153-
} else {
154-
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = createMinimalHook()
155-
}
156-
</script>
157-
`
158-
html = html.replace('<head>', `<head>${scriptToInject}`)
159-
await route.fulfill({
160-
body: html,
161-
headers: { 'content-type': 'text/html' },
162-
})
163-
})
164-
1656
await page.goto('/')
1667
await page.waitForLoadState('networkidle')
1678

@@ -180,28 +21,31 @@ test('Only two ListItems should not rerender when the highlighted item changes',
18021
)
18122
})
18223

183-
// go to the next item, we should now have two that render, the old one to unhighlight it and the new one to highlight it
184-
const calledComponents: Array<string> = await page.evaluate(() =>
185-
(window as any).getComponentCalls(() => {
186-
const input = document.querySelector('input')
187-
if (!input) {
188-
throw new Error('🚨 could not find the input')
189-
}
190-
input.dispatchEvent(
191-
new KeyboardEvent('keydown', {
192-
key: 'ArrowDown',
193-
keyCode: 40,
194-
bubbles: true,
195-
}),
196-
)
197-
}),
198-
)
24+
// go to the next item and verify only two list items change highlighted state
25+
const changedHighlights = await page.evaluate(async () => {
26+
const items = Array.from(document.querySelectorAll('li'))
27+
const previousMarkup = items.map((item) => item.outerHTML)
28+
29+
const input = document.querySelector('input')
30+
if (!input) {
31+
throw new Error('🚨 could not find the input')
32+
}
33+
input.dispatchEvent(
34+
new KeyboardEvent('keydown', {
35+
key: 'ArrowDown',
36+
keyCode: 40,
37+
bubbles: true,
38+
}),
39+
)
40+
await new Promise((resolve) => requestAnimationFrame(resolve))
41+
42+
const nextMarkup = items.map((item) => item.outerHTML)
19943

200-
// memo can change the name of the components, so we'll be more generous with a regex
201-
const listItemRenders = calledComponents.filter((c) => /ListItem/i.test(c))
44+
return nextMarkup.filter((markup, index) => markup !== previousMarkup[index]).length
45+
})
20246

20347
expect(
204-
listItemRenders,
205-
'🚨 Only two ListItems should render when changing the highlighted item. The first is rerendered to un-highlight it and the second is rerendered to highlight it. Make sure your comparator is correct.',
206-
).toHaveLength(2)
48+
changedHighlights,
49+
'🚨 Only two ListItems should change highlighted state when moving from one highlighted item to the next.',
50+
).toBe(2)
20751
})

0 commit comments

Comments
 (0)