test: remove low-value mobile and example coverage (#42087)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-11-13 09:55:11 -08:00
committed by GitHub
co-authored by OrcaWin
parent d3a79e606f
commit 048eefd3bf
11 changed files with 37 additions and 284 deletions
@@ -21,14 +21,3 @@ test('adds a task from the input and counts it as open', async () => {
assert.equal(stored.length, 3)
assert.deepEqual(panel.errors, [])
})
test('starts from the persisted list and clears done tasks', async () => {
panel = await mount(panelModule, {
persisted: { plugin: { todos: [{ id: 7, title: 'Ship it', done: true }] } }
})
assert.equal(panel.find({ role: 'status' })?.text, '0 open')
await panel.press({ text: 'Clear done' })
assert.ok(panel.find({ label: 'Nothing to do' }))
})
@@ -2,7 +2,6 @@ import { describe, expect, it, vi } from 'vitest'
import { parseCompilerPass } from './check-node-tests-typecheck.mjs'
import {
checkTransfers,
hasTsNocheckDirective,
parseFailingFiles,
parseProgramTestFiles
@@ -17,18 +16,6 @@ vi.mock('./mobile-typecheck-compiler.mjs', () => ({
})
}))
const transfers = [
'src/components/pr-sidebar/reviewer-picker.target-contract.test.tsx',
'src/test-support/rpc-recording/recorded-request-params.test.ts'
]
const cleanTransfers = () => ({
ok: true,
expected: transfers,
programTestFiles: transfers,
failures: [],
problems: []
})
describe('the failing-file parser', () => {
// Normalize Windows separators or every baseline entry appears stale and added.
it("normalises the Windows separators tsc prints to the baseline's POSIX ones", () => {
@@ -58,24 +45,11 @@ describe('the @ts-nocheck guard', () => {
})
})
describe('checked transfers', () => {
it('rejects a declared checked transfer missing from the configured roots', () => {
expect(
checkTransfers(
{ ok: true, expected: [], programTestFiles: [], failures: [], problems: [] },
new Map([['checked.test.ts', 'Checked transfer: strict Node program']])
)
).toEqual(['checked transfer is absent from tsconfig.test.node.json: checked.test.ts'])
})
const allowed = new Map(transfers.map((file) => [file, 'checked transfer']))
it('never reads a failed declaration producer or final compiler as clean output', () => {
describe('compiler pass failures', () => {
it('rejects nonzero exits and diagnostics returned with a zero exit', () => {
expect(parseCompilerPass('/repo/mobile/src/a.test.ts\n', 2).ok).toBe(false)
expect(
parseCompilerPass('/repo/mobile/src/a.test.ts\nsrc/a.test.ts(1,1): error TS2322: x\n', 0).ok
).toBe(false)
expect(checkTransfers({ ...cleanTransfers(), ok: false }, allowed)).toEqual([
'the phone/host contract program did not pass'
])
})
})
@@ -62,11 +62,5 @@ describe('mobile automation host contracts', () => {
expect(params.updates).toEqual({ name: 'Renamed' })
expect(params.destination).toBeUndefined()
expect(original).toMatchObject({
agentId: 'codex',
rrule: saved.rrule,
grace: '0',
reuseSession: true
})
})
})
@@ -52,20 +52,6 @@ function catalogHarness(respond: () => unknown) {
}
describe('automation catalog', () => {
it('shows the last list at once when the screen reopens, then the host’s newer one', async () => {
let reply: ReturnType<typeof deferred<unknown>> | null = null
const { read, mount } = catalogHarness(() => reply?.promise ?? listReply('Box review'))
await mount()
expect(read().rows.map((row) => row.automation.name)).toEqual(['Local review', 'Box review'])
act(() => tree?.unmount())
reply = deferred<unknown>()
await mount()
expect(read().loaded).toBe(true)
expect(read().rows.map((row) => row.automation.name)).toEqual(['Local review', 'Box review'])
await act(async () => reply?.resolve(listReply('Box nightly')))
expect(read().rows.map((row) => row.automation.name)).toEqual(['Local review', 'Box nightly'])
})
it('keeps a saved change when a list read sent before the write lands after it', async () => {
let held: ReturnType<typeof deferred<unknown>> | null = null
let remoteName = 'Box review'
@@ -40,7 +40,5 @@ describe('browser touch geometry', () => {
expect(delta.dy).toBe(-244)
expect(delta.dx).toBe(0)
// What it sent before: the screen delta itself, 41% of the scroll asked for.
expect(delta.dy).not.toBe(-100)
})
})
+18 -56
View File
@@ -18,19 +18,7 @@ describe('drag completion and cancellation', () => {
await act(async () => fixture.root.unmount())
})
it('does not write after a failed activation or an unchanged drop', async () => {
const fixture = await mounted()
await act(async () => {
fixture.gesture.finalize!({ absoluteY: 100, translationY: 0 }, false)
fixture.gesture.start!({ absoluteY: 100, translationY: 0 }, true)
fixture.gesture.finalize!({ absoluteY: 100, translationY: 0 }, true)
})
expect(fixture.onReorder).not.toHaveBeenCalled()
await act(async () => fixture.root.unmount())
})
it.each([
{ ids: ['a', 'fixed'], distance: 80, expected: { a: 0, fixed: 1 }, changed: false },
{ ids: ['a', 'fixed', 'b'], distance: 80, expected: { a: 0, fixed: 1, b: 2 }, changed: false },
{ ids: ['a', 'fixed', 'b'], distance: 160, expected: { b: 0, fixed: 1, a: 2 }, changed: true }
])('settles a drag across excluded slots at $distance with $ids', async (test) => {
@@ -90,22 +78,6 @@ describe('catalog changes during a drag', () => {
await act(async () => fixture.root.unmount())
})
it.each([{ ids: ['a', 'b', 'c'] }, { ids: ['b', 'a'] }])(
'does not commit a stale drag after the catalog becomes $ids',
async ({ ids }) => {
const fixture = await mounted()
await act(async () => {
fixture.gesture.start!({ absoluteY: 100, translationY: 0 }, true)
fixture.gesture.update!({ absoluteY: 180, translationY: 80 }, true)
})
await fixture.updateItems(ids)
await act(async () => fixture.gesture.finalize!({ absoluteY: 180, translationY: 80 }, true))
expect(fixture.onReorder).not.toHaveBeenCalled()
expect(fixture.onActive.mock.calls).toEqual([[true], [false]])
await act(async () => fixture.root.unmount())
}
)
it('releases its owner when unmounted while a row is held', async () => {
const fixture = await mounted()
await act(async () => fixture.gesture.start!({ absoluteY: 100, translationY: 0 }, true))
@@ -135,34 +107,24 @@ describe('catalog changes during a drag', () => {
})
describe('late gesture callbacks', () => {
it('ignores movement delivered after the row catalog changes', async () => {
const fixture = await mounted()
await act(async () => fixture.gesture.start!({ absoluteY: 100, translationY: 0 }, true))
await fixture.updateItems(['a', 'b', 'c'])
await act(async () => fixture.gesture.update!({ absoluteY: 180, translationY: 80 }, true))
expect(positions()).toEqual({ a: 0, b: 1, c: 2 })
expect(fixture.onReorder).not.toHaveBeenCalled()
await act(async () => fixture.root.unmount())
})
it.each([
['a', 'b', 'c'],
['b', 'a']
])('does not save a completed drop queued before catalog %j replaces it', async (...ids) => {
const fixture = await mounted()
await act(async () => {
fixture.gesture.start!({ absoluteY: 100, translationY: 0 }, true)
fixture.gesture.update!({ absoluteY: 180, translationY: 80 }, true)
probe.deferJS = true
fixture.gesture.finalize!({ absoluteY: 180, translationY: 80 }, true)
})
await fixture.updateItems(ids)
await act(async () => {
probe.jsQueue.splice(0).forEach((fn) => fn())
})
expect(fixture.onReorder).not.toHaveBeenCalled()
await act(async () => fixture.root.unmount())
})
it.each([['a', 'b', 'c']])(
'does not save a completed drop queued before catalog %j replaces it',
async (...ids) => {
const fixture = await mounted()
await act(async () => {
fixture.gesture.start!({ absoluteY: 100, translationY: 0 }, true)
fixture.gesture.update!({ absoluteY: 180, translationY: 80 }, true)
probe.deferJS = true
fixture.gesture.finalize!({ absoluteY: 180, translationY: 80 }, true)
})
await fixture.updateItems(ids)
await act(async () => {
probe.jsQueue.splice(0).forEach((fn) => fn())
})
expect(fixture.onReorder).not.toHaveBeenCalled()
await act(async () => fixture.root.unmount())
}
)
it('does not revive a queued drop when the original row order returns', async () => {
const fixture = await mounted()
@@ -33,9 +33,6 @@ describe('normalizeMobileMarkdownPreviewHtml', () => {
expect(normalizeMobileMarkdownPreviewHtml('```html\n<div>x</div>\n```')).toBe(
'```html\n<div>x</div>\n```'
)
expect(normalizeMobileMarkdownPreviewHtml('```ts\nconst x: Array<string> = []\n```')).toBe(
'```ts\nconst x: Array<string> = []\n```'
)
expect(normalizeMobileMarkdownPreviewHtml('```ts\nconst x: Array<string> = []')).toBe(
'```ts\nconst x: Array<string> = []'
)
@@ -49,12 +46,6 @@ describe('normalizeMobileMarkdownPreviewHtml', () => {
expect(normalizeMobileMarkdownPreviewHtml('Array<string> in prose')).toBe(
'Array<string> in prose'
)
expect(normalizeMobileMarkdownPreviewHtml('Promise<Result> in prose')).toBe(
'Promise<Result> in prose'
)
expect(normalizeMobileMarkdownPreviewHtml('Promise<Array<string>> in prose')).toBe(
'Promise<Array<string>> in prose'
)
expect(normalizeMobileMarkdownPreviewHtml('Map<string, Array<number>> in prose')).toBe(
'Map<string, Array<number>> in prose'
)
@@ -73,13 +64,6 @@ describe('normalizeMobileMarkdownPreviewHtml', () => {
expect(normalizeMobileMarkdownPreviewHtml('<mailto:orca@example.com>')).toBe(
'<mailto:orca@example.com>'
)
expect(normalizeMobileMarkdownPreviewHtml('<ftp://example.com/file>')).toBe(
'<ftp://example.com/file>'
)
expect(normalizeMobileMarkdownPreviewHtml('<tel:+15551234567>')).toBe('<tel:+15551234567>')
expect(normalizeMobileMarkdownPreviewHtml('<https://example.com>')).toBe(
'<https://example.com>'
)
expect(
normalizeMobileMarkdownPreviewHtml(
"<https://en.wikipedia.org/wiki/O'Brien> <svg>hidden</svg>"
@@ -96,11 +80,6 @@ describe('normalizeMobileMarkdownPreviewHtml', () => {
expect(
normalizeMobileMarkdownPreviewHtml('<span title="</string>"></span> Array<string> now')
).toBe('Array<string> now')
expect(
normalizeMobileMarkdownPreviewHtml(
'<span title=</your-api-key>></span> Replace <your-api-key> now'
)
).toBe('Replace <your-api-key> now')
expect(
normalizeMobileMarkdownPreviewHtml('<span title=</string>></span> Array<string> now')
).toBe('Array<string> now')
@@ -139,30 +118,14 @@ describe('normalizeMobileMarkdownPreviewHtml', () => {
'Logo done'
)
expect(normalizeMobileMarkdownPreviewHtml('Logo<svg=invalid>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('Logo<SVG=invalid>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('Logo<path=invalid>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('Logo<p=invalid>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('Logo<strong=invalid>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('Logo<math=invalid>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('Logo<foo=invalid>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('Logo<my-widget=invalid>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('Logo<my-widget disabled>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('<svg=invalid><path/>')).toBe('')
expect(normalizeMobileMarkdownPreviewHtml('Logo<my-widget=invalid>Hi</my-widget> done')).toBe(
'LogoHi done'
)
expect(normalizeMobileMarkdownPreviewHtml('<SVG><PATH/></SVG>')).toBe('')
expect(normalizeMobileMarkdownPreviewHtml('Logo<svg>Hi<path>there')).toBe('LogoHithere')
expect(normalizeMobileMarkdownPreviewHtml('Logo<p>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('Logo<B>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('Logo<strong>Hi')).toBe('LogoHi')
expect(normalizeMobileMarkdownPreviewHtml('Logo<center>Hi <font>there <marquee>now')).toBe(
'LogoHi there now'
)
expect(normalizeMobileMarkdownPreviewHtml('<center>Title</center>')).toBe('Title')
expect(normalizeMobileMarkdownPreviewHtml('<my-widget>Hi</my-widget>')).toBe('Hi')
expect(normalizeMobileMarkdownPreviewHtml('<my:widget>')).toBe('')
expect(normalizeMobileMarkdownPreviewHtml('<svg:path>')).toBe('')
expect(normalizeMobileMarkdownPreviewHtml('Logo<foo>Hi</foo> done')).toBe('LogoHi done')
expect(normalizeMobileMarkdownPreviewHtml('</1>Logo<svg>Hi</svg> done')).toBe('</1>LogoHi done')
expect(normalizeMobileMarkdownPreviewHtml('Logo<svg>Hi</svg > done')).toBe('LogoHi done')
@@ -38,12 +38,11 @@ const RELEASES_URL = 'https://github.com/stablyai/orca/releases'
let renderer: ReactTestRenderer | null = null
function render(verdict: BlockedVerdict, mobileUpdate: KnownAppUpdate | null = null): string {
function render(verdict: BlockedVerdict, mobileUpdate: KnownAppUpdate | null = null): void {
wallUpdate.current = mobileUpdate
act(() => {
renderer = create(createElement(ProtocolBlockScreen, { verdict }))
})
return JSON.stringify(renderer?.toJSON())
}
/** The mocked host components are plain strings, which `ElementType` does not admit. */
@@ -72,33 +71,22 @@ describe('ProtocolBlockScreen', () => {
renderer = null
})
it('tells a host without a bundle, or without this screen, the desktop is too old', () => {
for (const reason of ['bundle-unavailable', 'page-route-unlisted'] as const) {
const output = render({ kind: 'blocked', reason })
expect(output).toContain('Update Orca on your computer')
expect(output).toContain(
'This paired desktop app is too old for your current Orca Mobile app. Update Orca on your computer, then try this host again.'
)
expect(output).not.toContain('does not include the mobile workspace')
expect(primaryActionUrl()).toBe(RELEASES_URL)
}
it('sends a host without a bundle to the desktop release', () => {
render({ kind: 'blocked', reason: 'bundle-unavailable' })
expect(primaryActionUrl()).toBe(RELEASES_URL)
})
it('sends an unknown manifest schema to the mobile update', () => {
const output = render({
render({
kind: 'blocked',
reason: 'bundle-shell-too-old',
schemaVersion: 2
})
expect(output).toContain('Update Orca Mobile')
expect(output).toContain(
"This desktop's mobile workspace needs a newer Orca Mobile app. Update Orca Mobile from the App Store, then try this host again."
)
expect(primaryActionUrl()).toBe('itms-apps://apps.apple.com/app/orca-ide/id6766130217')
})
it('offers no download for a cached bundle the host outgrew, because none would clear it', () => {
const output = render({
render({
kind: 'blocked',
reason: 'bundle-incompatible',
side: 'mobile',
@@ -106,32 +94,18 @@ describe('ProtocolBlockScreen', () => {
requiredBundleRuntimeProtocolVersion: 4
})
expect(output).toContain('Refresh the mobile workspace')
expect(output).toContain(
'The workspace cached for this host is older than the desktop expects. Reconnect to this host to download the current one.'
)
// A store update cannot replace a stale cache, so neither store link is offered.
expect(output).not.toContain('Open App Store')
expect(output).not.toContain('Open GitHub Releases')
expect(output).not.toContain('Update Orca')
// Back to hosts is the only button left, and it is not a download.
expect(pressableCount()).toBe(1)
expect(output).toContain('Back to hosts')
// Nothing was "already updated" here; the note keeps only the pairing fallback.
expect(output).not.toContain('Already updated?')
expect(output).toContain('If this message stays, remove this host and pair it again.')
})
it('sends a host older than its own bundle to the desktop update', () => {
const output = render({
render({
kind: 'blocked',
reason: 'bundle-incompatible',
side: 'desktop',
hostProtocolVersion: 1,
requiredHostProtocolVersion: 2
})
expect(output).toContain('Update Orca on your computer')
expect(output).toContain('This paired desktop app is too old for your current Orca Mobile app')
expect(primaryActionUrl()).toBe(RELEASES_URL)
})
@@ -141,36 +115,27 @@ describe('ProtocolBlockScreen', () => {
url: 'https://github.com/stablyai/orca/releases/tag/mobile-v0.0.52'
}
it.each(['android'] as const)('opens that exact release on %s', (os) => {
nativeTestState.platform.OS = os
const output = render(
{ kind: 'blocked', reason: 'bundle-shell-too-old', schemaVersion: 2 },
release
)
expect(output).toContain('Get Orca 0.0.52')
expect(output).not.toContain('Open App Store')
expect(output).not.toContain('Open GitHub Releases')
it('opens the known Android release', () => {
nativeTestState.platform.OS = 'android'
render({ kind: 'blocked', reason: 'bundle-shell-too-old', schemaVersion: 2 }, release)
expect(primaryActionUrl()).toBe(release.url)
})
it('leaves the desktop wall on the desktop releases', () => {
const output = render({ kind: 'blocked', reason: 'bundle-unavailable' }, release)
expect(output).not.toContain('Get Orca')
render({ kind: 'blocked', reason: 'bundle-unavailable' }, release)
expect(primaryActionUrl()).toBe(RELEASES_URL)
})
})
it.each([
['ios', 'Open App Store', 'itms-apps://apps.apple.com/app/orca-ide/id6766130217'],
['android', 'Open GitHub Releases', RELEASES_URL]
] as const)('keeps the %s store link when no release is known', (os, label, url) => {
['ios', 'itms-apps://apps.apple.com/app/orca-ide/id6766130217'],
['android', RELEASES_URL]
] as const)('keeps the %s store link when no release is known', (os, url) => {
nativeTestState.platform.OS = os
const output = render(
render(
{ kind: 'blocked', reason: 'mobile-too-old', desktopVersion: 5, requiredMobileVersion: 9 },
null
)
expect(output).toContain(label)
expect(output).not.toContain('Get Orca')
expect(primaryActionUrl()).toBe(url)
})
})
@@ -1,45 +0,0 @@
import { createElement } from 'react'
import { act, create, type ReactTestRenderer } from 'react-test-renderer'
import { afterEach, expect, it, vi } from 'vitest'
import { SmartWorkspaceSourceRow } from './SmartWorkspaceSourceRow'
vi.mock('react-native', () => ({ Text: 'Text', View: 'View' }))
vi.mock('lucide-react-native', () => ({ GitBranch: 'Icon', Sparkles: 'Icon' }))
vi.mock('../theme/mobile-theme', () => ({ colors: {}, radii: {}, spacing: {} }))
vi.mock('../theme/themed-styles', () => ({ themedStyleSheet: (make: () => unknown) => make() }))
vi.mock('../theme/use-mobile-color-scheme', () => ({ useMobileColorScheme: () => 'dark' }))
vi.mock('../i18n/use-mobile-translation', () => ({
useMobileTranslation: () => (_key: string, fallback: string) => fallback
}))
vi.mock('./TaskProviderLogo', () => ({ TaskProviderLogo: () => null }))
vi.mock('./list/ListGroup', () => ({ ListRow: 'ListRow' }))
let renderer: ReactTestRenderer
afterEach(() => {
act(() => renderer?.unmount())
})
it('renders a natural remote label without a namespace subtitle and keeps collision qualification', async () => {
const onPress = vi.fn()
const row = {
kind: 'branch' as const,
value: 'branch-refs/remotes/origin/topic',
refName: 'refs/remotes/origin/topic',
localBranchName: 'topic'
}
await act(async () => {
renderer = create(createElement(SmartWorkspaceSourceRow, { row, onPress }))
})
expect(renderer.toJSON()).toMatchObject({ props: { title: 'origin/topic', subtitle: 'topic' } })
await act(async () => {
renderer.update(
createElement(SmartWorkspaceSourceRow, {
row: { ...row, label: 'refs/remotes/origin/topic' },
onPress
})
)
})
expect(renderer.toJSON()).toMatchObject({
props: { title: 'refs/remotes/origin/topic', subtitle: 'topic' }
})
})
@@ -72,7 +72,7 @@ describe('BottomDrawer close lifecycle', () => {
vi.restoreAllMocks()
})
it('keeps close stable and delivers the latest action once after unmount', () => {
it('delivers the latest action once after unmount', () => {
const firstAfterClose = vi.fn()
const rendered: { current?: ReactTestRenderer } = {}
const latestAfterClose = vi.fn(() => {
@@ -80,16 +80,11 @@ describe('BottomDrawer close lifecycle', () => {
})
const renderer = renderDrawer(true, vi.fn(), firstAfterClose)
rendered.current = renderer
const initialOnHidden = mountedDrawer(renderer).props.onHidden
updateDrawer(renderer, false, vi.fn(), firstAfterClose)
const closingOnHidden = mountedDrawer(renderer).props.onHidden
updateDrawer(renderer, false, vi.fn(), latestAfterClose)
const rerenderedOnHidden = mountedDrawer(renderer).props.onHidden
expect(closingOnHidden).toBe(initialOnHidden)
expect(rerenderedOnHidden).toBe(initialOnHidden)
act(() => {
rerenderedOnHidden()
rerenderedOnHidden()
@@ -102,22 +97,4 @@ describe('BottomDrawer close lifecycle', () => {
expect(latestAfterClose).toHaveBeenCalledTimes(1)
expect(renderer.toJSON()).toBeNull()
})
// Reopen before queued hide callback must invalidate it or next close leaves invisible tap-swallowing Modal.
it('a hide that lands after a reopen does not swallow the next close', () => {
const onAfterClose = vi.fn()
const renderer = renderDrawer(true, vi.fn(), onAfterClose)
const lateOnHidden = mountedDrawer(renderer).props.onHidden
updateDrawer(renderer, false, vi.fn(), onAfterClose)
updateDrawer(renderer, true, vi.fn(), onAfterClose)
act(() => lateOnHidden())
expect(mountedDrawer(renderer).props.visible).toBe(true)
expect(onAfterClose).not.toHaveBeenCalled()
updateDrawer(renderer, false, vi.fn(), onAfterClose)
act(() => mountedDrawer(renderer).props.onHidden())
expect(renderer.toJSON()).toBeNull()
expect(onAfterClose).toHaveBeenCalledTimes(1)
})
})
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { bottomDrawerDismissMotion, shouldDismissBottomDrawer } from './bottom-drawer-drag-motion'
import { shouldDismissBottomDrawer } from './bottom-drawer-drag-motion'
describe('bottom drawer release', () => {
it('judges where the sheet is heading, not where the finger let go', () => {
@@ -9,14 +9,4 @@ describe('bottom drawer release', () => {
// A flick back up keeps the sheet even after a long drag.
expect(shouldDismissBottomDrawer(180, -600, 777)).toBe(false)
})
it('leaves at the finger speed, slow or thrown, within an ordinary close', () => {
const remaining = 825 - 112
for (const velocity of [800, 6000, 12000]) {
const { duration, x1, y1 } = bottomDrawerDismissMotion(112, velocity, 825, 300)
expect(duration).toBeLessThanOrEqual(300)
// The curve's start slope (y1 / x1) times the average speed is the speed it starts at.
expect(((y1 / x1) * remaining) / (duration / 1000)).toBeCloseTo(velocity)
}
})
})