Repository: hustcc/jest-canvas-mock
Pull request #11 (2018-07-12 15:01:41)

Fixed all Path2D instance sharing same jest.fn mock
Moved Path2D management to another file
Add jest.fn to each instance instead of prototype
Update tests

coveralls: 
[![Coverage Status](https://coveralls.io/builds/17955563/badge)](https://coveralls.io/builds/17955563)

Coverage remained the same at 100.0% when pulling **6ab00cc455d9abad7bdc0480cbe35c5f969210ce on GMartigny:master** into **f72ecee73259dadf77d2452b5495d0ba344450f7 on hustcc:master**.

GMartigny: I found out that multiple instance of Path2D shared the same Jest mock function (Obviously because of prototype).

This behavior prevent the use of ``toHaveBeenCalledTimes`` for example as previous use change its value.

Patch:
diff --git a/lib/path2d.js b/lib/path2d.js
new file mode 100644
index 0000000..1f3816a
--- /dev/null
+++ b/lib/path2d.js
@@ -0,0 +1,23 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var addPath2D = function addPath2D(win) {
+  if (!win.Path2D) {
+    win.Path2D = function Path2D() {
+      var _this = this;
+
+      _classCallCheck(this, Path2D);
+
+      ['addPath', 'closePath', 'moveTo', 'lineTo', 'bezierCurveTo', 'quadraticCurveTo', 'arc', 'arcTo', 'ellipse', 'rect'].forEach(function (key) {
+        _this[key] = jest.fn();
+      });
+    };
+  }
+};
+
+exports.default = addPath2D;
\ No newline at end of file
diff --git a/lib/window.js b/lib/window.js
index 7025a03..ba8caab 100644
--- a/lib/window.js
+++ b/lib/window.js
@@ -8,12 +8,16 @@ var _canvas = require('./canvas');
 
 var _canvas2 = _interopRequireDefault(_canvas);
 
+var _path2d = require('./path2d');
+
+var _path2d2 = _interopRequireDefault(_path2d);
+
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /**
-                                                                                                                                                           * Created by hustcc 17/12/25.
-                                                                                                                                                           * Contract: i@hust.cc
-                                                                                                                                                           */
+/**
+ * Created by hustcc 17/12/25.
+ * Contract: i@hust.cc
+ */
 
 exports.default = function (win) {
   var d = win.document;
@@ -44,14 +48,7 @@ exports.default = function (win) {
     return param.toString().toLowerCase() === 'canvas' ? (0, _canvas2.default)('canvas') : f.call(d, param);
   };
 
-  if (!win.Path2D) {
-    win.Path2D = function Path2D() {
-      _classCallCheck(this, Path2D);
-    };
-    ['addPath', 'closePath', 'moveTo', 'lineTo', 'bezierCurveTo', 'quadraticCurveTo', 'arc', 'arcTo', 'ellipse', 'rect'].forEach(function (key) {
-      win.Path2D.prototype[key] = jest.fn();
-    });
-  }
+  (0, _path2d2.default)(win);
 
   return win;
 };
\ No newline at end of file
diff --git a/src/path2d.js b/src/path2d.js
new file mode 100644
index 0000000..ef968f1
--- /dev/null
+++ b/src/path2d.js
@@ -0,0 +1,24 @@
+const addPath2D = (win) => {
+  if (!win.Path2D) {
+    win.Path2D = class Path2D {
+      constructor() {
+        [
+          'addPath',
+          'closePath',
+          'moveTo',
+          'lineTo',
+          'bezierCurveTo',
+          'quadraticCurveTo',
+          'arc',
+          'arcTo',
+          'ellipse',
+          'rect',
+        ].forEach((key) => {
+          this[key] = jest.fn();
+        });
+      }
+    };
+  }
+};
+
+export default addPath2D;
diff --git a/src/window.js b/src/window.js
index 5d87618..530908b 100644
--- a/src/window.js
+++ b/src/window.js
@@ -4,6 +4,7 @@
  */
 
 import createCanvas from './canvas';
+import addPath2D from './path2d';
 
 export default win => {
   const d = win.document;
@@ -34,23 +35,7 @@ export default win => {
     ? createCanvas('canvas') 
     : f.call(d, param);
 
-  if (!win.Path2D) {
-    win.Path2D = class Path2D {};
-    [
-      'addPath',
-      'closePath',
-      'moveTo',
-      'lineTo',
-      'bezierCurveTo',
-      'quadraticCurveTo',
-      'arc',
-      'arcTo',
-      'ellipse',
-      'rect',
-    ].forEach((key) => {
-      win.Path2D.prototype[key] = jest.fn();
-    })
-  }
+  addPath2D(win);
 
   return win;
 };


Test patch:
diff --git a/__tests__/index.js b/__tests__/index.js
index e1ff8bd..fb8db14 100644
--- a/__tests__/index.js
+++ b/__tests__/index.js
@@ -4,7 +4,7 @@
 
 import createCanvas from '../src/canvas';
 import createContext2d from '../src/context2d';
-import mockWindow  from '../src/window';
+import mockWindow from '../src/window';
 
 describe('canvas', () => {
   beforeEach(() => {
@@ -48,7 +48,7 @@ describe('canvas', () => {
     expect(typeof ctx).toBe('object');
 
     Object.keys(ctx).forEach(key => {
-      if(typeof ctx[key] === "function"){
+      if (typeof ctx[key] === "function") {
         ctx[key]();
       }
     });
@@ -74,7 +74,7 @@ describe('canvas', () => {
       'closePath',
       'stroke',
       'strokeRect',
-      'strokeText', 
+      'strokeText',
       't2',
       'transform',
       'translate',
@@ -117,13 +117,7 @@ describe('canvas', () => {
 
     expect(path).toBeDefined();
 
-    Object.keys(path.constructor.prototype).forEach(key => {
-      if(typeof path[key] === "function"){
-        path[key]();
-      }
-    });
-
-    [
+    const pathFunctions = [
       'addPath',
       'closePath',
       'moveTo',
@@ -134,9 +128,22 @@ describe('canvas', () => {
       'arcTo',
       'ellipse',
       'rect',
-    ].forEach((key) => {
+    ];
+
+    pathFunctions.forEach(key => {
+      if (typeof path[key] === "function") {
+        path[key]();
+      }
+    });
+
+    pathFunctions.forEach((key) => {
       expect(path[key]).toBeCalled();
     });
+
+    const otherPath = new Path2D();
+    pathFunctions.forEach((key) => {
+      expect(otherPath[key]).not.toBeCalled();
+    });
   });
 
   test('Path2D not override', () => {