Files
orca/config/scripts/check-import-boundaries.test.mjs
T
Jinwoo Hong 01db1b89af Main titles agent tabs and applies phone tab moves itself, and tab moves name the tab they follow (dark, layout-owner build only) (#31812)
* Layout groundwork (switched off): main derives agent tab titles from its own hook status

With the layout-owner switch on, main gives agent tabs their generated titles from
the hook-server status it owns, on the desktop, headless serve and orcad: one
renameTabs per status batch, so one write and one frame. It keeps the window's
rules (setting, custom and quick-command titles, first title wins, dispatch labels).
The window stops sending generated titles for tabs main holds; a paired server's
tab, or one main has no tab-bar entry for, is still titled by the window as today.

The title rules move to src/shared (agent-row-primary-text, and the new
agent-generated-tab-title-rules) so both sides share them; switch-off behaviour
is unchanged.

* feat(layout): main applies a phone's or paired client's tab move itself, and a tab move names the tab it follows so a stale index can't misplace it (layout-owner build, L193)

* fix(layout): a move in a group showing a tab main lacks goes the window's way, a twin's agent tab keeps its window title, and orcad subscribes titles through the store attach (layout-owner build)

* chore(layout): main's tab move reaches the old-client translation through its compat entry

* chore(layout): mark the window-only-row move fallback as bridge code (ledger L280)

* test(layout): attaching the hook store follows its rows for main's tab titles once

* chore(layout): the old-client move translation is a compat entry of its own, with no cyclic re-export

* test(config): the boundary message test names the old-client folder's configured entries
2026-10-22 02:24:37 -04:00

79 lines
3.2 KiB
JavaScript

import { afterEach, expect, it, vi } from 'vitest'
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import path from 'node:path'
import { COMPAT_FOLDERS } from './check-compat-boundary-imports.mjs'
import { main } from './check-import-boundaries.mjs'
import { collectModuleSpecifiers } from './static-module-specifiers.mjs'
const roots = []
afterEach(() => {
vi.restoreAllMocks()
for (const root of roots.splice(0)) {
rmSync(root, { recursive: true, force: true })
}
})
function fixture(files = {}) {
const root = mkdtempSync(path.join(tmpdir(), 'orca-import-boundaries-'))
roots.push(root)
for (const [file, contents] of Object.entries({
'src/packages/process-host/package.json': JSON.stringify({ exports: { '.': './index.ts' } }),
'src/packages/process-host/src/index.ts': 'export {}',
'config/process-host-direct-import-baseline.txt': '',
...files
})) {
const target = path.join(root, file)
mkdirSync(path.dirname(target), { recursive: true })
writeFileSync(target, contents)
}
return root
}
it('parses candidate files once and reports violations from both guards', () => {
vi.spyOn(console, 'log').mockImplementation(() => {})
const error = vi.spyOn(console, 'error').mockImplementation(() => {})
const parseSpecifiers = vi.fn(collectModuleSpecifiers)
const root = fixture({
'src/main/consumer.ts': `import '@orca/process-host/private'
const entry = '../shared/workspace-layout/old-client/inner'
require(entry)`
})
expect(main(root, { parseSpecifiers })).toBe(1)
expect(
parseSpecifiers.mock.calls.filter(([file]) => file === 'src/main/consumer.ts')
).toHaveLength(1)
expect(error).toHaveBeenCalledWith(expect.stringContaining('not a public process-host export'))
const oldClient = COMPAT_FOLDERS.find(({ folder }) => folder.endsWith('/old-client'))
// The message names the folder's entry modules, whichever they are.
expect(error).toHaveBeenCalledWith(
expect.stringContaining(`through ${oldClient.entries.join(', ')}, not`)
)
})
it('uses fresh inputs on every invocation, including newly added files', () => {
vi.spyOn(console, 'log').mockImplementation(() => {})
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = fixture()
expect(main(root)).toBe(0)
mkdirSync(path.join(root, 'src/main'), { recursive: true })
writeFileSync(path.join(root, 'src/main/consumer.ts'), "import 'node:child_process'")
expect(main(root)).toBe(1)
})
it('does not cache a file across an edit at the same path', () => {
vi.spyOn(console, 'log').mockImplementation(() => {})
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = fixture({ 'src/main/consumer.ts': "import '@orca/process-host'" })
expect(main(root)).toBe(0)
writeFileSync(path.join(root, 'src/main/consumer.ts'), "import '@orca/process-host/private'")
expect(main(root)).toBe(1)
})
it('rejects malformed source and missing package implementations', () => {
expect(() => main(fixture({ 'src/main/broken.ts': 'import {' }))).toThrow('Cannot parse')
const root = fixture()
rmSync(path.join(root, 'src/packages/process-host/src'), { recursive: true })
expect(() => main(root)).toThrow('Missing process-host implementation')
})