Files
orca/tests/e2e/github-work-item-search-burst.unit.test.ts
T
Brennan Benson b029fb61ab Keep GitHub Tasks source changes consistent (#37387)
Keep the GitHub Tasks source picker, rows, totals, searches and issue creation tied to the selected project, host and source. Ignore outdated replies and wait for source preference saves before creating an issue. Preserve support for older paired servers.

Tracked in #8726. Tracked in STA-1815.
2026-11-03 13:26:23 -08:00

93 lines
3.4 KiB
TypeScript

import { z } from 'zod'
import { expect, it } from 'vitest'
import { join } from 'node:path'
import { api } from '../../src/main/github/work-item-search-test-harness'
import { listWorkItems } from '../../src/main/github/client/list/list-work-items'
import { countWorkItems } from '../../src/main/github/client/list/count-work-items'
import {
createTestStore,
mockApi
} from '../../src/renderer/src/store/slices/github-slice-test-harness'
import { answered } from '../../src/renderer/src/store/github/answered-request.test-fixture'
const repos = Array.from({ length: 36 }, (_, index) => ({
repoId: `repo-${index}`,
path: join('fixture', `repo-${index}`)
}))
function connectedStore() {
mockApi.gh.listWorkItems.mockImplementation((...params: unknown[]) => {
const args = z
.object({
repoPath: z.string(),
limit: z.number(),
query: z.string().optional(),
page: z.number().optional(),
noCache: z.boolean().optional()
})
.parse(params[0])
return listWorkItems(
args.repoPath,
args.limit,
args.query,
args.page,
undefined,
undefined,
args.noCache
)
})
mockApi.gh.countWorkItems.mockImplementation((...params: unknown[]) => {
const args = z.object({ repoPath: z.string(), query: z.string().optional() }).parse(params[0])
return countWorkItems(args.repoPath, args.query)
})
return createTestStore()
}
it.each(['counts-first', 'lists-first'] as const)(
'returns every repo and full totals with %s',
async (order) => {
const store = connectedStore()
const lists = () =>
store.getState().fetchWorkItemsAcrossRepos(repos, 24, 1000, '', { force: true })
const counts = () => store.getState().countWorkItemsAcrossRepos(repos, '', 24)
const pending =
order === 'counts-first'
? { total: counts(), items: lists() }
: { items: lists(), total: counts() }
const [listed, total] = await Promise.all([pending.items, pending.total])
const items = answered(listed)
expect(items).toMatchObject({ failedCount: 0 })
expect(items.items).toHaveLength(36 * 24)
expect(new Set(items.items.map((item) => item.repoId)).size).toBe(36)
expect(total).toEqual({ totalCount: 36 * 120, totalPages: 5 })
expect(api.restSearches).toBe(0)
expect(api.rejected).toBe(0)
expect(api.calls.some(({ args }) => args[0] === 'pr')).toBe(false)
expect(api.graphqlCalls).toBeLessThanOrEqual(72)
}
)
it('retains all repos on repeat, bypass-cache refresh and independent page jumps', async () => {
const store = connectedStore()
const fetch = async (noCache = false) =>
answered(
await store
.getState()
.fetchWorkItemsAcrossRepos(repos, 24, 1000, 'is:issue is:open', { force: true, noCache })
)
expect((await fetch()).items).toHaveLength(36 * 24)
const firstCalls = api.graphqlCalls
expect((await fetch()).items).toHaveLength(36 * 24)
expect(api.graphqlCalls).toBe(firstCalls)
for (let repeat = 0; repeat < 3; repeat++) {
expect((await fetch(true)).items).toHaveLength(36 * 24)
}
expect(api.graphqlCalls).toBe(firstCalls + 3 * 36)
const page3 = answered(
await store.getState().fetchWorkItemsNextPage(repos, 24, 1000, 'is:issue is:open', 3)
)
expect(page3.items).toHaveLength(36 * 24)
expect(page3.items.every((item) => item.number <= 9952 && item.number >= 9929)).toBe(true)
expect(page3.failedCount).toBe(0)
expect(api.restSearches).toBe(0)
})