Skip to content

Commit d6c2b7f

Browse files
committed
bench(useGroup): add benchmark tests
1 parent f4bcb78 commit d6c2b7f

File tree

2 files changed

+218
-0
lines changed

2 files changed

+218
-0
lines changed
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// Composables
2+
import { useGroup } from './index'
3+
4+
// Utilities
5+
import { describe, it, expect } from 'vitest'
6+
import { run, compare } from '#v0/utilities/benchmark'
7+
8+
describe('useGroup benchmarks', () => {
9+
it('should benchmark registration operations', async () => {
10+
const context = useGroup('benchmark-test')[2]
11+
12+
const result = await run('register 1000 group items', () => {
13+
for (let i = 0; i < 1000; i++) {
14+
context.register({ value: `item-${i}`, disabled: false })
15+
}
16+
}, 10)
17+
18+
expect(result.name).toBe('register 1000 group items')
19+
expect(result.duration).toBeGreaterThan(0)
20+
expect(result.ops).toBeGreaterThan(0)
21+
22+
console.log(`Group Registration: ${result.ops} ops/sec (${result.duration.toFixed(2)}ms avg)`)
23+
})
24+
25+
it('should benchmark selection operations', async () => {
26+
const context = useGroup('benchmark-test')[2]
27+
28+
// Pre-populate with items
29+
const ids: (string | number)[] = []
30+
for (let i = 0; i < 1000; i++) {
31+
const item = context.register({ value: `item-${i}`, disabled: false })
32+
ids.push(item.id)
33+
}
34+
35+
const result = await run('select 1000 items', () => {
36+
for (const id of ids) {
37+
context.select(id)
38+
}
39+
}, 10)
40+
41+
expect(result.name).toBe('select 1000 items')
42+
expect(result.duration).toBeGreaterThan(0)
43+
expect(result.ops).toBeGreaterThan(0)
44+
45+
console.log(`Selection: ${result.ops} ops/sec (${result.duration.toFixed(2)}ms avg)`)
46+
})
47+
48+
it('should benchmark browse operations', async () => {
49+
const context = useGroup('benchmark-test')[2]
50+
51+
// Pre-populate with items
52+
for (let i = 0; i < 1000; i++) {
53+
context.register({ value: `item-${i}`, disabled: false })
54+
}
55+
56+
const result = await run('browse 1000 values', () => {
57+
for (let i = 0; i < 1000; i++) {
58+
context.browse(`item-${i}`)
59+
}
60+
}, 10)
61+
62+
expect(result.name).toBe('browse 1000 values')
63+
expect(result.duration).toBeGreaterThan(0)
64+
expect(result.ops).toBeGreaterThan(0)
65+
66+
console.log(`Browse: ${result.ops} ops/sec (${result.duration.toFixed(2)}ms avg)`)
67+
})
68+
69+
it('should benchmark multiple selection operations', async () => {
70+
const context = useGroup('benchmark-test-multiple', { multiple: true })[2]
71+
72+
// Pre-populate with items
73+
const ids: (string | number)[] = []
74+
for (let i = 0; i < 100; i++) {
75+
const item = context.register({ value: `item-${i}`, disabled: false })
76+
ids.push(item.id)
77+
}
78+
79+
const result = await run('select multiple 100 items', () => {
80+
context.select(ids)
81+
}, 50)
82+
83+
expect(result.name).toBe('select multiple 100 items')
84+
expect(result.duration).toBeGreaterThan(0)
85+
expect(result.ops).toBeGreaterThan(0)
86+
87+
console.log(`Multiple Selection: ${result.ops} ops/sec (${result.duration.toFixed(2)}ms avg)`)
88+
})
89+
90+
it('should benchmark reset operations', async () => {
91+
const context = useGroup('benchmark-test')[2]
92+
93+
// Pre-populate with items and selections
94+
for (let i = 0; i < 1000; i++) {
95+
const item = context.register({ value: `item-${i}`, disabled: false })
96+
if (i % 10 === 0) context.select(item.id)
97+
}
98+
99+
const result = await run('reset 1000 items', () => {
100+
context.reset()
101+
}, 100)
102+
103+
expect(result.name).toBe('reset 1000 items')
104+
expect(result.duration).toBeGreaterThan(0)
105+
expect(result.ops).toBeGreaterThan(0)
106+
107+
console.log(`Reset: ${result.ops} ops/sec (${result.duration.toFixed(2)}ms avg)`)
108+
})
109+
110+
it('should benchmark mandate operations', async () => {
111+
const context = useGroup('benchmark-test-mandatory', { mandatory: true })[2]
112+
113+
// Pre-populate with items
114+
for (let i = 0; i < 1000; i++) {
115+
context.register({ value: `item-${i}`, disabled: i % 100 === 0 })
116+
}
117+
118+
const result = await run('mandate selection', () => {
119+
context.selectedIds.clear()
120+
context.mandate()
121+
}, 100)
122+
123+
expect(result.name).toBe('mandate selection')
124+
expect(result.duration).toBeGreaterThan(0)
125+
expect(result.ops).toBeGreaterThan(0)
126+
127+
console.log(`Mandate: ${result.ops} ops/sec (${result.duration.toFixed(2)}ms avg)`)
128+
})
129+
130+
it('should compare different group operation types', async () => {
131+
const context = useGroup('benchmark-test')[2]
132+
133+
// Pre-populate for operations
134+
const items: any[] = []
135+
for (let i = 0; i < 100; i++) {
136+
const item = context.register({ value: `item-${i}`, disabled: false })
137+
items.push(item)
138+
}
139+
140+
const results = await compare({
141+
'register 100 group items': () => {
142+
const ctx = useGroup('register-test')[2]
143+
for (let i = 0; i < 100; i++) {
144+
ctx.register({ value: `item-${i}`, disabled: false })
145+
}
146+
},
147+
'select 100 items': () => {
148+
for (const item of items) {
149+
context.select(item.id)
150+
}
151+
},
152+
'browse 100 values': () => {
153+
for (let i = 0; i < 100; i++) {
154+
context.browse(`item-${i}`)
155+
}
156+
},
157+
'reset 100 items': () => {
158+
context.reset()
159+
},
160+
})
161+
162+
expect(results).toHaveLength(4)
163+
164+
console.log('Group operation comparison (fastest to slowest):')
165+
for (const [index, result] of results.entries()) {
166+
console.log(`${index + 1}. ${result.name}: ${result.ops} ops/sec`)
167+
}
168+
})
169+
170+
it('should benchmark different group sizes', async () => {
171+
const sizes = [10, 100, 1000, 5000]
172+
173+
console.log('Group registration performance by collection size:')
174+
175+
for (const size of sizes) {
176+
const context = useGroup(`benchmark-size-${size}`)[2]
177+
178+
const result = await run(`register ${size} group items`, () => {
179+
for (let i = 0; i < size; i++) {
180+
context.register({ value: `item-${i}`, disabled: false })
181+
}
182+
}, 5)
183+
184+
console.log(`Size ${size}: ${result.ops} ops/sec (${result.duration.toFixed(2)}ms avg)`)
185+
186+
expect(result.ops).toBeGreaterThan(0)
187+
}
188+
})
189+
190+
it('should benchmark different group configurations', async () => {
191+
const configs = [
192+
{ name: 'default', options: {} },
193+
{ name: 'multiple', options: { multiple: true } },
194+
{ name: 'mandatory', options: { mandatory: true } },
195+
{ name: 'returnObject', options: { returnObject: true } },
196+
{ name: 'multiple + mandatory', options: { multiple: true, mandatory: true } },
197+
]
198+
199+
console.log('Group registration performance by configuration:')
200+
201+
for (const config of configs) {
202+
const context = useGroup(`benchmark-config-${config.name}`, config.options)[2]
203+
204+
const result = await run(`register 500 items (${config.name})`, () => {
205+
for (let i = 0; i < 500; i++) {
206+
context.register({ value: `item-${i}`, disabled: false })
207+
}
208+
}, 5)
209+
210+
console.log(`${config.name}: ${result.ops} ops/sec (${result.duration.toFixed(2)}ms avg)`)
211+
212+
expect(result.ops).toBeGreaterThan(0)
213+
}
214+
})
215+
})

packages/0/src/composables/useGroup/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export type GroupContext = RegistrarContext & {
2727
selectedIndexes: ComputedRef<Set<number>>
2828
selectedIds: Reactive<Set<ID>>
2929
selectedValues: ComputedRef<Set<unknown>>
30+
/** Register a new item */
3031
register: (item?: Partial<GroupTicket>, id?: ID) => Reactive<GroupTicket>
3132
/** Select the first available value */
3233
mandate: () => void
@@ -97,7 +98,9 @@ export function useGroup<
9798

9899
if (options.mandatory === 'force') {
99100
const first = registrar.collection.values().next().value
101+
100102
if (first) selectedIds.add(first.id)
103+
101104
return
102105
}
103106

0 commit comments

Comments
 (0)