diff --git a/src/shared/plugins/contributions/plugin-settings-contribution.test.ts b/src/shared/plugins/contributions/plugin-settings-contribution.test.ts index 0ba8e8e5de9..92f108365df 100644 --- a/src/shared/plugins/contributions/plugin-settings-contribution.test.ts +++ b/src/shared/plugins/contributions/plugin-settings-contribution.test.ts @@ -1,7 +1,6 @@ import { describe, expect, it } from 'vitest' -import { parseHostPluginManifest, parsePluginManifest } from '../manifest/plugin-manifest' +import { parsePluginManifest } from '../manifest/plugin-manifest' import { pluginSettingValueIssue } from './plugin-settings-contribution' -import { pluginSettingDefaults } from './plugin-settings-values' function manifest(settings: unknown[], capabilities = [{ kind: 'settings:own' }]) { return { @@ -29,36 +28,6 @@ function issues(raw: unknown): string { } describe('contributes.settings', () => { - it('accepts a typed setting list and reads defaults from it', () => { - const parsed = parseHostPluginManifest( - manifest([ - apiUrl, - { - key: 'pageSize', - title: 'Page size', - type: 'integer', - default: 20, - minimum: 1, - maximum: 100 - }, - { - key: 'mode', - title: 'Mode', - type: 'string', - enum: ['fast', 'safe'], - enumLabels: ['Fast', 'Safe'] - } - ]) - ) - expect(parsed.ok).toBe(true) - if (parsed.ok) { - expect(pluginSettingDefaults(parsed.manifest.contributes.settings)).toEqual({ - apiUrl: 'https://example.com', - pageSize: 20 - }) - } - }) - it('needs settings:own, unique keys, and defaults that fit the setting', () => { expect(issues(manifest([apiUrl], []))).toContain('settings:own') expect(issues(manifest([apiUrl, apiUrl]))).toContain('duplicate setting key') diff --git a/src/shared/plugins/declarative/plugin-declarative-catalog-rich.test.ts b/src/shared/plugins/declarative/plugin-declarative-catalog-rich.test.ts index c21827ea795..2b5f4f5ac06 100644 --- a/src/shared/plugins/declarative/plugin-declarative-catalog-rich.test.ts +++ b/src/shared/plugins/declarative/plugin-declarative-catalog-rich.test.ts @@ -1,13 +1,5 @@ import { describe, expect, it } from 'vitest' -import { - isPluginDeclarativeComponentName, - PLUGIN_DECLARATIVE_CATALOG -} from './plugin-declarative-catalog' import { isPluginDeclarativeImagePath } from './plugin-declarative-content-props' -import { - PLUGIN_DECLARATIVE_EDIT_PROP, - PLUGIN_DECLARATIVE_VALUE_CONTROLS -} from './plugin-declarative-message-names' import { PLUGIN_DECLARATIVE_LIMITS as LIMITS } from './plugin-declarative-limits' import { parsePluginDeclarativeTree } from './plugin-declarative-tree' @@ -20,51 +12,6 @@ const parse = (raw: unknown) => parsePluginDeclarativeTree(raw) const columns = [{ key: 'name', label: 'Name', sortable: true }] describe('catalog 2 components', () => { - it('gives every value control its value prop, change callback and edit tag', () => { - for (const [type, { value, change }] of Object.entries(PLUGIN_DECLARATIVE_VALUE_CONTROLS)) { - expect(isPluginDeclarativeComponentName(type)).toBe(true) - const shape: Record = isPluginDeclarativeComponentName(type) - ? PLUGIN_DECLARATIVE_CATALOG[type].props.shape - : {} - expect({ - type, - props: [value, change, PLUGIN_DECLARATIVE_EDIT_PROP].filter((p) => p in shape) - }).toEqual({ type, props: [value, change, PLUGIN_DECLARATIVE_EDIT_PROP] }) - } - }) - - it('accepts every new component in its place', () => { - const result = parse( - node('Stack', {}, [ - node('Field', { label: 'Notes', error: 'Required' }, [ - node('Textarea', { label: 'Notes', rows: 3 }) - ]), - node('Checkbox', { label: 'Agree', defaultChecked: true }), - node('RadioGroup', { label: 'Size', options: [{ value: 's', label: 'Small' }] }), - node('Slider', { label: 'Volume', min: 0, max: 10, step: 0.5 }), - node('Tabs', { label: 'Views', defaultValue: 'a' }, [ - node('Tab', { value: 'a', label: 'A' }, [node('Text', {}, ['first'])]), - node('Tab', { value: 'b', label: 'B' }) - ]), - node('Collapsible', { title: 'More' }, [node('Text', {}, ['hidden'])]), - node('Toolbar', { label: 'Actions' }, [node('Button', { tooltip: 'Run it' }, ['Run'])]), - node('Grid', { columns: 3 }, [node('Card', { title: 'One' })]), - node('Table', { label: 'Files', columns, rows: [{ key: 'r1', cells: { name: 'a.ts' } }] }), - node('Tree', { - label: 'Folders', - items: [{ key: 'src', label: 'src', children: [{ key: 'src/a', label: 'a' }] }] - }), - node('Markdown', { content: '# Hi\n\n[docs](https://example.com)' }), - node('CodeView', { code: 'let a = 1', language: 'typescript', lineNumbers: true }), - node('Image', { src: 'assets/logo.png', alt: 'Logo' }), - node('KeyValue', { items: [{ label: 'Branch', value: 'main', code: true }] }), - node('Callout', { tone: 'warning', title: 'Heads up' }, ['Careful']), - node('Skeleton', { lines: 2 }) - ]) - ) - expect(result).toMatchObject({ ok: true, warnings: [] }) - }) - it('keeps Tab inside Tabs and Tabs holding only Tab', () => { expect(parse(node('Stack', {}, [node('Tab', { value: 'a', label: 'A' })]))).toMatchObject({ ok: false, @@ -80,15 +27,6 @@ describe('catalog 2 components', () => { }) }) - it('keeps new controls out of a pressable ListItem', () => { - const result = parse( - node('List', {}, [ - node('ListItem', { onPress: { $callback: 'c1' } }, [node('Checkbox', { label: 'x' })]) - ]) - ) - expect(result).toMatchObject({ ok: false, error: expect.stringContaining('Checkbox') }) - }) - it('draws a placeholder for a Table or Tree with unusable data, and keeps the rest', () => { const duplicateRows = node('Table', { label: 'T', diff --git a/src/shared/plugins/declarative/plugin-declarative-relative-time.test.ts b/src/shared/plugins/declarative/plugin-declarative-relative-time.test.ts deleted file mode 100644 index 63e939845f4..00000000000 --- a/src/shared/plugins/declarative/plugin-declarative-relative-time.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { parsePluginDeclarativeTree } from './plugin-declarative-tree' -import { - formatPluginRelativeTime, - pluginRelativeTimeParts, - pluginRelativeTimeTickMs -} from './plugin-declarative-relative-time' - -const NOW = Date.UTC(2026, 10, 1, 12) - -describe('relative time', () => { - it('picks the largest whole unit and words it in each format', () => { - expect(pluginRelativeTimeParts(-45_000)).toEqual({ value: -45, unit: 'second' }) - expect(pluginRelativeTimeParts(-5 * 60_000 - 10)).toEqual({ value: -5, unit: 'minute' }) - expect(pluginRelativeTimeParts(3 * 86_400_000)).toEqual({ value: 3, unit: 'day' }) - const at = NOW - 5 * 60_000 - expect(formatPluginRelativeTime(at, NOW, 'short', 'en')).toBe('5m ago') - expect(formatPluginRelativeTime(at, NOW, 'long', 'en')).toBe('5 minutes ago') - expect(formatPluginRelativeTime(at, NOW, 'duration', 'en')).toBe('5m') - expect(formatPluginRelativeTime(NOW + 2 * 3_600_000, NOW, 'long', 'en')).toBe('in 2 hours') - }) - - it('ticks often only while the words change often', () => { - expect(pluginRelativeTimeTickMs(-10_000)).toBe(1000) - expect(pluginRelativeTimeTickMs(-10 * 60_000)).toBe(15_000) - expect(pluginRelativeTimeTickMs(-5 * 3_600_000)).toBe(300_000) - }) - - it('accepts RelativeTime inside Text and relative Table cells', () => { - const parsed = parsePluginDeclarativeTree({ - type: 'Stack', - props: {}, - children: [ - { - type: 'Text', - props: {}, - children: ['Started ', { type: 'RelativeTime', props: { at: NOW, format: 'long' } }] - }, - { - type: 'Table', - props: { - label: 'Agents', - columns: [{ key: 'since', label: 'Since' }], - rows: [ - { key: 'a', cells: { since: { type: 'relative', at: NOW, format: 'duration' } } } - ] - } - } - ] - }) - expect(parsed).toMatchObject({ ok: true, warnings: [] }) - const bad = parsePluginDeclarativeTree({ - type: 'RelativeTime', - props: { at: Number.POSITIVE_INFINITY } - }) - expect(bad.ok && bad.tree?.type).toBe('Unsupported') - }) -}) diff --git a/src/shared/plugins/declarative/plugin-declarative-tree.test.ts b/src/shared/plugins/declarative/plugin-declarative-tree.test.ts index e5e07a358d6..c82be4688ed 100644 --- a/src/shared/plugins/declarative/plugin-declarative-tree.test.ts +++ b/src/shared/plugins/declarative/plugin-declarative-tree.test.ts @@ -1,13 +1,5 @@ import { describe, expect, it } from 'vitest' -import { - PLUGIN_DECLARATIVE_CATALOG, - PLUGIN_DECLARATIVE_COMPONENT_NAMES -} from './plugin-declarative-catalog' import { PLUGIN_DECLARATIVE_LIMITS } from './plugin-declarative-limits' -import { - PLUGIN_DECLARATIVE_COMPONENT_PROPS, - PLUGIN_DECLARATIVE_EDIT_PROP -} from './plugin-declarative-message-names' import { parsePluginDeclarativeRender, pluginDeclarativeEventPayloadSchema @@ -26,47 +18,6 @@ function errorOf(tree: unknown): string { } describe('parsePluginDeclarativeTree', () => { - it('keeps the zod catalog and the runtime prop table in step', () => { - expect([...PLUGIN_DECLARATIVE_COMPONENT_NAMES].sort()).toEqual( - Object.keys(PLUGIN_DECLARATIVE_COMPONENT_PROPS).sort() - ) - for (const name of PLUGIN_DECLARATIVE_COMPONENT_NAMES) { - const zodProps = Object.keys(PLUGIN_DECLARATIVE_CATALOG[name].props.shape).filter( - (prop) => prop !== PLUGIN_DECLARATIVE_EDIT_PROP - ) - const runtimeProps: readonly string[] = PLUGIN_DECLARATIVE_COMPONENT_PROPS[name] - expect({ name, props: [...runtimeProps].sort() }).toEqual({ name, props: zodProps.sort() }) - } - }) - - it('accepts a valid tree, normalizes numbers and drops nothing it knows', () => { - const code = node('Code', {}, ['x']) - const text = node('Text', { tone: 'accent', muted: true }, ['Count ', 4, code]) - const rest = [ - node('Button', { onPress: { $callback: 'c1' }, icon: 'add', tone: 'danger' }, ['Add']), - node('List', { label: 'Items' }, [{ ...node('ListItem', { title: 'A' }), key: 'a' }]), - node('Select', { - label: 'Pick', - options: [{ value: 'a', label: 'A' }], - onChange: { $callback: 'c2' } - }), - node('Link', { href: 'https://example.com' }, ['docs']) - ] - const tree = node('Stack', { gap: 'sm' }, [text, ...rest]) - const result = parsePluginDeclarativeTree(tree) - expect(result).toMatchObject({ ok: true, nodes: 8, warnings: [] }) - expect(result.ok && result.tree).toEqual({ - ...tree, - children: [{ ...text, children: ['Count ', '4', code] }, ...rest] - }) - expect(parsePluginDeclarativeTree(null)).toEqual({ - ok: true, - tree: null, - nodes: 0, - warnings: [] - }) - }) - it('drops unknown props and enum values with a warning instead of refusing', () => { const result = parsePluginDeclarativeTree( node('Stack', { className: 'p-4', gap: 'huge' }, [ @@ -134,11 +85,6 @@ describe('parsePluginDeclarativeTree', () => { expect(errorOf(tree)).toMatch(message) }) - it('allows controls inside a ListItem that has no onPress', () => { - const tree = node('List', {}, [node('ListItem', {}, [node('Button', {}, ['x'])])]) - expect(parsePluginDeclarativeTree(tree).ok).toBe(true) - }) - it('caps depth without recursing', () => { let tree = node('Text') for (let depth = 0; depth < 10_000; depth++) { diff --git a/src/shared/plugins/declarative/plugin-declarative-typings.test.ts b/src/shared/plugins/declarative/plugin-declarative-typings.test.ts deleted file mode 100644 index 914e7885350..00000000000 --- a/src/shared/plugins/declarative/plugin-declarative-typings.test.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { readFileSync } from 'node:fs' -import path from 'node:path' -import ts from 'typescript-api' -import { describe, expect, it } from 'vitest' -import { - PLUGIN_DECLARATIVE_CATALOG, - PLUGIN_DECLARATIVE_COMPONENT_NAMES, - PLUGIN_DECLARATIVE_ICONS, - PLUGIN_DECLARATIVE_TONES -} from './plugin-declarative-catalog' -import { spliceOrcaHostTypings } from './plugin-declarative-host-typings' -import * as orcaModule from './runtime/orca-module' - -const DECLARATIVE = path.resolve(import.meta.dirname, '../../../../resources/plugins/declarative') -const TYPINGS = path.join(DECLARATIVE, 'orca.d.ts') -// The `orca` module spans these files; `orca plugin types` writes them as one. -const FILES = [ - 'orca.d.ts', - 'orca-components.d.ts', - 'orca-components-layout.d.ts', - 'orca-components-data.d.ts' -] - -function orcaModules(): ts.ModuleBlock[] { - return FILES.flatMap((file) => { - const full = path.join(DECLARATIVE, file) - const source = ts.createSourceFile( - full, - readFileSync(full, 'utf8'), - ts.ScriptTarget.Latest, - true - ) - return source.statements.flatMap((statement) => - ts.isModuleDeclaration(statement) && - ts.isStringLiteral(statement.name) && - statement.name.text === 'orca' && - statement.body && - ts.isModuleBlock(statement.body) - ? [statement.body] - : [] - ) - }) -} - -const aliases = new Map() -const components = new Map() -for (const block of orcaModules()) { - for (const statement of block.statements) { - if (ts.isTypeAliasDeclaration(statement)) { - aliases.set(statement.name.text, statement.type) - } - if (ts.isVariableStatement(statement)) { - for (const declaration of statement.declarationList.declarations) { - const type = declaration.type - if ( - ts.isIdentifier(declaration.name) && - type && - ts.isTypeReferenceNode(type) && - type.typeName.getText() === 'OrcaComponent' && - type.typeArguments?.[0] - ) { - components.set(declaration.name.text, type.typeArguments[0].getText()) - } - } - } - } -} - -/** String literals of a union, following local aliases; null when it is not a literal union. */ -function literals(node: ts.TypeNode): string[] | null { - if (ts.isTypeReferenceNode(node)) { - const target = aliases.get(node.typeName.getText()) - return target ? literals(target) : null - } - if (ts.isUnionTypeNode(node)) { - const parts = node.types.map(literals) - return parts.every((part) => part !== null) ? parts.flat() : null - } - if (ts.isLiteralTypeNode(node) && ts.isStringLiteral(node.literal)) { - return [node.literal.text] - } - return null -} - -type Member = { optional: boolean; type: ts.TypeNode | undefined } - -/** Members of a props alias such as `WithChildren & { ... }`, plus whether it is a leaf. */ -function propsOf(alias: string): { members: Map; leaf: boolean } { - const node = aliases.get(alias) - if (!node) { - throw new Error(`orca.d.ts has no type ${alias}`) - } - const parts = ts.isIntersectionTypeNode(node) ? node.types : [node] - const members = new Map() - let leaf = false - for (const part of parts) { - if (ts.isTypeReferenceNode(part)) { - leaf ||= part.typeName.getText() === 'Leaf' - } else if (ts.isTypeLiteralNode(part)) { - for (const member of part.members) { - if (ts.isPropertySignature(member) && member.name) { - members.set(member.name.getText(), { - optional: member.questionToken !== undefined, - type: member.type - }) - } - } - } - } - return { members, leaf } -} - -type ShapeEntry = { - safeParse(value: unknown): { success: boolean } - unwrap?: () => unknown -} - -function enumOptions(schema: ShapeEntry): string[] | null { - const inner: unknown = schema.unwrap ? schema.unwrap() : schema - const options: unknown = - typeof inner === 'object' && inner !== null && 'options' in inner ? inner.options : undefined - return Array.isArray(options) && options.every((option) => typeof option === 'string') - ? options - : null -} - -describe('orca.d.ts matches the catalog', () => { - it('declares exactly the catalog components', () => { - expect([...components.keys()].sort()).toEqual([...PLUGIN_DECLARATIVE_COMPONENT_NAMES].sort()) - }) - - it.each(PLUGIN_DECLARATIVE_COMPONENT_NAMES)('%s props, requiredness and enums', (name) => { - const entry = PLUGIN_DECLARATIVE_CATALOG[name] - const shape: Record = entry.props.shape - const { members, leaf } = propsOf(components.get(name) ?? '') - expect(leaf).toBe(entry.children === 'none') - // `$`-props are wire-only (the runtime adds them); authors never write them. - const authored = Object.entries(shape).filter(([prop]) => !prop.startsWith('$')) - expect([...members.keys()].sort()).toEqual(authored.map(([prop]) => prop).sort()) - for (const [prop, schema] of authored) { - const member = members.get(prop) - expect({ prop, optional: member?.optional }).toEqual({ - prop, - optional: schema.safeParse(undefined).success - }) - const options = enumOptions(schema) - if (options && member?.type) { - expect({ prop, values: literals(member.type)?.sort() }).toEqual({ - prop, - values: [...options].sort() - }) - } - } - }) - - it('lists the same component names, and generates host methods from the host API table', () => { - expect(literals(aliases.get('ComponentName')!)?.sort()).toEqual( - [...PLUGIN_DECLARATIVE_COMPONENT_NAMES].sort() - ) - const file = readFileSync(TYPINGS, 'utf8') - expect(spliceOrcaHostTypings(file)).toBe(file) - }) - - it('exports every catalog component from the guest `orca` module, as its own tag', () => { - const exported: Record = { ...orcaModule } - for (const name of PLUGIN_DECLARATIVE_COMPONENT_NAMES) { - expect({ name, tag: exported[name] }).toEqual({ name, tag: name }) - } - }) - - it('names the same tones and icons', () => { - expect(literals(aliases.get('Tone')!)?.sort()).toEqual([...PLUGIN_DECLARATIVE_TONES].sort()) - expect(literals(aliases.get('IconName')!)?.sort()).toEqual([...PLUGIN_DECLARATIVE_ICONS].sort()) - }) -}) diff --git a/src/shared/plugins/declarative/runtime/declarative-error-location.test.ts b/src/shared/plugins/declarative/runtime/declarative-error-location.test.ts index 9e17638b940..75370304596 100644 --- a/src/shared/plugins/declarative/runtime/declarative-error-location.test.ts +++ b/src/shared/plugins/declarative/runtime/declarative-error-location.test.ts @@ -69,10 +69,4 @@ describe('plugin errors as logged', () => { }) expect(describePluginError(refused, base)).toBe('src/lib/a.ts:2:19: cannot import "react"') }) - - it('logs the plain stack outside a guest', () => { - const error = Object.assign(new Error('boom'), { stack: 'Error: boom\n at x (/a.js:1:1)' }) - expect(describePluginErrorForLog(error, null)).toBe('Error: boom\n at x (/a.js:1:1)') - expect(describePluginErrorForLog('thrown', base)).toBe('thrown') - }) }) diff --git a/src/shared/plugins/declarative/runtime/declarative-hot-reload.test.ts b/src/shared/plugins/declarative/runtime/declarative-hot-reload.test.ts index 03fb4bf4a82..698c29da448 100644 --- a/src/shared/plugins/declarative/runtime/declarative-hot-reload.test.ts +++ b/src/shared/plugins/declarative/runtime/declarative-hot-reload.test.ts @@ -1,12 +1,6 @@ import { afterEach, describe, expect, it, vi } from 'vitest' -import { PLUGIN_FRAME_RESERVED_SEGMENT } from '../../frames/plugin-frame-guest' import { atom, read, set } from './declarative-atoms' import { h } from './declarative-elements' -import { - describePluginError, - ORCA_RESERVED_PATH_PREFIX, - pluginErrorLocation -} from './declarative-error-location' import { createOrcaDeclarativeRuntime, type OrcaBridge } from './declarative-renderer' function booted() { @@ -120,32 +114,3 @@ describe('dev hot reload of keyed memory atoms', () => { runtime.dispose() }) }) - -describe('plugin error locations', () => { - const base = 'orca-plugin-frame://0123456789abcdef/' - - it('names the first plugin stack frame, skipping Orca runtime frames', () => { - const stack = [ - 'TypeError: x is undefined', - ` at evaluate (${base}__orca/orca-runtime.mjs:120:7)`, - ` at Panel (${base}src/my%20panel.tsx:12:5)`, - ` at ${base}src/other.ts:1:1` - ].join('\n') - expect(pluginErrorLocation(stack, base)).toBe('src/my panel.tsx:12:5') - const error = Object.assign(new TypeError('x is undefined'), { stack }) - expect(describePluginError(error, base)).toBe('src/my panel.tsx:12:5: x is undefined') - }) - - it("keeps a message that already names its file (Orca's transpile errors)", () => { - const error = Object.assign(new Error('src/panel.tsx:3:5: Unexpected token'), { - stack: `Error: src/panel.tsx:3:5: Unexpected token\n at ${base}src/panel.tsx:1:7` - }) - expect(describePluginError(error, base)).toBe('src/panel.tsx:3:5: Unexpected token') - }) - - it('falls back to the bare message outside a guest or without a plugin frame', () => { - expect(describePluginError(new Error('boom'), null)).toBe('boom') - expect(describePluginError('thrown string', base)).toBe('thrown string') - expect(ORCA_RESERVED_PATH_PREFIX).toBe(`/${PLUGIN_FRAME_RESERVED_SEGMENT}/`) - }) -}) diff --git a/src/shared/plugins/declarative/runtime/declarative-lifecycle.test.ts b/src/shared/plugins/declarative/runtime/declarative-lifecycle.test.ts index 72df95426e4..aae1ae25e8e 100644 --- a/src/shared/plugins/declarative/runtime/declarative-lifecycle.test.ts +++ b/src/shared/plugins/declarative/runtime/declarative-lifecycle.test.ts @@ -135,14 +135,6 @@ describe('components panel lifecycle', () => { expect(seen.signal?.aborted).toBe(true) }) - it('says clearly when the module has no component', async () => { - const { runtime, host } = booted() - host.send('ui.hydrate', {}) - await expect(runtime.boot({ default: 'nope' })).rejects.toThrow( - /must export a component function as its default export \(got string\)/ - ) - }) - it('refuses duplicate atom keys', () => { atom('lifecycle.once', 1) expect(() => atom('lifecycle.once', 2)).toThrow(/already used/) diff --git a/src/shared/plugins/declarative/testing/orca-testing-plugin-data.test.ts b/src/shared/plugins/declarative/testing/orca-testing-plugin-data.test.ts index e69811e5f56..ec499552b79 100644 --- a/src/shared/plugins/declarative/testing/orca-testing-plugin-data.test.ts +++ b/src/shared/plugins/declarative/testing/orca-testing-plugin-data.test.ts @@ -89,9 +89,4 @@ describe('orca/testing and the plugin bridge', () => { await expect(settings.get('theme')).resolves.toBe('dark') expect(host.data().storage).toEqual({ filter: 'open' }) }) - - it('refuses storage without the capability, as Orca would', async () => { - panel = await mount(() => h('Text', null, 'x'), { host: mockHost({ capabilities: [] }) }) - await expect(storage.get('k')).rejects.toMatchObject({ code: 'capability_denied' }) - }) }) diff --git a/src/shared/plugins/declarative/testing/orca-testing-rich.test.ts b/src/shared/plugins/declarative/testing/orca-testing-rich.test.ts index 804a2fb120e..e0d5f9ef200 100644 --- a/src/shared/plugins/declarative/testing/orca-testing-rich.test.ts +++ b/src/shared/plugins/declarative/testing/orca-testing-rich.test.ts @@ -158,41 +158,3 @@ describe('orca/testing with catalog 2', () => { expect(panel.errors).toEqual([]) }) }) - -describe('summary and responsive columns', () => { - it('summarizes what a person notices first, and which columns fit a width', async () => { - panel = await mount(() => - h( - 'Stack', - null, - h('Heading', null, 'Review queue'), - h('Callout', { tone: 'danger', title: 'Could not load the queue' }, 'offline'), - h('Table', { - label: 'PRs', - columns: [ - { key: 'title', label: 'Title', minWidth: 'sm' }, - { key: 'author', label: 'Author', hideBelow: 'sm' }, - { key: 'checks', label: 'Checks', hideBelow: 'md' } - ], - rows: [ - { key: 'a', cells: { title: 'One' } }, - { key: 'b', cells: { title: 'Two' } } - ] - }), - h('List', { label: 'Later' }, h('ListItem', { title: 'x' })), - h('EmptyState', { title: 'All caught up' }) - ) - ) - expect(panel.summary()).toEqual([ - 'Heading "Review queue"', - 'Callout danger "Could not load the queue"', - 'Table "PRs": 2 row(s)', - 'List "Later": 1 item(s)', - 'EmptyState "All caught up"' - ]) - const table = { type: 'Table' } - expect(panel.columnsOf(table)).toEqual(['title', 'author', 'checks']) - expect(panel.columnsOf(table, { width: 400 })).toEqual(['title', 'author']) - expect(panel.columnsOf(table, { width: 300 })).toEqual(['title']) - }) -}) diff --git a/src/shared/plugins/declarative/testing/orca-testing-worker.test.ts b/src/shared/plugins/declarative/testing/orca-testing-worker.test.ts index 6f678301458..a9705ddc9d2 100644 --- a/src/shared/plugins/declarative/testing/orca-testing-worker.test.ts +++ b/src/shared/plugins/declarative/testing/orca-testing-worker.test.ts @@ -1,5 +1,4 @@ -import { afterEach, describe, expect, it, vi } from 'vitest' -import { exportedTypeShape, runtimeShape } from '../../authoring/plugin-author-typings.test-fixture' +import { afterEach, describe, expect, it } from 'vitest' import { agentStatusChangedPayloadSchema } from '../../events/plugin-events' import { atom, read, set } from '../runtime/declarative-atoms' import { h } from '../runtime/declarative-elements' @@ -128,15 +127,6 @@ describe('mountWorker', () => { ) ).rejects.toThrow(/registered undeclared command other/) }) - - it('hands activate the same shape of orca object as Orca does', async () => { - let captured: unknown - await mountWorker( - { default: (orca: unknown) => (captured = orca) }, - { events: [], commands: [] } - ) - expect(runtimeShape(captured)).toEqual(exportedTypeShape('orca/worker', 'OrcaWorkerApi').shape) - }) }) describe('panel refusals', () => { @@ -197,30 +187,3 @@ describe('a panel and its worker on one host', () => { await worker.deactivate() }) }) - -describe('RelativeTime in the test kit', () => { - afterEach(() => { - vi.useRealTimers() - }) - - it('reads as Orca draws it now, in a node and in a Table cell', async () => { - // Only Date is faked: the kit settles on real macrotasks. - vi.useFakeTimers({ now: Date.UTC(2026, 10, 1, 12), toFake: ['Date'] }) - const at = Date.UTC(2026, 10, 1, 12) - 5 * 60_000 - panel = await mount(() => - h( - 'Stack', - null, - h('Text', null, 'Started ', h('RelativeTime', { at })), - h('Table', { - label: 'Agents', - columns: [{ key: 'since', label: 'Since' }], - rows: [{ key: 'a', cells: { since: { type: 'relative', at, format: 'duration' } } }] - }) - ) - ) - expect(panel.find({ role: 'time' })?.text).toBe('5m ago') - expect(panel.find({ role: 'grid' })?.text).toBe('5m') - expect(panel.warnings).toEqual([]) - }) -}) diff --git a/src/shared/plugins/declarative/testing/orca-testing.test.ts b/src/shared/plugins/declarative/testing/orca-testing.test.ts index e0fe80f497b..297b004cfb4 100644 --- a/src/shared/plugins/declarative/testing/orca-testing.test.ts +++ b/src/shared/plugins/declarative/testing/orca-testing.test.ts @@ -1,7 +1,7 @@ import { afterEach, describe, expect, it } from 'vitest' import { atom, read, set, update } from '../runtime/declarative-atoms' import { h } from '../runtime/declarative-elements' -import { host, on, shell } from '../runtime/orca-module' +import { host, shell } from '../runtime/orca-module' import { hostError, mockHost, mount, stored, type TestPanel } from './orca-testing' let panel: TestPanel | null = null @@ -156,28 +156,6 @@ describe('orca/testing', () => { ]) }) - it('delivers events and visibility, and runs setup cleanup on unmount', async () => { - const seen: string[] = [] - let cleaned = false - panel = await mount({ - setup: (ctx: { - subscriptions: { dispose(): void }[] - visible: Parameters>[0] - }) => { - ctx.subscriptions.push(on('theme', (payload) => seen.push(JSON.stringify(payload)))) - return () => { - cleaned = true - } - }, - default: () => h('Text', null, 'x') - }) - await panel.emit('theme', { colorScheme: 'light' }) - expect(seen).toEqual(['{"colorScheme":"light"}']) - await panel.unmount() - panel = null - expect(cleaned).toBe(true) - }) - it('fails a test that never settles instead of hanging', async () => { const ticks = atom(0) const loop = () => { diff --git a/src/shared/plugins/frames/plugin-frame-facades.test.ts b/src/shared/plugins/frames/plugin-frame-facades.test.ts index 4b16529e538..ef89ac0bc3f 100644 --- a/src/shared/plugins/frames/plugin-frame-facades.test.ts +++ b/src/shared/plugins/frames/plugin-frame-facades.test.ts @@ -56,17 +56,6 @@ describe('window.orca.plugin', () => { answer(sent.id, { output: [{ id: '1' }] }) await expect(todos).resolves.toEqual([{ id: '1' }]) }) - - it('hands worker posts to plugin.on by event name', () => { - const { orca, push } = mountShell() - const changed = vi.fn() - const other = vi.fn() - orca.plugin.on('todos.changed', changed) - orca.plugin.on('other', other) - push({ kind: 'message', event: 'todos.changed', payload: { count: 3 } }) - expect(changed).toHaveBeenCalledWith({ count: 3 }) - expect(other).not.toHaveBeenCalled() - }) }) describe('window.orca events and data', () => { @@ -85,21 +74,4 @@ describe('window.orca events and data', () => { push({ kind: 'event', event: 'agent.status.changed', payload: { state: 'done' } }) expect(first).toHaveBeenCalledWith({ state: 'done' }) }) - - it('reads storage and settings, and hears which key changed', async () => { - const { orca, requests, answer, push } = mountShell() - const value = orca.storage.get('todos') - const setting = orca.settings.get('apiUrl') - const [get, settings] = requests() - answer(get.id, { value: null }) - answer(settings.id, { settings: { apiUrl: 'https://x' } }) - await expect(value).resolves.toBeNull() - await expect(setting).resolves.toBe('https://x') - const changed = vi.fn() - orca.storage.onDidChange(changed) - push({ kind: 'changed', area: 'settings', key: 'apiUrl' }) - push({ kind: 'changed', area: 'storage', key: 'todos' }) - expect(changed).toHaveBeenCalledOnce() - expect(changed).toHaveBeenCalledWith({ key: 'todos' }) - }) }) diff --git a/src/shared/plugins/frames/plugin-frame-guest.test.ts b/src/shared/plugins/frames/plugin-frame-guest.test.ts index cd4e05cd26c..82c8e3dbb13 100644 --- a/src/shared/plugins/frames/plugin-frame-guest.test.ts +++ b/src/shared/plugins/frames/plugin-frame-guest.test.ts @@ -1,4 +1,3 @@ -import { createHash } from 'node:crypto' import { describe, expect, it } from 'vitest' import { isPluginFrameOriginUrl, @@ -12,11 +11,6 @@ import { const KEY = pluginFrameKey('acme.charts') describe('plugin frame guest identity', () => { - it('derives the key as the first 16 hex chars of sha256(publisher.id)', () => { - expect(KEY).toBe(createHash('sha256').update('acme.charts').digest('hex').slice(0, 16)) - expect(pluginFrameKey('acme.other')).not.toBe(KEY) - }) - it('round-trips the partition and refuses look-alikes', () => { expect(pluginFramePartition(KEY)).toBe(`persist:orca-plugin-${KEY}`) expect(readPluginFramePartitionKey(pluginFramePartition(KEY))).toBe(KEY) diff --git a/src/shared/plugins/frames/plugin-frame-typings.test.ts b/src/shared/plugins/frames/plugin-frame-typings.test.ts deleted file mode 100644 index 9860e719739..00000000000 --- a/src/shared/plugins/frames/plugin-frame-typings.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -// @vitest-environment happy-dom - -import { describe, expect, it } from 'vitest' -import { - exportedTypeShape, - runtimeShape, - type TypingsShape -} from '../authoring/plugin-author-typings.test-fixture' -import { buildPluginGuestShellHtml, buildPluginPanelShellHtml } from './plugin-panel-shell' - -/** The `window.orca` a frame shell defines, read without leaving it on the test window. */ -function frameOrca(html: string): unknown { - const script = html.match(/