Skip to content

Commit e2ac6c1

Browse files
committed
Update icons.
1 parent 9ac2174 commit e2ac6c1

11 files changed

Lines changed: 2287 additions & 1752 deletions

‎packages/ts-components/src/standard/virtualList/variableMeasurement.test.ts‎

Lines changed: 162 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -12,167 +12,172 @@ import {
1212
} from './virtualList'
1313

1414
describe('variable row measurements', () => {
15-
it.each([
16-
'list',
17-
'table',
18-
] as const)('keeps %s rows observed after the window updates', async (kind) => {
19-
const cleanupGlobals = ensureDomGlobals()
20-
const cleanupDom = createDom(
21-
'<html><body><div id="app"></div></body></html>',
22-
)
23-
const frames = new Map<number, FrameRequestCallback>()
24-
let frameId = 0
25-
const observers: TestResizeObserver[] = []
26-
const heights = new Map<Element, number>()
27-
class TestResizeObserver {
28-
readonly elements = new Set<Element>()
29-
constructor(readonly callback: ResizeObserverCallback) {
30-
observers.push(this)
31-
}
32-
observe(element: Element) {
33-
this.elements.add(element)
34-
element.getBoundingClientRect = () =>
35-
({ height: heights.get(element) ?? 40 }) as DOMRect
36-
}
37-
unobserve(element: Element) {
38-
this.elements.delete(element)
39-
}
40-
disconnect() {
41-
this.elements.clear()
42-
}
43-
resize(element: Element) {
44-
if (this.elements.has(element))
45-
this.callback(
46-
[{ target: element } as ResizeObserverEntry],
47-
this as unknown as ResizeObserver,
48-
)
15+
it.each(['list', 'table'] as const)(
16+
'keeps %s rows observed after the window updates',
17+
async (kind) => {
18+
const cleanupGlobals = ensureDomGlobals()
19+
const cleanupDom = createDom(
20+
'<html><body><div id="app"></div></body></html>',
21+
)
22+
const frames = new Map<number, FrameRequestCallback>()
23+
let frameId = 0
24+
const observers: TestResizeObserver[] = []
25+
const heights = new Map<Element, number>()
26+
class TestResizeObserver {
27+
readonly elements = new Set<Element>()
28+
constructor(readonly callback: ResizeObserverCallback) {
29+
observers.push(this)
30+
}
31+
observe(element: Element) {
32+
this.elements.add(element)
33+
element.getBoundingClientRect = () =>
34+
({ height: heights.get(element) ?? 40 }) as DOMRect
35+
}
36+
unobserve(element: Element) {
37+
this.elements.delete(element)
38+
}
39+
disconnect() {
40+
this.elements.clear()
41+
}
42+
resize(element: Element) {
43+
if (this.elements.has(element))
44+
this.callback(
45+
[{ target: element } as ResizeObserverEntry],
46+
this as unknown as ResizeObserver,
47+
)
48+
}
4949
}
50-
}
51-
vi.stubGlobal('ResizeObserver', TestResizeObserver)
52-
vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) => {
53-
frames.set(++frameId, callback)
54-
return frameId
55-
})
56-
vi.stubGlobal('cancelAnimationFrame', (id: number) => frames.delete(id))
57-
const flush = async () => {
58-
for (let pass = 0; pass < 20; pass++) {
59-
await Promise.resolve()
60-
if (!frames.size) return
61-
const pending = [...frames.values()]
62-
frames.clear()
63-
for (const callback of pending) callback(0)
50+
vi.stubGlobal('ResizeObserver', TestResizeObserver)
51+
vi.stubGlobal(
52+
'requestAnimationFrame',
53+
(callback: FrameRequestCallback) => {
54+
frames.set(++frameId, callback)
55+
return frameId
56+
},
57+
)
58+
vi.stubGlobal('cancelAnimationFrame', (id: number) => frames.delete(id))
59+
const flush = async () => {
60+
for (let pass = 0; pass < 20; pass++) {
61+
await Promise.resolve()
62+
if (!frames.size) return
63+
const pending = [...frames.values()]
64+
frames.clear()
65+
for (const callback of pending) callback(0)
66+
}
67+
throw new Error('Measurement did not settle')
6468
}
65-
throw new Error('Measurement did not settle')
66-
}
67-
let context: VariableVirtualList | VariableVirtualTable | undefined
68-
const recordContext = <
69-
T extends VariableVirtualList | VariableVirtualTable,
70-
>(
71-
candidate: Component<T>,
72-
) => {
73-
const original = candidate.context
74-
candidate.context = (head) => {
75-
const resolved = original(head)
76-
context = resolved
77-
return resolved
69+
let context: VariableVirtualList | VariableVirtualTable | undefined
70+
const recordContext = <
71+
T extends VariableVirtualList | VariableVirtualTable,
72+
>(
73+
candidate: Component<T>,
74+
) => {
75+
const original = candidate.context
76+
candidate.context = (head) => {
77+
const resolved = original(head)
78+
context = resolved
79+
return resolved
80+
}
81+
return candidate
7882
}
79-
return candidate
80-
}
81-
const component =
82-
kind === 'list'
83-
? recordContext(defineVirtualListComponents().variableVirtualList)
84-
: recordContext(
85-
defineVariableVirtualTableComponents().variableVirtualTable,
86-
)
87-
const viewportHeight = ref(160)
88-
let rowMounts = 0
89-
const app = createApp(
90-
{
91-
components: {
92-
Measured: component,
93-
Row: defineComponent(
94-
kind === 'list'
95-
? '<div>{{ item.label }}</div>'
96-
: '<tr><td>{{ item.label }}</td></tr>',
97-
{
98-
props: ['item', 'index'],
99-
context: (head) => {
100-
rowMounts++
101-
return head.props
102-
},
103-
},
104-
),
105-
},
106-
tsSsgContext: createTestContext(),
107-
items: Array.from({ length: 50000 }, (_, index) => ({
108-
label: `Row ${index}`,
109-
})),
110-
viewportHeight,
111-
},
112-
{
113-
selector: '#app',
114-
template:
115-
'<Measured :items="items" :height="viewportHeight" estimateHeight="80" overscan="2" rowComponent="Row" />',
116-
},
117-
)
118-
try {
119-
await flush()
120-
const beforeRows = context?.visibleRows?.() ?? []
121-
expect(beforeRows.length).toBeGreaterThan(0)
122-
const firstRow = beforeRows[0]
123-
const elements = observers.flatMap((observer) => [...observer.elements])
124-
expect(elements.length).toBeGreaterThan(0)
125-
if (kind === 'table')
126-
expect(elements.every((element) => element.tagName === 'TR')).toBe(true)
127-
const total = () =>
83+
const component =
12884
kind === 'list'
129-
? Number.parseFloat(
130-
(context as VariableVirtualList).spacerStyle?.().height ?? '0',
131-
)
132-
: Number.parseFloat(
133-
(context as VariableVirtualTable).bottomSpacerStyle?.().height ??
134-
'0',
85+
? recordContext(defineVirtualListComponents().variableVirtualList)
86+
: recordContext(
87+
defineVariableVirtualTableComponents().variableVirtualTable,
13588
)
136-
const initial = total()
137-
expect(initial).toBeLessThan(50000 * 80)
138-
viewportHeight(200)
139-
await flush()
140-
expect(context?.visibleRows?.()[0]).toBe(firstRow)
141-
const element = elements[0]
142-
const beforeResize = total()
143-
heights.set(element, 120)
144-
for (const observer of observers) observer.resize(element)
145-
await flush()
146-
expect(total()).toBeGreaterThan(beforeResize)
147-
expect(context?.visibleRows?.()[0]).toBe(firstRow)
148-
const emittedSizes: number[] = []
149-
const visibleRows = context?.visibleRows
150-
const viewport = context?.viewportElement?.()
151-
if (!visibleRows || !viewport)
152-
throw new Error('Virtual rows and viewport were not initialized')
153-
const stop = observe(visibleRows, (rows) => {
154-
emittedSizes.push(rows.length)
155-
})
156-
for (const position of [1000000, 1900000, 200000, 0]) {
157-
const beforeJump = rowMounts
158-
viewport.scrollTop = position
159-
viewport.dispatchEvent(new Event('scroll'))
160-
expect(visibleRows().length).toBeLessThan(20)
161-
expect(rowMounts - beforeJump).toBeLessThan(40)
162-
}
163-
stop()
164-
expect(emittedSizes.length).toBeGreaterThan(0)
165-
// Checking only the final window misses thousands of transient mounts.
166-
expect(Math.max(...emittedSizes)).toBeLessThan(20)
167-
app.unbind()
168-
expect(observers.every((observer) => observer.elements.size === 0)).toBe(
169-
true,
89+
const viewportHeight = ref(160)
90+
let rowMounts = 0
91+
const app = createApp(
92+
{
93+
components: {
94+
Measured: component,
95+
Row: defineComponent(
96+
kind === 'list'
97+
? '<div>{{ item.label }}</div>'
98+
: '<tr><td>{{ item.label }}</td></tr>',
99+
{
100+
props: ['item', 'index'],
101+
context: (head) => {
102+
rowMounts++
103+
return head.props
104+
},
105+
},
106+
),
107+
},
108+
tsSsgContext: createTestContext(),
109+
items: Array.from({ length: 50000 }, (_, index) => ({
110+
label: `Row ${index}`,
111+
})),
112+
viewportHeight,
113+
},
114+
{
115+
selector: '#app',
116+
template:
117+
'<Measured :items="items" :height="viewportHeight" estimateHeight="80" overscan="2" rowComponent="Row" />',
118+
},
170119
)
171-
} finally {
172-
app.unbind()
173-
vi.unstubAllGlobals()
174-
cleanupDom()
175-
cleanupGlobals()
176-
}
177-
})
120+
try {
121+
await flush()
122+
const beforeRows = context?.visibleRows?.() ?? []
123+
expect(beforeRows.length).toBeGreaterThan(0)
124+
const firstRow = beforeRows[0]
125+
const elements = observers.flatMap((observer) => [...observer.elements])
126+
expect(elements.length).toBeGreaterThan(0)
127+
if (kind === 'table')
128+
expect(elements.every((element) => element.tagName === 'TR')).toBe(
129+
true,
130+
)
131+
const total = () =>
132+
kind === 'list'
133+
? Number.parseFloat(
134+
(context as VariableVirtualList).spacerStyle?.().height ?? '0',
135+
)
136+
: Number.parseFloat(
137+
(context as VariableVirtualTable).bottomSpacerStyle?.()
138+
.height ?? '0',
139+
)
140+
const initial = total()
141+
expect(initial).toBeLessThan(50000 * 80)
142+
viewportHeight(200)
143+
await flush()
144+
expect(context?.visibleRows?.()[0]).toBe(firstRow)
145+
const element = elements[0]
146+
const beforeResize = total()
147+
heights.set(element, 120)
148+
for (const observer of observers) observer.resize(element)
149+
await flush()
150+
expect(total()).toBeGreaterThan(beforeResize)
151+
expect(context?.visibleRows?.()[0]).toBe(firstRow)
152+
const emittedSizes: number[] = []
153+
const visibleRows = context?.visibleRows
154+
const viewport = context?.viewportElement?.()
155+
if (!visibleRows || !viewport)
156+
throw new Error('Virtual rows and viewport were not initialized')
157+
const stop = observe(visibleRows, (rows) => {
158+
emittedSizes.push(rows.length)
159+
})
160+
for (const position of [1000000, 1900000, 200000, 0]) {
161+
const beforeJump = rowMounts
162+
viewport.scrollTop = position
163+
viewport.dispatchEvent(new Event('scroll'))
164+
expect(visibleRows().length).toBeLessThan(20)
165+
expect(rowMounts - beforeJump).toBeLessThan(40)
166+
}
167+
stop()
168+
expect(emittedSizes.length).toBeGreaterThan(0)
169+
// Checking only the final window misses thousands of transient mounts.
170+
expect(Math.max(...emittedSizes)).toBeLessThan(20)
171+
app.unbind()
172+
expect(
173+
observers.every((observer) => observer.elements.size === 0),
174+
).toBe(true)
175+
} finally {
176+
app.unbind()
177+
vi.unstubAllGlobals()
178+
cleanupDom()
179+
cleanupGlobals()
180+
}
181+
},
182+
)
178183
})

0 commit comments

Comments
 (0)