mirror of
https://github.com/stablyai/orca.git
synced 2026-10-16 08:03:09 +00:00
122 lines
3.8 KiB
TypeScript
122 lines
3.8 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const { acquireMock, ghExecFileAsyncMock, releaseMock, runRestMock } = vi.hoisted(() => ({
|
|
acquireMock: vi.fn(),
|
|
ghExecFileAsyncMock: vi.fn(),
|
|
releaseMock: vi.fn(),
|
|
runRestMock: vi.fn()
|
|
}))
|
|
|
|
vi.mock('./internals', () => ({
|
|
acquire: acquireMock,
|
|
release: releaseMock,
|
|
extractExecError: (err: unknown) => ({
|
|
stderr: err instanceof Error ? err.message : String(err),
|
|
stdout: ''
|
|
}),
|
|
ghExecFileAsync: ghExecFileAsyncMock,
|
|
rateLimitGuard: () => ({ blocked: false }),
|
|
noteRateLimitSpend: vi.fn(),
|
|
classifyProjectError: (stderr: string) => ({ type: 'unknown', message: stderr }),
|
|
rateLimitedError: () => ({ type: 'rate_limited', message: 'rate limited' }),
|
|
runGraphql: vi.fn(),
|
|
runRest: runRestMock,
|
|
validateSlugArgs: (owner: string, repo: string) =>
|
|
owner && repo ? { ok: true } : { ok: false, error: { type: 'validation_error' } },
|
|
assertPositiveInt: (value: number, name: string) =>
|
|
Number.isInteger(value) && value > 0
|
|
? { ok: true, value }
|
|
: { ok: false, error: { type: 'validation_error', message: `${name} invalid` } }
|
|
}))
|
|
|
|
import { updateIssueBySlug } from './mutations'
|
|
|
|
describe('updateIssueBySlug', () => {
|
|
beforeEach(() => {
|
|
acquireMock.mockReset().mockResolvedValue(undefined)
|
|
ghExecFileAsyncMock.mockReset().mockResolvedValue({ stdout: '', stderr: '' })
|
|
releaseMock.mockReset()
|
|
runRestMock.mockReset().mockResolvedValue({ ok: true, data: {} })
|
|
})
|
|
|
|
it('closes slug-addressed issues with completed and not planned reasons via gh issue close', async () => {
|
|
await expect(
|
|
updateIssueBySlug({
|
|
owner: 'acme',
|
|
repo: 'widgets',
|
|
number: 12,
|
|
updates: { state: 'closed', stateReason: 'completed' }
|
|
})
|
|
).resolves.toEqual({ ok: true })
|
|
await expect(
|
|
updateIssueBySlug({
|
|
owner: 'acme',
|
|
repo: 'widgets',
|
|
number: 13,
|
|
updates: { state: 'closed', stateReason: 'not_planned' }
|
|
})
|
|
).resolves.toEqual({ ok: true })
|
|
|
|
expect(ghExecFileAsyncMock).toHaveBeenNthCalledWith(
|
|
1,
|
|
['issue', 'close', '12', '--repo', 'acme/widgets', '--reason', 'completed'],
|
|
{ encoding: 'utf-8' }
|
|
)
|
|
expect(ghExecFileAsyncMock).toHaveBeenNthCalledWith(
|
|
2,
|
|
['issue', 'close', '13', '--repo', 'acme/widgets', '--reason', 'not planned'],
|
|
{ encoding: 'utf-8' }
|
|
)
|
|
expect(runRestMock).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('closes slug-addressed duplicate issues with --duplicate-of', async () => {
|
|
await expect(
|
|
updateIssueBySlug({
|
|
owner: 'acme',
|
|
repo: 'widgets',
|
|
number: 12,
|
|
updates: { state: 'closed', stateReason: 'duplicate', duplicateOf: 99 }
|
|
})
|
|
).resolves.toEqual({ ok: true })
|
|
|
|
expect(ghExecFileAsyncMock).toHaveBeenCalledWith(
|
|
['issue', 'close', '12', '--repo', 'acme/widgets', '--duplicate-of', '99'],
|
|
{ encoding: 'utf-8' }
|
|
)
|
|
expect(runRestMock).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('rejects duplicate closes without a target before spawning gh', async () => {
|
|
const result = await updateIssueBySlug({
|
|
owner: 'acme',
|
|
repo: 'widgets',
|
|
number: 12,
|
|
updates: { state: 'closed', stateReason: 'duplicate' }
|
|
})
|
|
|
|
expect(result).toMatchObject({
|
|
ok: false,
|
|
error: { type: 'validation_error' }
|
|
})
|
|
expect(ghExecFileAsyncMock).not.toHaveBeenCalled()
|
|
expect(runRestMock).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('reopens slug-addressed issues via gh issue reopen', async () => {
|
|
await expect(
|
|
updateIssueBySlug({
|
|
owner: 'acme',
|
|
repo: 'widgets',
|
|
number: 12,
|
|
updates: { state: 'open' }
|
|
})
|
|
).resolves.toEqual({ ok: true })
|
|
|
|
expect(ghExecFileAsyncMock).toHaveBeenCalledWith(
|
|
['issue', 'reopen', '12', '--repo', 'acme/widgets'],
|
|
{ encoding: 'utf-8' }
|
|
)
|
|
})
|
|
})
|