Files
orca/tests/e2e/github-url-smart-input-transition.spec.ts
T
Neil f107499e44 fix(lint): enable anti-slop/no-reflect-get (#20786)
`anti-slop/no-reflect-get` rejects every call to `Reflect.get`. The
reflective read bypasses ordinary property access and throws away the
type evidence the compiler would otherwise give you: the result is
`any`/`unknown` with no narrowing, so a typo in the key or a shape drift
in the source object is invisible until runtime. The rule's remedy is to
parse dynamic input into a named domain type (or narrow it with `in`)
and then read the field normally.

Baseline: 86 violations across 67 files. Now zero unsuppressed
violations under
`npx oxlint --config config/oxlint-anti-slop.json --ignore-pattern 'config/oxlint-plugins/anti-slop/**' src config tests mobile`.

Fix pattern
-----------
44 of the 86 were rewritten. The dominant shape was an `unknown` value
read through `Reflect.get` right after a `typeof === 'object'` guard;
those became `in`-narrowed property access, which TypeScript checks:

  - Reflect.get(value, 'agents')
  + 'agents' in value ? value.agents : null

Two further shapes:
- `Reflect.get(Object(x), 'k')` on a possibly-primitive envelope became a
  small named reader that boxes once and indexes a
  `Record<string, unknown>` (`settingsField` in
  mobile/src/transport/settings-read-operations.ts).
- Tests reaching into private state moved to TypeScript's checked
  bracket-index escape hatch (`runtime['layoutQueues']`), or to a
  documented read-only accessor on the owning class
  (`SearchSubprocessLineAccumulator.retainedCapacityBytes()`,
  `CodexSubagentExecutions.retentionSizes()`).

No type assertion was added anywhere: the diff contains zero net-new
`as` casts, `as any`, `as unknown as`, `@ts-ignore`, or
`@ts-expect-error`, so nothing was laundered into the sibling
assertion rules.

Suppressions
------------
42x `// oxlint-disable-next-line anti-slop/no-reflect-get` across 38
files. Every one is the default-forward branch of a `Proxy` `get` trap:

    get(target, property, receiver) {
      ...
      return Reflect.get(target, property, receiver)
    }

`Reflect.get(target, property, receiver)` is the only construct that
forwards with correct `receiver` semantics; `target[property]` invokes
an accessor with the wrong `this` and silently breaks getters that read
sibling state. There is no typed alternative, so these are suppressed
rather than rewritten.

3x `// oxlint-disable-next-line typescript-eslint/consistent-type-definitions
-- declaration merging requires interface` in
tests/e2e/github-url-smart-input-transition.spec.ts,
tests/e2e/linear-url-workspace-entry.spec.ts, and
tests/e2e/worktree-active-delete-scroll-position.spec.ts. Replacing
`Reflect.get(window, 'x')` with typed `window.x` requires a
`declare global { interface Window }` block, and `interface` is
mandatory for declaration merging. Matches the existing convention at
tests/e2e/helpers/runtime-types.ts:63.

1x `// eslint-disable-next-line no-var -- main-process gate handle for
this spec` in tests/e2e/project-group-creation-visibility.spec.ts, for
the same reason a `var` global is needed to type the handle. Matches
tests/e2e/agent-session-log-tail-stability.spec.ts:24.

Also updates two source-text anchors in mobile's rpc-recording mutation
harness (mobile/src/test-support/rpc-recording/operation-mutations.ts
and recording-runner.test.ts), which pin the exact text of the rewritten
line in settings-read-operations.ts and would otherwise fail with
"Mutant anchor matched 0 sites, expected 1".
2026-09-15 01:24:30 -07:00

370 lines
12 KiB
TypeScript

import { openSidebarWorkspaceComposer } from './helpers/sidebar-project-dialog'
import type { ElectronApplication, Locator, Page } from '@stablyai/playwright-test'
import type { GitHubWorkItem } from '../../src/shared/github/work-item-types'
import type { GitLabWorkItem } from '../../src/shared/gitlab-types'
import { test, expect } from './helpers/orca-app'
import { waitForActiveWorktree, waitForSessionReady } from './helpers/store'
const TARGET_URL = 'https://github.com/stablyai/orca/issues/4242'
const WRONG_TITLE = 'Wrong cached issue'
const TARGET_TITLE = 'Exact pasted issue'
const GITLAB_TARGET_URL = 'https://gitlab.example.test/stablyai/orca/-/merge_requests/4242'
const GITLAB_WRONG_TITLE = 'Wrong cached merge request'
const GITLAB_TARGET_TITLE = 'Exact pasted merge request'
const MIN_PASTED_FRAMES = 2
const TRANSITION_FRAME_LIMIT = 600
const WRONG_ITEM: GitHubWorkItem = {
id: 'issue-17',
type: 'issue',
number: 17,
title: WRONG_TITLE,
state: 'open',
url: 'https://github.com/stablyai/orca/issues/17',
labels: [],
updatedAt: '2026-08-01T00:00:00.000Z',
author: 'e2e',
repoId: 'e2e-repo'
}
const TARGET_ITEM: GitHubWorkItem = {
...WRONG_ITEM,
id: 'issue-4242',
number: 4242,
title: TARGET_TITLE,
url: TARGET_URL,
updatedAt: '2026-08-02T00:00:00.000Z'
}
const GITLAB_WRONG_ITEM: GitLabWorkItem = {
id: 'mr-17',
type: 'mr',
number: 17,
title: GITLAB_WRONG_TITLE,
state: 'opened',
url: 'https://gitlab.example.test/stablyai/orca/-/merge_requests/17',
labels: [],
updatedAt: '2026-08-01T00:00:00.000Z',
author: 'e2e',
repoId: 'e2e-repo'
}
const GITLAB_TARGET_ITEM: GitLabWorkItem = {
...GITLAB_WRONG_ITEM,
id: 'mr-4242',
number: 4242,
title: GITLAB_TARGET_TITLE,
url: GITLAB_TARGET_URL,
updatedAt: '2026-08-02T00:00:00.000Z'
}
type TransitionFrame = {
value: string
wrongVisible: boolean
wrongSelected: boolean
targetVisible: boolean
targetSelected: boolean
}
declare global {
// oxlint-disable-next-line typescript-eslint/consistent-type-definitions -- declaration merging requires interface
interface Window {
// Per-provider capture buffers written by startTransitionCapture below.
__githubUrlTransitionFrames?: TransitionFrame[]
__gitlabUrlTransitionFrames?: TransitionFrame[]
}
}
type TransitionFrameKey = '__githubUrlTransitionFrames' | '__gitlabUrlTransitionFrames'
function pasteChord(): string {
return process.platform === 'darwin' ? 'Meta+V' : 'Control+V'
}
async function startTransitionCapture(
page: Page,
frameKey: TransitionFrameKey,
wrongTitle: string,
targetTitle: string
): Promise<void> {
await page.evaluate(
({ frameKey, frameLimit, wrongTitle, targetTitle }) => {
const frames: TransitionFrame[] = []
const capture = (): void => {
const input = document.querySelector<HTMLInputElement>('[data-workspace-name-input="true"]')
const options = [...document.querySelectorAll<HTMLElement>('[role="option"]')]
const wrong = options.find((option) => option.textContent?.includes(wrongTitle))
const target = options.find((option) => option.textContent?.includes(targetTitle))
frames.push({
value: input?.value ?? '',
wrongVisible: Boolean(wrong && wrong.getClientRects().length > 0),
wrongSelected: wrong?.dataset.selected === 'true',
targetVisible: Boolean(target && target.getClientRects().length > 0),
targetSelected: target?.dataset.selected === 'true'
})
if (frames.length < frameLimit) {
requestAnimationFrame(capture)
}
}
window[frameKey] = frames
capture()
},
{ frameKey, frameLimit: TRANSITION_FRAME_LIMIT, wrongTitle, targetTitle }
)
}
async function readTransitionFrames(
page: Page,
frameKey: TransitionFrameKey
): Promise<TransitionFrame[]> {
return page.evaluate((key) => {
const frames = window[key]
if (!frames) {
throw new Error(`Transition capture ${key} was never installed`)
}
return frames
}, frameKey)
}
async function expectLookupHeldWithoutStaleRow(
page: Page,
frameKey: TransitionFrameKey,
targetUrl: string,
wrongOption: Locator,
targetOption: Locator
): Promise<void> {
await expect
.poll(async () => {
const frames = await readTransitionFrames(page, frameKey)
return frames.filter((frame) => frame.value === targetUrl).length
})
.toBeGreaterThanOrEqual(MIN_PASTED_FRAMES)
await expect(wrongOption).toHaveCount(0)
await expect(targetOption).toHaveCount(0)
}
async function expectExactTargetAfterLookup(
page: Page,
frameKey: TransitionFrameKey,
targetUrl: string,
targetOption: Locator
): Promise<void> {
await expect(targetOption).toBeVisible()
await expect(targetOption).toHaveAttribute('data-selected', 'true')
await expect
.poll(async () => {
const frames = await readTransitionFrames(page, frameKey)
return frames.some((frame) => frame.targetVisible && frame.targetSelected)
})
.toBe(true)
const frames = await readTransitionFrames(page, frameKey)
const pastedFrames = frames.filter((frame) => frame.value === targetUrl)
expect(frames.some((frame) => frame.wrongVisible)).toBe(true)
expect(pastedFrames.length).toBeGreaterThanOrEqual(MIN_PASTED_FRAMES)
expect(pastedFrames.every((frame) => !frame.wrongVisible && !frame.wrongSelected)).toBe(true)
expect(pastedFrames.some((frame) => frame.targetVisible && frame.targetSelected)).toBe(true)
}
async function installHeldGitHubLookup(
electronApp: ElectronApplication,
page: Page
): Promise<void> {
await electronApp.evaluate(({ ipcMain }, targetItem) => {
const fixture = globalThis as unknown as {
__githubUrlLookupStarted?: boolean
__releaseGitHubUrlLookup?: () => void
}
fixture.__githubUrlLookupStarted = false
ipcMain.removeHandler('gh:repoSlug')
ipcMain.handle('gh:repoSlug', () => ({ owner: 'stablyai', repo: 'orca' }))
ipcMain.removeHandler('gh:workItemByOwnerRepo')
ipcMain.handle('gh:workItemByOwnerRepo', () => {
fixture.__githubUrlLookupStarted = true
return new Promise((resolve) => {
fixture.__releaseGitHubUrlLookup = () => resolve(targetItem)
})
})
}, TARGET_ITEM)
await page.evaluate((wrongItem) => {
const store = window.__store
if (!store) {
throw new Error('window.__store is not available')
}
store.setState({
getCachedWorkItems: () => [wrongItem],
fetchWorkItems: async () => [wrongItem],
fetchWorkItemsAcrossRepos: async () => ({
items: [wrongItem],
failedCount: 0,
githubUnavailable: false
})
})
}, WRONG_ITEM)
}
async function releaseGitHubLookup(electronApp: ElectronApplication): Promise<void> {
await electronApp.evaluate(() => {
const fixture = globalThis as unknown as { __releaseGitHubUrlLookup?: () => void }
if (!fixture.__releaseGitHubUrlLookup) {
throw new Error('GitHub lookup is not held')
}
fixture.__releaseGitHubUrlLookup()
})
}
async function installHeldGitLabLookup(
electronApp: ElectronApplication,
page: Page
): Promise<void> {
await electronApp.evaluate(
({ ipcMain }, { wrongItem, targetItem }) => {
const fixture = globalThis as unknown as {
__gitlabUrlLookupStarted?: boolean
__releaseGitLabUrlLookup?: () => void
}
fixture.__gitlabUrlLookupStarted = false
ipcMain.removeHandler('preflight:check')
ipcMain.handle('preflight:check', () => ({
git: { installed: true },
gh: { installed: true, authenticated: true },
glab: { installed: true, authenticated: true }
}))
ipcMain.removeHandler('gitlab:listMRs')
ipcMain.handle('gitlab:listMRs', () => ({
items: [wrongItem],
page: 1,
perPage: 12,
totalCount: 1,
totalPages: 1
}))
ipcMain.removeHandler('gitlab:workItemByPath')
ipcMain.handle('gitlab:workItemByPath', () => {
fixture.__gitlabUrlLookupStarted = true
return new Promise((resolve) => {
fixture.__releaseGitLabUrlLookup = () => resolve(targetItem)
})
})
},
{ wrongItem: GITLAB_WRONG_ITEM, targetItem: GITLAB_TARGET_ITEM }
)
await page.evaluate(async () => {
const store = window.__store
if (!store) {
throw new Error('window.__store is not available')
}
await store.getState().refreshPreflightStatus({ force: true })
})
}
async function releaseGitLabLookup(electronApp: ElectronApplication): Promise<void> {
await electronApp.evaluate(() => {
const fixture = globalThis as unknown as { __releaseGitLabUrlLookup?: () => void }
if (!fixture.__releaseGitLabUrlLookup) {
throw new Error('GitLab lookup is not held')
}
fixture.__releaseGitLabUrlLookup()
})
}
test('a pasted GitHub URL never selects a stale cached issue', async ({
electronApp,
orcaPage
}, testInfo) => {
await waitForSessionReady(orcaPage)
await waitForActiveWorktree(orcaPage)
await installHeldGitHubLookup(electronApp, orcaPage)
await openSidebarWorkspaceComposer(orcaPage)
const dialog = orcaPage.getByRole('dialog', { name: /Create (Workspace|Worktree)/i })
const input = dialog.locator('[data-workspace-name-input="true"]')
await expect(input).toBeVisible()
await input.click()
const wrongOption = orcaPage.getByRole('option', { name: `#17 ${WRONG_TITLE}`, exact: true })
const targetOption = orcaPage.getByRole('option', {
name: `#4242 ${TARGET_TITLE}`,
exact: true
})
await expect(wrongOption).toBeVisible()
const frameKey: TransitionFrameKey = '__githubUrlTransitionFrames'
await startTransitionCapture(orcaPage, frameKey, WRONG_TITLE, TARGET_TITLE)
await orcaPage.evaluate((text) => window.api.ui.writeClipboardText(text), TARGET_URL)
await input.focus()
await orcaPage.keyboard.press(pasteChord())
await expect
.poll(() =>
electronApp.evaluate(() => {
const fixture = globalThis as unknown as { __githubUrlLookupStarted?: boolean }
return fixture.__githubUrlLookupStarted === true
})
)
.toBe(true)
await expectLookupHeldWithoutStaleRow(orcaPage, frameKey, TARGET_URL, wrongOption, targetOption)
await releaseGitHubLookup(electronApp)
await expectExactTargetAfterLookup(orcaPage, frameKey, TARGET_URL, targetOption)
await testInfo.attach('github-url-smart-input-fixed.png', {
body: await orcaPage.screenshot(),
contentType: 'image/png'
})
})
test('a pasted GitLab URL never selects a stale cached merge request', async ({
electronApp,
orcaPage
}, testInfo) => {
await waitForSessionReady(orcaPage)
await waitForActiveWorktree(orcaPage)
await installHeldGitLabLookup(electronApp, orcaPage)
await openSidebarWorkspaceComposer(orcaPage)
const dialog = orcaPage.getByRole('dialog', { name: /Create (Workspace|Worktree)/i })
const input = dialog.locator('[data-workspace-name-input="true"]')
await expect(input).toBeVisible()
await input.click()
const wrongOption = orcaPage.getByRole('option', {
name: `!17 ${GITLAB_WRONG_TITLE}`,
exact: true
})
const targetOption = orcaPage.getByRole('option', {
name: `!4242 ${GITLAB_TARGET_TITLE}`,
exact: true
})
await expect(wrongOption).toBeVisible()
const frameKey: TransitionFrameKey = '__gitlabUrlTransitionFrames'
await startTransitionCapture(orcaPage, frameKey, GITLAB_WRONG_TITLE, GITLAB_TARGET_TITLE)
await orcaPage.evaluate((text) => window.api.ui.writeClipboardText(text), GITLAB_TARGET_URL)
await input.focus()
await orcaPage.keyboard.press(pasteChord())
await expect
.poll(() =>
electronApp.evaluate(() => {
const fixture = globalThis as unknown as { __gitlabUrlLookupStarted?: boolean }
return fixture.__gitlabUrlLookupStarted === true
})
)
.toBe(true)
await expectLookupHeldWithoutStaleRow(
orcaPage,
frameKey,
GITLAB_TARGET_URL,
wrongOption,
targetOption
)
await releaseGitLabLookup(electronApp)
await expectExactTargetAfterLookup(orcaPage, frameKey, GITLAB_TARGET_URL, targetOption)
await testInfo.attach('gitlab-url-smart-input-fixed.png', {
body: await orcaPage.screenshot(),
contentType: 'image/png'
})
})