Repository: mozilla-services/react-jsonschema-form
Pull request #1095 (2018-12-03 20:21:35)

fix: check obj1 in mergeObjects
### Reasons for making this change

`mergeObjects` function doesn't check the arguments which leads to an exception.

https://github.com/mozilla-services/react-jsonschema-form/issues/1094

### Checklist

* [ ] **I'm updating documentation**
  - [ ] I've checked the rendering of the Markdown text I've added
  - [ ] If I'm adding a new section, I've updated the Table of Content
* [x] **I'm adding or updating code**
  - [x] I've added and/or updated tests
  - [ ] I've updated docs if needed
  - [x] I've run `npm run cs-format` on my branch to conform my code to [prettier](https://github.com/prettier/prettier) coding style
* [ ] **I'm adding a new feature**
  - [ ] I've updated the playground with an example use of the feature


nLight: @edi9999 in my opinion this mergeObjects shouldn't be a part of the library at all. I can add an _integration_ test if that expedites the merge decision.
nLight: @edi9999 added an integration test
edi9999: Good , thanks !

Patch:
diff --git a/src/utils.js b/src/utils.js
index f8cc7838e..816db131d 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -222,9 +222,9 @@ export function mergeObjects(obj1, obj2, concatArrays = false) {
   // Recursively merge deeply nested objects.
   var acc = Object.assign({}, obj1); // Prevent mutation of source object.
   return Object.keys(obj2).reduce((acc, key) => {
-    const left = obj1[key],
+    const left = obj1 ? obj1[key] : {},
       right = obj2[key];
-    if (obj1.hasOwnProperty(key) && isObject(right)) {
+    if (obj1 && obj1.hasOwnProperty(key) && isObject(right)) {
       acc[key] = mergeObjects(left, right, concatArrays);
     } else if (concatArrays && Array.isArray(left) && Array.isArray(right)) {
       acc[key] = left.concat(right);


Test patch:
diff --git a/test/utils_test.js b/test/utils_test.js
index fb688506c..deb24f5a3 100644
--- a/test/utils_test.js
+++ b/test/utils_test.js
@@ -183,6 +183,41 @@ describe("utils", () => {
         });
       });
 
+      it("should support nested values in formData", () => {
+        const schema = {
+          type: "object",
+          properties: {
+            level1: {
+              type: "object",
+              properties: {
+                level2: {
+                  oneOf: [
+                    {
+                      type: "object",
+                      properties: {
+                        leaf1: {
+                          type: "string",
+                        },
+                      },
+                    },
+                  ],
+                },
+              },
+            },
+          },
+        };
+        const formData = {
+          level1: {
+            level2: {
+              leaf1: "a",
+            },
+          },
+        };
+        expect(getDefaultFormState(schema, formData)).eql({
+          level1: { level2: { leaf1: "a" } },
+        });
+      });
+
       it("should use parent defaults for ArrayFields", () => {
         const schema = {
           type: "object",
@@ -422,6 +457,12 @@ describe("utils", () => {
       expect(mergeObjects({ a: 1 }, { a: 2 })).eql({ a: 2 });
     });
 
+    it("should override non-existing values of the first object with the values from the second", () => {
+      expect(mergeObjects({ a: { b: undefined } }, { a: { b: { c: 1 } } })).eql(
+        { a: { b: { c: 1 } } }
+      );
+    });
+
     it("should recursively merge deeply nested objects", () => {
       const obj1 = {
         a: 1,