diff --git a/packages/core/src/utils.js b/packages/core/src/utils.js index 83c20cdec8..c0a20e65ea 100644 --- a/packages/core/src/utils.js +++ b/packages/core/src/utils.js @@ -3,6 +3,7 @@ import * as ReactIs from "react-is"; import mergeAllOf from "json-schema-merge-allof"; import fill from "core-js-pure/features/array/fill"; import union from "lodash/union"; +import isEmpty from "lodash/isEmpty"; import jsonpointer from "jsonpointer"; import fields from "./components/fields"; import widgets from "./components/widgets"; @@ -220,10 +221,22 @@ function computeDefaults( ); } else if ("oneOf" in schema) { schema = - schema.oneOf[getMatchingOption(undefined, schema.oneOf, rootSchema)]; + schema.oneOf[ + getMatchingOption( + isEmpty(formData) ? undefined : formData, + schema.oneOf, + rootSchema + ) + ]; } else if ("anyOf" in schema) { schema = - schema.anyOf[getMatchingOption(undefined, schema.anyOf, rootSchema)]; + schema.anyOf[ + getMatchingOption( + isEmpty(formData) ? undefined : formData, + schema.anyOf, + rootSchema + ) + ]; } // Not defaults defined for this node, fallback to generic typed ones. diff --git a/packages/core/test/oneOf_test.js b/packages/core/test/oneOf_test.js index 7bb795078c..805bfa3055 100644 --- a/packages/core/test/oneOf_test.js +++ b/packages/core/test/oneOf_test.js @@ -541,6 +541,43 @@ describe("oneOf", () => { expect(node.querySelector("input#root").value).eql(""); }); + it("should use only the selected option when generating default values", () => { + const schema = { + type: "object", + oneOf: [ + { + additionalProperties: false, + properties: { lorem: { type: "object" } }, + }, + { + additionalProperties: false, + properties: { ipsum: { type: "object" } }, + }, + { + additionalProperties: false, + properties: { pyot: { type: "object" } }, + }, + ], + }; + + const { node, onChange } = createFormComponent({ + schema, + formData: { lorem: {} }, + }); + + const $select = node.querySelector("select"); + + Simulate.change($select, { + target: { value: $select.options[1].value }, + }); + + expect($select.value).eql("1"); + + sinon.assert.calledWithMatch(onChange.lastCall, { + formData: { lorem: undefined, ipsum: {} }, + }); + }); + describe("Arrays", () => { it("should correctly render mixed types for oneOf inside array items", () => { const schema = { diff --git a/packages/core/test/utils_test.js b/packages/core/test/utils_test.js index d7c554141c..fc882e07cc 100644 --- a/packages/core/test/utils_test.js +++ b/packages/core/test/utils_test.js @@ -657,6 +657,23 @@ describe("utils", () => { }); }); + it("should populate defaults for oneOf second option", () => { + const schema = { + type: "object", + properties: { + test: { + oneOf: [ + { properties: { a: { type: "string", default: "a" } } }, + { properties: { b: { type: "string", default: "b" } } }, + ], + }, + }, + }; + expect(getDefaultFormState(schema, { test: { b: "b" } })).eql({ + test: { b: "b" }, + }); + }); + it("should populate defaults for oneOf when 'type': 'object' is missing", () => { const schema = { type: "object", @@ -754,6 +771,23 @@ describe("utils", () => { }); }); + it("should populate defaults for anyOf second option", () => { + const schema = { + type: "object", + properties: { + test: { + anyOf: [ + { properties: { a: { type: "string", default: "a" } } }, + { properties: { b: { type: "string", default: "b" } } }, + ], + }, + }, + }; + expect(getDefaultFormState(schema, { test: { b: "b" } })).eql({ + test: { b: "b" }, + }); + }); + it("should populate nested default values for anyOf", () => { const schema = { type: "object",