Skip to content

Commit 9509699

Browse files
os-zhuangclaude
andauthored
test(data-objectstack): pin getObjectSchema's validations pass-through (inert-metadata guard) (#2117)
The inline select editor filters its options by the object's `state_machine` validation (#2110); that only works because `getObjectSchema` passes the served `validations` through untouched. Today that's verified only by hand (curl the endpoint + grep the adapter). Codify it: a fetch-mocked test asserts the state-machine transitions survive the adapter intact, so a future change that strips or reshapes top-level metadata trips a red test instead of silently turning the feature inert (valid-but-inert, the failure mode behind several prior "shipped but runtime-dead" bugs). Test-only; no changeset (no version-affecting change). Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 2e3e058 commit 9509699

1 file changed

Lines changed: 36 additions & 0 deletions

File tree

packages/data-objectstack/src/getObjectSchema.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,40 @@ describe('ObjectStackAdapter.getObjectSchema', () => {
7474
expect(schema.name).toBe('account');
7575
expect(Object.keys(schema.fields)).toEqual(['x']);
7676
});
77+
78+
it('preserves `validations` (incl. state_machine transitions) — the seam the inline editor depends on', async () => {
79+
// Inert-metadata regression guard. The inline select editor filters its
80+
// options by the object's `state_machine` validation (objectui#2110). That
81+
// feature only works because `getObjectSchema` passes the served
82+
// `validations` through untouched — the server enforces the same rule. If a
83+
// future change here started stripping or reshaping top-level metadata, the
84+
// filter would silently no-op (valid-but-inert) with no error. Pin the
85+
// pass-through so the data path can't go dark unnoticed.
86+
const { fetchImpl } = makeFetch({
87+
name: 'showcase_task',
88+
fields: { status: { type: 'select', options: [{ value: 'done', label: 'Done' }] } },
89+
validations: [
90+
{
91+
type: 'state_machine',
92+
field: 'status',
93+
transitions: { in_review: ['done', 'in_progress'], done: ['in_progress'] },
94+
},
95+
],
96+
});
97+
const adapter = new ObjectStackAdapter({
98+
baseUrl: 'http://localhost:3000',
99+
autoReconnect: false,
100+
fetch: fetchImpl as any,
101+
});
102+
103+
const schema: any = await adapter.getObjectSchema('showcase_task');
104+
105+
const sm = (schema.validations ?? []).find((v: any) => v?.type === 'state_machine');
106+
expect(sm).toBeTruthy();
107+
expect(sm.field).toBe('status');
108+
// The exact map the consumer filters on — `done` only transitions to
109+
// `in_progress` (so the editor must not offer `in_review`).
110+
expect(sm.transitions.done).toEqual(['in_progress']);
111+
expect(sm.transitions.in_review).toEqual(['done', 'in_progress']);
112+
});
77113
});

0 commit comments

Comments
 (0)