diff --git a/.changeset/dispatcher-envelope-shared-predicate.md b/.changeset/dispatcher-envelope-shared-predicate.md new file mode 100644 index 0000000000..2de0f29483 --- /dev/null +++ b/.changeset/dispatcher-envelope-shared-predicate.md @@ -0,0 +1,17 @@ +--- +--- + +`domain-handler-registry.test.ts` now uses `envelopeViolations` instead of its own +copy of the rule. Deliberately empty frontmatter: test-only, this releases nothing. + +That test hand-rolled "no key beside the envelope's own may hold the payload" for +#4038. #4090 promoted the rule into the spec so it would stop having two +definitions; leaving the local copy would have recreated the exact failure this +line has been closing — one rule, two places, only one updated next time. + +The two were also not equivalent. The local set allowed any body whose top-level +keys were `success` / `data` / `meta`, so it passed a success body with no `data` +at all and one carrying an `error` beside `success: true`. The shared predicate +rejects both, which makes this a strict tightening rather than a refactor: +injecting `{ success: true }` into the producer now fails the suite, and used to +pass it. diff --git a/packages/runtime/src/domain-handler-registry.test.ts b/packages/runtime/src/domain-handler-registry.test.ts index 5d46434709..0798c50983 100644 --- a/packages/runtime/src/domain-handler-registry.test.ts +++ b/packages/runtime/src/domain-handler-registry.test.ts @@ -14,6 +14,7 @@ */ import { describe, it, expect, vi } from 'vitest'; +import { envelopeViolations } from '@objectstack/spec/api'; import { HttpDispatcher } from './http-dispatcher.js'; import { DomainHandlerRegistry } from './domain-handler-registry.js'; import type { DomainHandler } from './domain-handler-registry.js'; @@ -391,9 +392,15 @@ describe('HttpDispatcher extracted domains (PR-4: share-links)', () => { }); it('every success body carries its payload under `data` and nowhere else', async () => { - // The general form of the two assertions above, over all four success - // routes: no key beside the envelope's own may hold the payload. - const ENVELOPE_KEYS = new Set(['success', 'data', 'meta']); + // The general form of the two assertions above, over all the success + // routes — and `envelopeViolations` (#4090) is now where that general form + // lives. This test hand-rolled it first, for #4038; extracting it into the + // spec meant the same rule stopped having two definitions that could drift + // apart, which is the failure this whole line has been closing. + // + // The shared one is also stricter than what stood here: the local set + // allowed any body whose keys were `success`/`data`/`meta`, so it passed a + // success body with no `data` at all and one carrying an `error`. const shareLinks = { createLink: vi.fn().mockResolvedValue(LINK), listLinks: vi.fn().mockResolvedValue([LINK]), @@ -407,9 +414,7 @@ describe('HttpDispatcher extracted domains (PR-4: share-links)', () => { ]; for (const body of bodies) { expect(body?.success).toBe(true); - for (const key of Object.keys(body ?? {})) { - expect(ENVELOPE_KEYS.has(key), `body carries a non-envelope top-level key: ${key}`).toBe(true); - } + expect(envelopeViolations(body), `not the declared envelope: ${JSON.stringify(body)}`).toEqual([]); } });