fix(environment): preserve null bodies and unique member matches (#10014)

This commit is contained in:
morluto authored and GitHub committed 2026-11-11 17:19:37 +08:00
1 parent 44ef32c1c0
commit 3896f72552
4 files changed
+48 -4

No files matched your search

@@ -166,3 +166,25 @@ it.each([
expect(requestBody(capture.records[0]!)).toEqual(expected);
},
);
it.each([
["null", null],
["false", false],
["0", 0],
['""', ""],
["not-json", "not-json"],
] as const)(
"preserves the recorded request JSON value %s",
(text, expected) => {
const capture = environmentManifestCaptureFixture([
{
request: {
method: "POST",
url: "http://app.example/api/value",
postData: { mimeType: "application/json", text },
},
},
]);
expect(requestBody(capture.records[0]!)).toEqual(expected);
},
);
@@ -429,7 +429,9 @@ class Differ {
for (const [key, value] of Object.entries(live)) {
const child = `${pointer}/${escapePointer(key)}`;
const other = envKey(key);
if (!Object.hasOwn(env, other))
// A translated key and a verbatim key may name the same entry; an
// environment member can account for only one live member.
if (!Object.hasOwn(env, other) || matched.has(other))
this.add({
category: "missing-field",
pointer: child,
@@ -26,6 +26,25 @@ const compareRows = (
return report.value.probes[0]!;
};
describe("environment comparison collection matching", () => {
it("does not match two live object keys to one environment entry", () => {
const probe = compareRows(
[
["GET", "/api/items", [{ id: 1, name: "A" }]],
["GET", "/api/counts", { counts: { "1": 5 } }],
],
[
["GET", "/api/items", [{ id: 101, name: "A" }]],
["GET", "/api/counts", { counts: { "1": 5, "101": 5 } }],
],
);
expect(probe.results.map((step) => step.equal)).toEqual([true, false]);
expect(probe.results[1]?.differences).toMatchObject([
{ category: "missing-field", pointer: "/counts/101" },
]);
});
});
describe("environment comparison identifier semantics", () => {
it("reports changed business tokens and numeric arrays through the application comparison boundary", () => {
const probe = compareRows(
@@ -78,9 +78,10 @@ export const requestBody = (
return undefined;
const { mimeType, text } = facts.postData;
if (mimeType === undefined || text === undefined) return undefined;
return isJsonLike(mediaTypeEssence(mimeType))
? (parseExactJson(text) ?? text)
: text;
const value = isJsonLike(mediaTypeEssence(mimeType))
? parseExactJson(text)
: undefined;
return value === undefined ? text : value;
};
/** The application's answer as an environment answer carries it: JSON, text, or null when it is empty; a body the probe did not record is marked. */