Files
orca/mobile/src/source-control/mobile-pr-create.test.ts
T
Neil 6e1b7e7fa3 test: remove junk tests that assert source text instead of behavior (#23815)
Deletes 101 test files and trims 112 more, all matching documented junk
patterns: exact source/import/string greps, copied inventories and export
lists, duplicate invocations of a contract another test already owns,
typeof-shape checks TypeScript already enforces, and self-comparisons.

The largest group read a production `.ts` file and asserted on its text —
for example a TaskPage test that required the source to contain
`selectedRepos.find((r) => r.id === newIssueRepoId) ?? selectedRepos[0] ?? null`.
Any behavior-preserving rename broke it; no behavior change ever did.

Production-side follow-through: exports that only these tests imported are
de-exported or deleted, stale comments pointing at removed censuses are
dropped, and the reliability-gate registry, `cloud/package.json` test lists,
and orphaned source-reading helpers are updated so nothing references a
deleted file.

Two files kept their real coverage and lost only the census scaffolding:
`agent-status-producer-census.test.ts` now drives all five producers end to
end instead of grepping the source tree, and `config-toml-trust-stale-writes`
replaces an export-list parity check.
2026-09-29 01:21:53 -07:00

419 lines
14 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
import type { RpcClient } from '../transport/rpc-client'
import type { RpcFailure, RpcResponse, RpcSuccess } from '../transport/types'
import type { HostedReviewCreationEligibility } from '../../../src/shared/hosted-review'
import { shouldOpenChecksPanelCreateComposer } from '../../../src/renderer/src/components/right-sidebar/checks-panel-review-creation'
import {
buildMobilePrCreateParams,
getMobilePrCreateBlockMessage,
mobileRepoSelectorFromWorktreeId,
createMobilePr,
resolveMobilePrPrefill,
shouldPushBeforeMobilePrCreate,
type MobilePrPrefill
} from './mobile-pr-create'
function ok(result: unknown): RpcSuccess {
return { id: 'r', ok: true, result, _meta: { runtimeId: 'rt' } }
}
function fail(message: string): RpcFailure {
return { id: 'r', ok: false, error: { code: 'x', message }, _meta: { runtimeId: 'rt' } }
}
function clientWith(responses: RpcResponse[]): Pick<RpcClient, 'sendRequest'> & {
calls: Array<{ method: string; params: unknown }>
} {
const calls: Array<{ method: string; params: unknown }> = []
return {
calls,
sendRequest: vi.fn(async (method: string, params?: unknown) => {
calls.push({ method, params })
return responses.shift() ?? fail('unexpected')
})
}
}
function eligibility(
overrides: Partial<HostedReviewCreationEligibility> = {}
): HostedReviewCreationEligibility {
return {
provider: 'github',
review: null,
canCreate: true,
blockedReason: null,
nextAction: null,
reviewLookupOutcome: 'not_found',
defaultBaseRef: 'main',
title: 'Add feature',
body: '',
...overrides
}
}
describe('mobileRepoSelectorFromWorktreeId', () => {
it('extracts the repo id before the :: separator', () => {
expect(mobileRepoSelectorFromWorktreeId('repo-1::/tmp/wt')).toBe('id:repo-1')
expect(mobileRepoSelectorFromWorktreeId('repo-1')).toBe('id:repo-1')
})
})
describe('buildMobilePrCreateParams', () => {
it('trims fields and drops empty optionals', () => {
expect(
buildMobilePrCreateParams('repo-1::/tmp/wt', {
provider: 'github',
base: ' main ',
title: ' Add feature ',
body: ' ',
draft: false,
useTemplate: true
})
).toEqual({
repo: 'id:repo-1',
worktree: 'id:repo-1::/tmp/wt',
provider: 'github',
base: 'main',
title: 'Add feature',
draft: false,
useTemplate: true
})
})
it('keeps a non-empty body and head', () => {
const params = buildMobilePrCreateParams('repo-1::/tmp/wt', {
provider: 'gitlab',
base: 'main',
head: 'feature/x',
title: 'T',
body: 'Body text',
draft: true
})
expect(params).toMatchObject({ head: 'feature/x', body: 'Body text', draft: true })
})
})
describe('mobile create form gating parity', () => {
it.each([
{ reason: null, canCreate: true },
{ reason: 'dirty', canCreate: false },
{ reason: 'detached_head', canCreate: false },
{ reason: 'default_branch', canCreate: false },
{ reason: 'no_upstream', canCreate: false },
{ reason: 'needs_push', canCreate: false },
{ reason: 'needs_sync', canCreate: false },
{ reason: 'auth_required', canCreate: false },
{ reason: 'unsupported_provider', canCreate: false },
{ reason: 'existing_review', canCreate: false },
{ reason: 'fork_head_unsupported', canCreate: false }
] as const)('matches desktop composer gating for $reason', ({ reason, canCreate }) => {
const desktopEligibility = eligibility({ canCreate, blockedReason: reason })
const desktopAllowsComposer = shouldOpenChecksPanelCreateComposer({
activeReview: null,
isFolder: false,
branch: 'feature/x',
hostedReviewCreation: desktopEligibility
})
const mobileAllowsComposer =
getMobilePrCreateBlockMessage({
provider: desktopEligibility.provider,
base: desktopEligibility.defaultBaseRef ?? 'main',
title: desktopEligibility.title ?? 'feature/x',
body: desktopEligibility.body ?? '',
canCreate: desktopEligibility.canCreate,
blockedReason: desktopEligibility.blockedReason,
nextAction: desktopEligibility.nextAction,
// Mobile receives the lookup outcome from eligibility; thread it so the
// gate reflects real prefills (current hosts always populate it).
reviewLookupOutcome: desktopEligibility.reviewLookupOutcome
}) === null
expect(mobileAllowsComposer).toBe(desktopAllowsComposer)
})
it('fails closed when the review-lookup outcome is missing (older host)', () => {
// A host that predates `reviewLookupOutcome` leaves review existence unproven.
// Mobile must not open Create / Push & Create on that ambiguity.
expect(
getMobilePrCreateBlockMessage({
provider: 'github',
base: 'main',
title: 'Add feature',
body: '',
canCreate: true,
blockedReason: null
})
).toBe(
'Orca could not confirm whether this branch already has a pull request. Try again in a moment.'
)
expect(
getMobilePrCreateBlockMessage({
provider: 'github',
base: 'main',
title: 'Add feature',
body: '',
canCreate: false,
blockedReason: 'needs_push'
})
).toBe(
'Orca could not confirm whether this branch already has a pull request. Try again in a moment.'
)
})
it('fails closed on an unavailable review lookup even when eligibility looks ready', () => {
// The existing-review lookup could not prove there is no PR; mobile has no
// review-lookup signal of its own, so create must be blocked.
expect(
getMobilePrCreateBlockMessage({
provider: 'github',
base: 'main',
title: 'Add feature',
body: '',
canCreate: true,
blockedReason: null,
reviewLookupOutcome: 'unavailable'
})
).toBe(
'Orca could not confirm whether this branch already has a pull request. Try again in a moment.'
)
})
it('fails closed on unavailable even on the needs_push Push & Create path', () => {
// needs_push would normally be allowed (Push & Create); an unavailable lookup
// must still block it — this is the fail-open gap the parity gate closes.
const mobileBlocked =
getMobilePrCreateBlockMessage({
provider: 'github',
base: 'main',
title: 'Add feature',
body: '',
canCreate: false,
blockedReason: 'needs_push',
reviewLookupOutcome: 'unavailable'
}) !== null
const desktopAllowsComposer = shouldOpenChecksPanelCreateComposer({
activeReview: null,
isFolder: false,
branch: 'feature/x',
hostedReviewCreation: eligibility({
canCreate: false,
blockedReason: 'needs_push',
reviewLookupOutcome: 'unavailable'
})
})
expect(mobileBlocked).toBe(true)
expect(desktopAllowsComposer).toBe(false)
})
it('stays safely blocked for a reason added by a newer desktop contract', () => {
expect(
getMobilePrCreateBlockMessage({
provider: 'github',
base: 'main',
title: 'Add feature',
body: '',
canCreate: false,
blockedReason: 'future_desktop_reason' as unknown as MobilePrPrefill['blockedReason']
})
).toBe('This branch is not ready for a pull request yet.')
})
})
describe('resolveMobilePrPrefill', () => {
const baseArgs = {
branch: 'feature/x',
title: 'feature/x',
hasUncommittedChanges: false,
hasUpstream: true,
ahead: 1,
behind: 0
}
it('sends back a provider token this build does not list, unchanged', async () => {
// The regression this pins: an enum fallback on the eligibility reply put 'unsupported' on the
// wire, and the host that named 'codeberg' refused its own provider.
const client = clientWith([
ok({
provider: 'codeberg',
canCreate: true,
review: null,
blockedReason: null,
nextAction: null,
defaultBaseRef: 'main',
title: 'Add feature',
body: '',
reviewLookupOutcome: 'not_found'
}),
ok({ ok: true, number: 12, url: 'https://codeberg.test/pr/12' }),
ok({ worktree: { id: 'wt' } })
])
const prefill = await resolveMobilePrPrefill(client, 'repo-1::/tmp/wt', baseArgs)
expect(prefill.provider).toBe('codeberg')
await createMobilePr(client, 'repo-1::/tmp/wt', {
provider: prefill.provider,
base: prefill.base,
title: prefill.title,
body: prefill.body,
draft: false
})
const created = client.calls.find((call) => call.method === 'hostedReview.create')
expect(created?.params).toMatchObject({ provider: 'codeberg' })
})
it('derives provider/base/title/body from eligibility (non-GitHub honored)', async () => {
const client = clientWith([
ok({
provider: 'gitlab',
canCreate: true,
review: null,
blockedReason: null,
nextAction: null,
defaultBaseRef: 'develop',
title: 'Add feature',
body: 'Body',
reviewLookupOutcome: 'not_found'
})
])
await expect(resolveMobilePrPrefill(client, 'repo-1::/tmp/wt', baseArgs)).resolves.toEqual({
provider: 'gitlab',
base: 'develop',
title: 'Add feature',
body: 'Body',
canCreate: true,
blockedReason: null,
nextAction: null,
reviewLookupOutcome: 'not_found'
})
})
it('marks needs_push eligibility for submit-time push parity', async () => {
const client = clientWith([
ok({
provider: 'github',
canCreate: false,
review: null,
blockedReason: 'needs_push',
nextAction: 'push',
defaultBaseRef: 'main',
title: 'Add feature',
body: '',
reviewLookupOutcome: 'not_found'
})
])
const prefill = await resolveMobilePrPrefill(client, 'repo-1::/tmp/wt', baseArgs)
expect(shouldPushBeforeMobilePrCreate(prefill)).toBe(true)
expect(getMobilePrCreateBlockMessage(prefill)).toBeNull()
})
it('returns a mobile block message for desktop-blocked create states', async () => {
const client = clientWith([
ok({
provider: 'github',
canCreate: false,
review: null,
blockedReason: 'dirty',
nextAction: 'commit',
defaultBaseRef: 'main',
reviewLookupOutcome: 'not_found'
})
])
const prefill = await resolveMobilePrPrefill(client, 'repo-1::/tmp/wt', baseArgs)
expect(getMobilePrCreateBlockMessage(prefill)).toBe(
'Commit changes before creating a pull request.'
)
})
it('returns a blocked fallback when eligibility is unavailable', async () => {
const client = clientWith([fail('nope')])
const prefill = await resolveMobilePrPrefill(client, 'repo-1::/tmp/wt', baseArgs)
expect(prefill).toEqual({
provider: 'github',
base: 'main',
title: 'feature/x',
body: '',
// No `canCreate`: nobody determined anything. A false one would route the copy through
// blockedReason and tell the user the branch is not ready.
blockedReason: null,
nextAction: null,
// Eligibility could not be resolved, so the review lookup is unproven.
reviewLookupOutcome: 'unavailable'
})
// A prefill Orca could not resolve must not offer create.
expect(getMobilePrCreateBlockMessage(prefill)).not.toBeNull()
})
// Three ways eligibility fails to arrive, one answer: say so, rather than claim the branch is
// not ready. Only a host that actually determined `canCreate: false` gets the blocked copy.
const UNCONFIRMED =
'Orca could not confirm whether this branch already has a pull request. Try again in a moment.'
it.each([
{ name: 'a malformed reply', responses: [ok({ provider: 7 })] },
{ name: 'a refusal', responses: [fail('nope')] }
])('asks the user to retry after $name', async ({ responses }) => {
const prefill = await resolveMobilePrPrefill(clientWith(responses), 'repo-1::/tmp/wt', baseArgs)
expect(prefill.canCreate).toBeUndefined()
expect(getMobilePrCreateBlockMessage(prefill)).toBe(UNCONFIRMED)
})
it('asks the user to retry after a transport rejection', async () => {
const rejecting = {
sendRequest: vi.fn(async () => {
throw new Error('offline')
})
}
const prefill = await resolveMobilePrPrefill(rejecting, 'repo-1::/tmp/wt', baseArgs)
expect(prefill.canCreate).toBeUndefined()
expect(getMobilePrCreateBlockMessage(prefill)).toBe(UNCONFIRMED)
})
it('still blocks when the host determined the branch is not ready', async () => {
const client = clientWith([
ok({
provider: 'github',
canCreate: false,
review: null,
blockedReason: 'dirty',
nextAction: 'commit',
defaultBaseRef: 'main',
reviewLookupOutcome: 'not_found'
})
])
const prefill = await resolveMobilePrPrefill(client, 'repo-1::/tmp/wt', baseArgs)
expect(prefill.canCreate).toBe(false)
expect(getMobilePrCreateBlockMessage(prefill)).toBe(
'Commit changes before creating a pull request.'
)
})
it('threads reviewLookupOutcome from eligibility into the prefill and blocks needs_push', async () => {
const client = clientWith([
ok({
provider: 'github',
canCreate: false,
review: null,
blockedReason: 'needs_push',
nextAction: 'push',
defaultBaseRef: 'main',
title: 'Add feature',
body: '',
reviewLookupOutcome: 'unavailable'
})
])
const prefill = await resolveMobilePrPrefill(client, 'repo-1::/tmp/wt', baseArgs)
expect(prefill.reviewLookupOutcome).toBe('unavailable')
expect(getMobilePrCreateBlockMessage(prefill)).not.toBeNull()
})
it('blocks without calling the RPC when there is no branch', async () => {
const client = clientWith([])
const result = await resolveMobilePrPrefill(client, 'repo-1::/tmp/wt', {
...baseArgs,
branch: undefined
})
expect(result.provider).toBe('github')
expect(result.canCreate).toBe(false)
expect(result.blockedReason).toBe('detached_head')
expect(client.calls).toEqual([])
})
})