From 1ad9864ad72181932ee4433a2dce8d8b333661b8 Mon Sep 17 00:00:00 2001
From: Lucas Fernandes da Costa <lucas@lucasfcosta.com>
Date: Mon, 1 Jul 2019 21:08:00 +0100
Subject: [PATCH] fix(jest-mock): fix mock restoration reassigning to
 previously unexisting prop (#8625)

---
 CHANGELOG.md                                  |  1 +
 .../jest-mock/src/__tests__/index.test.ts     | 26 +++++++++++++++++++
 packages/jest-mock/src/index.ts               |  8 +++++-
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c57e8fc17c7..2bb3607b3b6d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,6 +22,7 @@
 - `[jest-haste-map]` Don't throw on missing mapper in Node crawler ([#8558](https://github.com/facebook/jest/pull/8558))
 - `[jest-core]` Fix incorrect `passWithNoTests` warning ([#8595](https://github.com/facebook/jest/pull/8595))
 - `[jest-snapshots]` Fix test retries that contain snapshots ([#8629](https://github.com/facebook/jest/pull/8629))
+- `[jest-mock]` Fix incorrect assignments when restoring mocks in instances where they originally didn't exist ([#8631](https://github.com/facebook/jest/pull/8631))
 
 ### Chore & Maintenance
 
diff --git a/packages/jest-mock/src/__tests__/index.test.ts b/packages/jest-mock/src/__tests__/index.test.ts
index 64c47464be83..f665def33ea6 100644
--- a/packages/jest-mock/src/__tests__/index.test.ts
+++ b/packages/jest-mock/src/__tests__/index.test.ts
@@ -542,6 +542,32 @@ describe('moduleMocker', () => {
       });
     });
 
+    it('mocks the method in the passed object itself', () => {
+      const parent = {func: () => 'abcd'};
+      const child = Object.create(parent);
+
+      moduleMocker.spyOn(child, 'func').mockReturnValue('efgh');
+
+      expect(child.hasOwnProperty('func')).toBe(true);
+      expect(child.func()).toEqual('efgh');
+      expect(parent.func()).toEqual('abcd');
+    });
+
+    it('should delete previously inexistent methods when restoring', () => {
+      const parent = {func: () => 'abcd'};
+      const child = Object.create(parent);
+
+      moduleMocker.spyOn(child, 'func').mockReturnValue('efgh');
+
+      moduleMocker.restoreAllMocks();
+      expect(child.func()).toEqual('abcd');
+
+      moduleMocker.spyOn(parent, 'func').mockReturnValue('jklm');
+
+      expect(child.hasOwnProperty('func')).toBe(false);
+      expect(child.func()).toEqual('jklm');
+    });
+
     it('supports mock value returning undefined', () => {
       const obj = {
         func: () => 'some text',
diff --git a/packages/jest-mock/src/index.ts b/packages/jest-mock/src/index.ts
index 7647b81c379a..be19de0df52f 100644
--- a/packages/jest-mock/src/index.ts
+++ b/packages/jest-mock/src/index.ts
@@ -1009,9 +1009,15 @@ class ModuleMockerClass {
         );
       }
 
+      const isMethodOwner = object.hasOwnProperty(methodName);
+
       // @ts-ignore overriding original method with a Mock
       object[methodName] = this._makeComponent({type: 'function'}, () => {
-        object[methodName] = original;
+        if (isMethodOwner) {
+          object[methodName] = original;
+        } else {
+          delete object[methodName];
+        }
       });
 
       // @ts-ignore original method is now a Mock