Skip to content

Commit 23f37ab

Browse files
committed
[core] Port fix of deep nested dependencies defaults assignment
1 parent af5e68b commit 23f37ab

File tree

4 files changed

+256
-2
lines changed

4 files changed

+256
-2
lines changed

.changeset/clever-emus-stare.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@sjsf/form": patch
3+
---
4+
5+
Porst a bunch of fixes for `getDefaultFormState`:
6+
7+
- [Bug: issue with dependencies computeDefaults](https://github.com/rjsf-team/react-jsonschema-form/pull/4282)
8+
- [Make fields with const pre-fiiled and readonly](https://github.com/rjsf-team/react-jsonschema-form/pull/4326)
9+
- [Bug: Deep nested dependencies issue with assigning values to formData](https://github.com/rjsf-team/react-jsonschema-form/pull/4356)

packages/form/src/core/default-state.test.ts

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,91 @@ describe("getDefaultFormState2()", () => {
109109
fromFormData: "fromFormData",
110110
});
111111
});
112+
it("test an object with deep nested dependencies with formData", () => {
113+
const schema: Schema = {
114+
type: "object",
115+
properties: {
116+
nestedObject: {
117+
type: "object",
118+
properties: {
119+
first: {
120+
type: "string",
121+
enum: ["no", "yes"],
122+
default: "no",
123+
},
124+
},
125+
dependencies: {
126+
first: {
127+
oneOf: [
128+
{
129+
properties: {
130+
first: {
131+
enum: ["yes"],
132+
},
133+
second: {
134+
type: "object",
135+
properties: {
136+
deeplyNestedThird: {
137+
type: "string",
138+
enum: ["before", "after"],
139+
default: "before",
140+
},
141+
},
142+
},
143+
},
144+
},
145+
{
146+
properties: {
147+
first: {
148+
enum: ["no"],
149+
},
150+
},
151+
},
152+
],
153+
},
154+
},
155+
},
156+
},
157+
};
158+
159+
// Mock isValid so that withExactlyOneSubschema works as expected
160+
testValidator = makeTestValidator({
161+
isValid: [
162+
true, // First oneOf... first === first
163+
false, // Second oneOf... second !== first
164+
],
165+
});
166+
expect(
167+
getDefaultFormState2(
168+
testValidator,
169+
defaultMerger,
170+
schema,
171+
{
172+
nestedObject: {
173+
first: "yes",
174+
},
175+
},
176+
schema,
177+
false,
178+
{
179+
emptyObjectFields: "populateAllDefaults",
180+
allOf: "skipDefaults",
181+
arrayMinItems: {
182+
populate: "populate" as any,
183+
mergeExtraDefaults: false,
184+
},
185+
mergeDefaultsIntoFormData: "useFormDataIfPresent",
186+
}
187+
)
188+
).toEqual({
189+
nestedObject: {
190+
first: "yes",
191+
second: {
192+
deeplyNestedThird: "before",
193+
},
194+
},
195+
});
196+
});
112197
it("getInnerSchemaForArrayItem() item of type boolean returns empty schema", () => {
113198
expect(
114199
getInnerSchemaForArrayItem(
@@ -479,6 +564,79 @@ describe("getDefaultFormState2()", () => {
479564
})
480565
).toEqual({});
481566
});
567+
it("test an object with deep nested dependencies with formData", () => {
568+
const schema: Schema = {
569+
type: "object",
570+
properties: {
571+
nestedObject: {
572+
type: "object",
573+
properties: {
574+
first: {
575+
type: "string",
576+
enum: ["no", "yes"],
577+
default: "no",
578+
},
579+
},
580+
dependencies: {
581+
first: {
582+
oneOf: [
583+
{
584+
properties: {
585+
first: {
586+
enum: ["yes"],
587+
},
588+
second: {
589+
type: "object",
590+
properties: {
591+
deeplyNestedThird: {
592+
type: "string",
593+
enum: ["before", "after"],
594+
default: "before",
595+
},
596+
},
597+
},
598+
},
599+
},
600+
{
601+
properties: {
602+
first: {
603+
enum: ["no"],
604+
},
605+
},
606+
},
607+
],
608+
},
609+
},
610+
},
611+
},
612+
};
613+
614+
// Mock isValid so that withExactlyOneSubschema works as expected
615+
testValidator = makeTestValidator({
616+
isValid: [
617+
true, // First oneOf... first === first
618+
false, // Second oneOf... second !== first
619+
],
620+
});
621+
expect(
622+
computeDefaults3(testValidator, defaultMerger, schema, {
623+
...defaults,
624+
rootSchema: schema,
625+
rawFormData: {
626+
nestedObject: {
627+
first: "yes",
628+
},
629+
},
630+
})
631+
).toEqual({
632+
nestedObject: {
633+
first: "no",
634+
second: {
635+
deeplyNestedThird: "before",
636+
},
637+
},
638+
});
639+
});
482640
it("test computeDefaults handles an invalid property schema", () => {
483641
const schema: Schema = {
484642
type: "object",

packages/form/src/core/default-state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,6 @@ export function computeDefaults3(
307307
} else if (DEPENDENCIES_KEY in schema) {
308308
// Get the default if set from properties to ensure the dependencies conditions are resolved based on it
309309
const defaultFormData = {
310-
...formData,
311310
...getObjectDefaults(
312311
validator,
313312
merger,
@@ -318,6 +317,7 @@ export function computeDefaults3(
318317
},
319318
defaults
320319
),
320+
...formData,
321321
};
322322
// Get the default if set from properties to ensure the dependencies conditions are resolved based on it
323323
const resolvedSchema = resolveDependencies2(

packages/form/src/core/resolve.test.ts

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
getAllPermutationsOfXxxOf,
2626
resolveAnyOrOneOfSchemas,
2727
resolveCondition2,
28+
resolveDependencies2,
2829
retrieveSchema2,
2930
retrieveSchemaInternal,
3031
stubExistingAdditionalProperties2,
@@ -45,14 +46,100 @@ import {
4546
} from "./fixtures/test-data.js";
4647
import type { Validator } from "./validator.js";
4748
import { makeTestValidator } from "./test-validator.js";
48-
import { defaultMerger } from './merger.js';
49+
import { defaultMerger } from "./merger.js";
4950

5051
let testValidator: Validator;
5152

5253
beforeEach(() => {
5354
testValidator = makeTestValidator();
5455
});
5556

57+
describe("resolveDependencies()", () => {
58+
it("test an object with dependencies", () => {
59+
const schema: Schema = {
60+
type: "object",
61+
properties: {
62+
first: {
63+
type: "string",
64+
enum: ["no", "yes"],
65+
default: "no",
66+
},
67+
},
68+
dependencies: {
69+
first: {
70+
oneOf: [
71+
{
72+
properties: {
73+
first: {
74+
enum: ["yes"],
75+
},
76+
second: {
77+
type: "object",
78+
properties: {
79+
deeplyNestedThird: {
80+
type: "string",
81+
enum: ["before", "after"],
82+
default: "before",
83+
},
84+
},
85+
},
86+
},
87+
},
88+
{
89+
properties: {
90+
first: {
91+
enum: ["no"],
92+
},
93+
},
94+
},
95+
],
96+
},
97+
},
98+
};
99+
100+
// Mock isValid so that withExactlyOneSubschema works as expected
101+
testValidator = makeTestValidator({
102+
isValid: [
103+
true, // First oneOf... first === first
104+
false, // Second oneOf... second !== first
105+
],
106+
});
107+
expect(
108+
resolveDependencies2(
109+
testValidator,
110+
defaultMerger,
111+
schema,
112+
schema,
113+
false,
114+
new Set(),
115+
{
116+
first: "yes",
117+
}
118+
)
119+
).toEqual([
120+
{
121+
type: "object",
122+
properties: {
123+
first: {
124+
type: "string",
125+
enum: ["no", "yes"],
126+
default: "no",
127+
},
128+
second: {
129+
type: "object",
130+
properties: {
131+
deeplyNestedThird: {
132+
type: "string",
133+
enum: ["before", "after"],
134+
default: "before",
135+
},
136+
},
137+
},
138+
},
139+
},
140+
]);
141+
});
142+
});
56143
describe("retrieveSchema2()", () => {
57144
let consoleWarnSpy: MockInstance<typeof console.warn>;
58145
beforeAll(() => {

0 commit comments

Comments
 (0)