Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/spec/src/ui/view-item-config-type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ void [
parsedArtifactScalarConfig,
];

describe('[#19920] a ViewItem config is typed by its arm, not unknown', () => {
describe('a ViewItem config is typed by its arm, not unknown', () => {
it('each body typed through the published names parses at its door', () => {
expect(ViewItemSchema.safeParse(listItem).success).toBe(true);
expect(ViewItemSchema.safeParse(formItem).success).toBe(true);
Expand Down
16 changes: 8 additions & 8 deletions packages/spec/src/ui/view-metadata-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { ListViewSchema, ViewItemSchema, ViewMetadataSchema } from './view.zod';

const PLACEHOLDER_DATA = { provider: 'object', object: 'crm_lead' } as const;

describe('ViewMetadataSchema — genuine validation across the three runtime shapes (#3095)', () => {
describe('ViewMetadataSchema — genuine validation across the three runtime shapes', () => {
// ── shape 2: standalone ViewItem record ───────────────────────────────────
describe('ViewItem record form', () => {
it('accepts a well-formed list ViewItem', () => {
Expand Down Expand Up @@ -92,7 +92,7 @@ describe('ViewMetadataSchema — genuine validation across the three runtime sha
expect(ViewMetadataSchema.safeParse({ listViews: {} }).success).toBe(false);
});

it('REJECTS a bare `{}` — the pin this line used to make, reversed by #5599', () => {
it('REJECTS a bare `{}` — the pin this line used to make, reversed by the identity precondition', () => {
// This assertion previously read `.toBe(true)`, justified as "legacy-
// compatible … a truly empty body carries no viewKind/object, so every
// consumer that filters on identity drops it". #5599 measured what that
Expand Down Expand Up @@ -122,7 +122,7 @@ describe('ViewMetadataSchema — genuine validation across the three runtime sha
expect(r.success).toBe(true);
});

it('REJECTS a raw list config with NO object binding — the #7741 dead row, with located guidance', () => {
it('REJECTS a raw list config with NO object binding — a row no read path could serve, with located guidance', () => {
// ⚠️ Deliberate inversion (#7741, ruled 2026-08-12, direction B). This
// test used to PIN acceptance of exactly this body ("adhoc PUT, no
// registry entry to inherit from") — and QA run #7695 measured what that
Expand Down Expand Up @@ -212,7 +212,7 @@ describe('ViewMetadataSchema — genuine validation across the three runtime sha
});

// ── #5599: the identity precondition, ahead of all four arms ──────────────
describe('identity precondition (#5599)', () => {
describe('identity precondition — a body must read as a view before any member judges it', () => {
// The reproduction from the issue, verbatim. On `origin/main` every input
// in this block was ACCEPTED and reduced to `{ type: 'simple' }` — member 4
// (`FormViewSchema.extend(…).strip()`) both strips unknown keys and requires
Expand Down Expand Up @@ -384,7 +384,7 @@ describe('ViewMetadataSchema — genuine validation across the three runtime sha
expect(ViewMetadataSchema.safeParse({ groupByField: 'stage' }).success).toBe(false);
});

it('does NOT close the arms — `.strip()` round-tripping is untouched (#5074)', () => {
it('does NOT close the arms — `.strip()` round-tripping is untouched', () => {
// The ruling on #5599 kept every arm's `.strip()`: a body that speaks the
// vocabulary still carries undeclared aux keys through without a 422.
// This is the deliberate residue of the minimal fix, pinned so a later
Expand All @@ -403,14 +403,14 @@ describe('ViewMetadataSchema — genuine validation across the three runtime sha
// authorable (objectui's `gridNonAuthorKeys` disposition). The two halves
// below are the card's executable acceptance criterion; a change that flips
// either one is reversing a ruling, not tidying a schema.
describe('columnState — runtime-only overlay key (#9933)', () => {
describe('columnState — runtime-only overlay key', () => {
// The REAL payload, measured: objectui's `persistViewPatch` sends
// `{ columnState: { order?, widths? }, _isOverride: true }` and
// `normalizeViewMetadata` inherits `name`/`object`/`viewKind` from the
// shadowed entry (#2555). Before commit d5552ca13 this body carried no declared key,
// so the identity precondition 422'd it — the ruled patch-only write for
// a column drag could not persist.
it('HALF 1 — the overlay face accepts a `columnState`-only patch (the objectui#5233 payload)', () => {
it('HALF 1 — the overlay face accepts a `columnState`-only patch (the patch-only write the console persists)', () => {
const r = ViewMetadataSchema.safeParse({
name: 'showcase_task.default',
object: 'showcase_task',
Expand All @@ -421,7 +421,7 @@ describe('ViewMetadataSchema — genuine validation across the three runtime sha
expect(r.success).toBe(true);
});

it('HALF 1 — a baseline-less columnState patch is refused at the MEMBERS (binding pair, #7741), not the precondition', () => {
it('HALF 1 — a baseline-less columnState patch is refused at the MEMBERS (the object + viewKind binding pair), not the precondition', () => {
// `columnState` is vocabulary now, so the precondition stays inert; what
// refuses the unbound body is the members' object+viewKind requirement.
const r = ViewMetadataSchema.safeParse({ columnState: { order: ['name'] } });
Expand Down
4 changes: 2 additions & 2 deletions packages/spec/src/ui/view-metadata-type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const parsedUndeclaredKey: ViewMetadataParsed = { type: 'grid', columns: ['name'
const parsedScalar: ViewMetadataParsed = 42;
void [parsedFromUnknown, parsedUndeclaredKey, parsedScalar];

describe('[#19871] ViewMetadata is a view body, not unknown', () => {
describe('ViewMetadata is a view body, not unknown', () => {
it('has a typed body for every member of the union', () => {
expect(Object.keys(BODY_OF_EACH_MEMBER).sort()).toEqual([...VIEW_METADATA_BRANCHES].sort());
});
Expand All @@ -92,7 +92,7 @@ describe('[#19871] ViewMetadata is a view body, not unknown', () => {
}
});

describe('[#19920] ViewMetadataParsed is a parsed view body, not unknown', () => {
describe('ViewMetadataParsed is a parsed view body, not unknown', () => {
for (const branch of VIEW_METADATA_BRANCHES) {
it(`the ${branch} member's parse output and diagnoseViewMetadata's data are both ViewMetadataParsed`, () => {
const memberOutput: ViewMetadataParsed = VIEW_METADATA_MEMBERS[branch].parse(BODY_OF_EACH_MEMBER[branch]);
Expand Down
12 changes: 6 additions & 6 deletions packages/spec/src/ui/view-overlay-options-bag.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function under(issues: Issue[], prefix: PropertyKey[]): Array<Omit<Issue, 'path'
.sort((a, b) => `${a.path}|${a.code}`.localeCompare(`${b.path}|${b.code}`));
}

describe('[#20051] the bag declares exactly the list kinds, derived from the shape', () => {
describe('the bag declares exactly the list kinds, derived from the shape', () => {
it('declares one block per list-view kind that has a block — `grid` has none', () => {
// A pin on the DERIVATION (`listViewKindBlocks`): the list is not
// hand-maintained in the schema, so it is stated once here, where a new
Expand All @@ -88,7 +88,7 @@ describe('[#20051] the bag declares exactly the list kinds, derived from the sha
});
});

describe('[#20051] a direct and an `options`-wrapped out-of-contract key get the same refusal', () => {
describe('a direct and an `options`-wrapped out-of-contract key get the same refusal', () => {
it('the card\'s headline: `options.timeline.metaFields` is refused by name, as `timeline.metaFields` is', () => {
const timeline = { startDateField: 'created_at', titleField: 'name', metaFields: ['region'] };
const direct = listOverlayIssues(overlay({ type: 'timeline', timeline }));
Expand Down Expand Up @@ -136,7 +136,7 @@ describe('[#20051] a direct and an `options`-wrapped out-of-contract key get the
});
});

describe('[#20051] the bag itself is closed', () => {
describe('the bag itself is closed', () => {
it('`options.foo` is refused by name at `options`, not dropped', () => {
const issues = listOverlayIssues(overlay({ options: { foo: 1 } }));
const hit = issues.find((i) => i.code === 'unrecognized_keys');
Expand All @@ -157,7 +157,7 @@ describe('[#20051] the bag itself is closed', () => {
});
});

describe('[#20051] a legal `options.KIND` still parses and round-trips', () => {
describe('a legal `options.KIND` still parses and round-trips', () => {
it('CONTROL: the legacy `options.map` bag objectui pins is accepted and kept in the parse output', () => {
// objectui `packages/app-shell/src/views/InterfaceListPage.mapConfig.test.tsx`
// — "CONTROL: the legacy `options.map` bag is still forwarded on its own
Expand Down Expand Up @@ -205,7 +205,7 @@ describe('[#20051] a legal `options.KIND` still parses and round-trips', () => {
});
});

describe('[#20051] the form overlay cannot take the bag the list overlay refused', () => {
describe('the form overlay cannot take the bag the list overlay refused', () => {
it('a column-less, type-less body with a bad `options` bag is refused, not accepted as a form', () => {
// Without the form overlay's `options` pin this body is ACCEPTED: the list
// member refuses it (no `columns`, and the bag), the form member — which
Expand Down Expand Up @@ -252,7 +252,7 @@ describe('[#20051] the form overlay cannot take the bag the list overlay refused
* `.strip()` used to drop it unread; with the save storing the parsed body it
* would have vanished on a `200` instead.
*/
describe('[#20051] a ViewItem record carries no top-level `options` bag', () => {
describe('a ViewItem record carries no top-level `options` bag', () => {
const record = (extra: Record<string, unknown> = {}) => ({
name: 'crm_lead.board',
object: 'crm_lead',
Expand Down
2 changes: 1 addition & 1 deletion packages/spec/src/ui/view-overlay-options-type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const numericBagArtifact: AssembledViewArtifact = { object: 'crm_lead', viewKind
const numericBagParsedArtifact: AssembledViewArtifactParsed = { object: 'crm_lead', viewKind: 'list', options: { kanban: 42 } };
void [typedBag, numericBagMetadata, numericBagParsedMetadata, numericBagArtifact, numericBagParsedArtifact];

describe('[#19920] the list overlay options bag carries each kind block', () => {
describe('the list overlay options bag carries each kind block', () => {
it('the runtime key set is the kind set the type names', () => {
const bag = VIEW_METADATA_MEMBERS.listOverlay.shape.options.unwrap();
expect(Object.keys(bag.shape).sort()).toEqual([...KIND_BLOCKS]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ describe('overlay owner/hidden retirement — ADR-0087 registration', () => {
expect(MIGRATIONS_BY_MAJOR[18]!.conversionIds).toContain('view-overlay-owner-hidden-removed');
});

it('the family carries ONE D3 semantic entry, and it names the family\'s D2 conversion (ruling B on #17152)', () => {
it('the family carries ONE D3 semantic entry, and it names the family\'s D2 conversion (ruled: a D3 entry per family, even beside a lossless D2)', () => {
const semantic = MIGRATIONS_BY_MAJOR[18]!.semantic;
const family = semantic.filter((s) => s.id === 'view-overlay-owner-hidden-retired');
expect(family).toHaveLength(1);
Expand Down
20 changes: 10 additions & 10 deletions packages/spec/src/ui/view-overlay-viewkind-arm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ function acceptance(body: unknown) {
return { data: parsed.data as Record<string, unknown>, branch: diagnosis.branch };
}

describe('#20186 a column-less list PATCH is judged by the list member', () => {
describe('a column-less list PATCH is judged by the list member', () => {
it('the headline `{ name, object, viewKind: list, sort }` is ACCEPTED on listOverlay and parses to a LIST', () => {
const { data, branch } = acceptance({ ...LIST, sort: [{ field: 'name', order: 'asc' }] });
expect(branch).toBe('listOverlay');
Expand All @@ -99,14 +99,14 @@ describe('#20186 a column-less list PATCH is judged by the list member', () => {
['inlineEdit', { inlineEdit: true }],
['columnState', { columnState: { widths: { name: 120 } } }],
['rowHeight', { rowHeight: 'compact' }],
])('the console %s toggle (patch only, ruled on #7494) is ACCEPTED on listOverlay', (_label, patch) => {
])('the console %s toggle (a patch-only write, as ruled) is ACCEPTED on listOverlay', (_label, patch) => {
const { branch, data } = acceptance({ ...patch, viewKind: 'list', ...ID, _isOverride: true });
expect(branch).toBe('listOverlay');
expect(data.type).toBe('grid');
});
});

describe('#20186 …and its list keys are JUDGED, not stripped', () => {
describe('…and its list keys are JUDGED, not stripped', () => {
it('a retired bare-string `sort` is REFUSED at `sort`, with the 17.5.0 retirement prescription', () => {
const r = refusal({ ...LIST, sort: 'name desc' });
expect(r.topCodes).toEqual(['invalid_union']);
Expand Down Expand Up @@ -141,7 +141,7 @@ describe('#20186 …and its list keys are JUDGED, not stripped', () => {
});
});

describe('#20186 a column-less list overlay that NAMES a `type` stays refused — at `columns`', () => {
describe('a column-less list overlay that NAMES a `type` stays refused — at `columns`', () => {
// `overlay.list.identity` in `view-union-diagnostics.test.ts`: refused before,
// refused now, and still wrapped as `invalid_union` (the refusal is an
// ABORTING issue, so the list member is not the union's lone survivor).
Expand All @@ -161,7 +161,7 @@ describe('#20186 a column-less list overlay that NAMES a `type` stays refused
});
});

describe('#20186 the mirror: a `viewKind: form` body is judged by the form member', () => {
describe('the mirror: a `viewKind: form` body is judged by the form member', () => {
it('list `columns` on a form overlay is REFUSED under formOverlay, at `columns`, with the count prescription', () => {
const r = refusal({ ...FORM, columns: ['name'] });
expect(r.topCodes).toEqual(['invalid_union']);
Expand All @@ -179,7 +179,7 @@ describe('#20186 the mirror: a `viewKind: form` body is judged by the form membe
});
});

describe('#20186 W2 — a list-legal value under a key both arms declare differently is ACCEPTED', () => {
describe('W2 — a list-legal value under a key both arms declare differently is ACCEPTED', () => {
// Refused before: the form member judged these keys by FORM rules (a retired
// `aria` tombstone, a string-only `description`, a public-link `sharing`).
// Declared as a widening: `Clause-②: yes (narrowing)`.
Expand All @@ -193,7 +193,7 @@ describe('#20186 W2 — a list-legal value under a key both arms declare differe
});
});

describe('#20186 controls — byte-identical parse output (measured on origin/main ce70876e)', () => {
describe('controls — byte-identical parse output (measured on origin/main ce70876e)', () => {
it('a real form overlay', () => {
const { data, branch } = acceptance({
name: 'acct.f', object: 'account', viewKind: 'form', type: 'simple', sections: [{ label: 'Main', fields: ['name'] }],
Expand All @@ -216,7 +216,7 @@ describe('#20186 controls — byte-identical parse output (measured on origin/ma
});
});

describe('#20186 each member judges ONE viewKind — read off the members themselves', () => {
describe('each member judges ONE viewKind — read off the members themselves', () => {
it('a direct parse of the form member names where a list body is judged', () => {
const r = VIEW_METADATA_MEMBERS.formOverlay.safeParse({ ...LIST, sort: [{ field: 'name', order: 'asc' }] });
expect(r.success).toBe(false);
Expand All @@ -232,7 +232,7 @@ describe('#20186 each member judges ONE viewKind — read off the members themse
expect(issue?.message).toMatch(/^This is the flattened LIST overlay member, which judges `viewKind: "list"` only\./);
});

it('an ABSENT viewKind keeps the binding prescription (#7741), on both members', () => {
it('an ABSENT viewKind keeps the binding prescription, on both members', () => {
for (const member of [VIEW_METADATA_MEMBERS.listOverlay, VIEW_METADATA_MEMBERS.formOverlay]) {
const r = member.safeParse({ object: 'crm_lead', hidden: true });
const issue = r.error!.issues.find((i) => i.path[0] === 'viewKind');
Expand All @@ -241,7 +241,7 @@ describe('#20186 each member judges ONE viewKind — read off the members themse
});
});

describe('#20186 the premise: no pipe, and the served JSON Schema moves only by the contract', () => {
describe('the premise: no pipe, and the served JSON Schema moves only by the contract', () => {
it('both overlay members are still plain object schemas', () => {
// A pipe serves its INPUT side to `/api/v1/meta/types/view`, and for a
// transform that is `{}` (the `assertViewIdentity` docblock). The input-side
Expand Down
2 changes: 1 addition & 1 deletion packages/spec/src/ui/view-overlay-viewkind-type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ type IsOptionalKey<T, K extends keyof T> = {} extends Pick<T, K> ? true : false;
const typeIsOptionalOnListOverlayOutput: IsOptionalKey<ListOverlayOut, 'type'> = true;
void [typeIsOptionalOnListOverlayOutput];

describe('[#19920] the flattened overlay members keep their own viewKind literal', () => {
describe('the flattened overlay members keep their own viewKind literal', () => {
it('the list-shaped `viewKind: "form"` body is refused by every door that judges it', () => {
const body = { type: 'grid', columns: ['name'], object: 'crm_lead', viewKind: 'form' };
expect(VIEW_METADATA_MEMBERS.listOverlay.safeParse(body).success).toBe(false);
Expand Down
Loading
Loading