Skip to content

Commit 453d28e

Browse files
committed
test(contracts): drive interactor-operation conformance from the catalog itself
The completeness gate read raw test sources and regex-matched operation literals, so a commented-out row still counted as conformed while nothing executed it. The three binding rules now live in one test file that walks INTERACTOR_OPERATIONS and binds through each catalog row's own bind and label, with the per-operation expectations (interactor method, minimal input) in a table typed over every catalog operation. A missing, duplicated or unregistered row fails typecheck and the table-vs-catalog test; every row is executed by construction. The conformance fixture and the per-facet conformInteractorOperations blocks are gone; each facet test keeps only its dedicated tests.
1 parent a87c698 commit 453d28e

12 files changed

Lines changed: 172 additions & 344 deletions

packages/contracts/src/alert-runtime.test.ts

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { expect, test, vi } from 'vitest';
22
import { alertRuntimeOperationFacts, bindAlertLeg } from './alert-runtime.ts';
33
import { localInteractorSource } from './interactor-operation-binding.ts';
4-
import { conformInteractorOperations } from './interactor-operation-conformance.fixtures.ts';
54
import type { AlertInteractorOptions, Interactor } from './interactor-types.ts';
65

76
const device = {
@@ -15,7 +14,10 @@ const device = {
1514

1615
test('builds the exact alert operation fact catalog', () => {
1716
const read = { available: true } as const;
18-
const wait = { available: false, reason: 'owner-capability-missing' } as const;
17+
const wait = {
18+
available: false,
19+
reason: 'owner-capability-missing',
20+
} as const;
1921
const accept = { available: true } as const;
2022
const dismiss = { available: true } as const;
2123

@@ -51,7 +53,11 @@ test('each local leg forwards the window and the session target to its own owner
5153
await bindAlertLeg('acceptAlert', signal, source).acceptAlert(input);
5254
await bindAlertLeg('dismissAlert', signal, source).dismissAlert(input);
5355

54-
const expectedOptions = { timeoutMs: 37, appBundleId: 'com.example.app', surface: 'app' };
56+
const expectedOptions = {
57+
timeoutMs: 37,
58+
appBundleId: 'com.example.app',
59+
surface: 'app',
60+
};
5561
expect(legs.readAlert).toHaveBeenCalledWith(expectedOptions);
5662
expect(legs.awaitAlert).toHaveBeenCalledWith(expectedOptions);
5763
expect(legs.acceptAlert).toHaveBeenCalledWith(expectedOptions);
@@ -76,37 +82,3 @@ test('an absent target field never reaches the owner as an explicit undefined',
7682
expect(readAlert).toHaveBeenCalledWith({ surface: 'frontmost-app' });
7783
expect(Object.keys(readAlert.mock.calls[0]?.[0] ?? {})).toEqual(['surface']);
7884
});
79-
80-
conformInteractorOperations({
81-
device,
82-
rows: [
83-
{
84-
operation: 'readAlert',
85-
label: 'alert get',
86-
bind: (signal, resolve) => bindAlertLeg('readAlert', signal, resolve),
87-
method: 'readAlert',
88-
input: {},
89-
},
90-
{
91-
operation: 'awaitAlert',
92-
label: 'alert wait',
93-
bind: (signal, resolve) => bindAlertLeg('awaitAlert', signal, resolve),
94-
method: 'awaitAlert',
95-
input: {},
96-
},
97-
{
98-
operation: 'acceptAlert',
99-
label: 'alert accept',
100-
bind: (signal, resolve) => bindAlertLeg('acceptAlert', signal, resolve),
101-
method: 'acceptAlert',
102-
input: {},
103-
},
104-
{
105-
operation: 'dismissAlert',
106-
label: 'alert dismiss',
107-
bind: (signal, resolve) => bindAlertLeg('dismissAlert', signal, resolve),
108-
method: 'dismissAlert',
109-
input: {},
110-
},
111-
],
112-
});

packages/contracts/src/app-event-runtime.test.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { expect, test, vi } from 'vitest';
22
import { appEventRuntimeOperationFacts, bindAppEvent } from './app-event-runtime.ts';
33
import type { Interactor } from './interactor-types.ts';
44
import { localInteractorSource } from './interactor-operation-binding.ts';
5-
import { conformInteractorOperations } from './interactor-operation-conformance.fixtures.ts';
65

76
const device = {
87
platform: 'android',
@@ -14,7 +13,9 @@ const device = {
1413

1514
test('builds the exact app-event operation fact catalog', () => {
1615
const triggerAppEvent = { available: true } as const;
17-
expect(appEventRuntimeOperationFacts({ triggerAppEvent })).toEqual({ triggerAppEvent });
16+
expect(appEventRuntimeOperationFacts({ triggerAppEvent })).toEqual({
17+
triggerAppEvent,
18+
});
1819
});
1920

2021
// The URL is resolved daemon-side from the event name, payload, and per-platform template; what
@@ -41,16 +42,3 @@ test('a local binding opens the resolved event URL against the session app', asy
4142
appBundleId: 'com.example.app',
4243
});
4344
});
44-
45-
conformInteractorOperations({
46-
device,
47-
rows: [
48-
{
49-
operation: 'triggerAppEvent',
50-
label: 'trigger-app-event',
51-
bind: bindAppEvent,
52-
method: 'open',
53-
input: { eventUrl: 'myapp://x' },
54-
},
55-
],
56-
});

packages/contracts/src/app-switcher-runtime.test.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { expect, test, vi } from 'vitest';
22
import { appSwitcherRuntimeOperationFacts, bindAppSwitcher } from './app-switcher-runtime.ts';
33
import type { Interactor } from './interactor-types.ts';
44
import { localInteractorSource } from './interactor-operation-binding.ts';
5-
import { conformInteractorOperations } from './interactor-operation-conformance.fixtures.ts';
65

76
const device = {
87
platform: 'android',
@@ -14,7 +13,9 @@ const device = {
1413

1514
test('builds the exact app-switcher operation fact catalog', () => {
1615
const appSwitcher = { available: true } as const;
17-
expect(appSwitcherRuntimeOperationFacts({ appSwitcher })).toEqual({ appSwitcher });
16+
expect(appSwitcherRuntimeOperationFacts({ appSwitcher })).toEqual({
17+
appSwitcher,
18+
});
1819
});
1920

2021
test('a local binding drives the interactor with the request runner context', async () => {
@@ -36,16 +37,3 @@ test('a local binding drives the interactor with the request runner context', as
3637
});
3738
expect(appSwitcher).toHaveBeenCalledOnce();
3839
});
39-
40-
conformInteractorOperations({
41-
device,
42-
rows: [
43-
{
44-
operation: 'appSwitcher',
45-
label: 'app-switcher',
46-
bind: bindAppSwitcher,
47-
method: 'appSwitcher',
48-
input: {},
49-
},
50-
],
51-
});

packages/contracts/src/back-runtime.test.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { expect, test, vi } from 'vitest';
22
import { bindBack, backRuntimeOperationFacts } from './back-runtime.ts';
33
import type { Interactor } from './interactor-types.ts';
44
import { localInteractorSource } from './interactor-operation-binding.ts';
5-
import { conformInteractorOperations } from './interactor-operation-conformance.fixtures.ts';
65

76
const device = {
87
platform: 'android',
@@ -37,16 +36,3 @@ test('a local binding drives the interactor with the requested mode', async () =
3736
});
3837
expect(back).toHaveBeenCalledWith('system');
3938
});
40-
41-
conformInteractorOperations({
42-
device,
43-
rows: [
44-
{
45-
operation: 'back',
46-
label: 'back',
47-
bind: bindBack,
48-
method: 'back',
49-
input: {},
50-
},
51-
],
52-
});

packages/contracts/src/clipboard-runtime.test.ts

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
localInteractorSource,
1010
type LocalInteractorOperationResolver,
1111
} from './interactor-operation-binding.ts';
12-
import { conformInteractorOperations } from './interactor-operation-conformance.fixtures.ts';
1312

1413
const device = {
1514
platform: 'android',
@@ -24,7 +23,10 @@ const local = (resolveInteractor: LocalInteractorOperationResolver) =>
2423

2524
test('builds the exact clipboard operation fact catalog', () => {
2625
const read = { available: true } as const;
27-
const write = { available: false, reason: 'owner-capability-missing' } as const;
26+
const write = {
27+
available: false,
28+
reason: 'owner-capability-missing',
29+
} as const;
2830
expect(clipboardRuntimeOperationFacts({ read, write })).toEqual({
2931
readClipboard: read,
3032
writeClipboard: write,
@@ -61,23 +63,3 @@ test('a local write binding hands the interactor the already-joined text', async
6163

6264
expect(writeClipboard).toHaveBeenCalledWith('hello world');
6365
});
64-
65-
conformInteractorOperations({
66-
device,
67-
rows: [
68-
{
69-
operation: 'readClipboard',
70-
label: 'clipboard read',
71-
bind: bindClipboardRead,
72-
method: 'readClipboard',
73-
input: {},
74-
},
75-
{
76-
operation: 'writeClipboard',
77-
label: 'clipboard write',
78-
bind: bindClipboardWrite,
79-
method: 'writeClipboard',
80-
input: { text: '' },
81-
},
82-
],
83-
});

packages/contracts/src/home-runtime.test.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { expect, test, vi } from 'vitest';
22
import { bindHome, homeRuntimeOperationFacts } from './home-runtime.ts';
33
import type { Interactor } from './interactor-types.ts';
44
import { localInteractorSource } from './interactor-operation-binding.ts';
5-
import { conformInteractorOperations } from './interactor-operation-conformance.fixtures.ts';
65

76
const device = {
87
platform: 'android',
@@ -36,8 +35,3 @@ test('a local binding drives the interactor with no arguments', async () => {
3635
});
3736
expect(home).toHaveBeenCalledWith();
3837
});
39-
40-
conformInteractorOperations({
41-
device,
42-
rows: [{ operation: 'home', label: 'home', bind: bindHome, method: 'home', input: {} }],
43-
});

packages/contracts/src/interactor-operation-conformance.fixtures.ts

Lines changed: 0 additions & 110 deletions
This file was deleted.

0 commit comments

Comments
 (0)