Repository: sinonjs/lolex
Pull request #204 (2018-09-05 17:25:59)

Fix cloud tests for IE and Safari :hankey:
The changes introduced for 2.7.3 did not break anything, but it introduced a new test that showed
bugs in the existing implementation by actually running `performance.mark()`.

Also, trying to run performance.mark failed on Safari 9, as it has `performance.now`, but
not `performance.mark`. We therefore needed an additional guard before those tests.

We didn't see the fail until merging to master due to pull requests not running the Sauce Labs
tests, and me being too forgetful and impatient to wait for the tests 😀

The changes can be split into two

- changes in the test code to avoid running a test in Safari 9
- changes in the library that deals with IE 10 and IE 11

The prototype for `Performance` in Internet Explorer is not a function like
everywhere else, so we needed to expand the test for object types.


Patch:
diff --git a/src/lolex-src.js b/src/lolex-src.js
index faa0c69..a4bbc05 100644
--- a/src/lolex-src.js
+++ b/src/lolex-src.js
@@ -32,7 +32,7 @@ function withGlobal(_global) {
     var hrtimePresent = (_global.process && typeof _global.process.hrtime === "function");
     var nextTickPresent = (_global.process && typeof _global.process.nextTick === "function");
     var performancePresent = (_global.performance && typeof _global.performance.now === "function");
-    var performanceConstructorExists = (_global.Performance && typeof _global.Performance === "function");
+    var hasPerformancePrototype = (_global.Performance && (typeof _global.Performance).match(/^(function|object)$/));
     var requestAnimationFramePresent = (
         _global.requestAnimationFrame && typeof _global.requestAnimationFrame === "function"
     );
@@ -744,18 +744,15 @@ function withGlobal(_global) {
         };
 
         if (performancePresent) {
-            clock.performance = Object.create(_global.performance);
+            clock.performance = Object.create(null);
 
-
-            if (performanceConstructorExists) {
+            if (hasPerformancePrototype) {
                 var proto = _global.Performance.prototype;
 
                 Object
                     .getOwnPropertyNames(proto)
                     .forEach(function (name) {
-                        if (Object.getOwnPropertyDescriptor(proto, name).writable) {
-                            clock.performance[name] = NOOP;
-                        }
+                        clock.performance[name] = NOOP;
                     });
             }
 
@@ -763,6 +760,7 @@ function withGlobal(_global) {
                 return clock.hrNow;
             };
         }
+
         if (hrtimePresent) {
             clock.hrtime = function (prev) {
                 if (Array.isArray(prev)) {


Test patch:
diff --git a/test/lolex-test.js b/test/lolex-test.js
index 0ee2b92..cc22934 100644
--- a/test/lolex-test.js
+++ b/test/lolex-test.js
@@ -20,7 +20,8 @@ var GlobalDate = Date;
 var NOOP = function NOOP() { return undefined; };
 var nextTickPresent = (global.process && typeof global.process.nextTick === "function");
 var hrtimePresent = (global.process && typeof global.process.hrtime === "function");
-var performancePresent = (global.performance && typeof global.performance.now === "function");
+var performanceNowPresent = (global.performance && typeof global.performance.now === "function");
+var performanceMarkPresent = (global.performance && typeof global.performance.mark === "function");
 
 describe("issue #59", function () {
     var context = {
@@ -1884,7 +1885,8 @@ describe("lolex", function () {
                 assert.same(result[0], 0);
             });
         }
-        if (performancePresent) {
+
+        if (performanceNowPresent) {
             it("replaces global performance.now", function () {
                 this.clock = lolex.install();
                 var prev = performance.now();
@@ -1902,10 +1904,15 @@ describe("lolex", function () {
                 assert.same(performance.now, oldNow);
             });
 
-            it("should let performance.mark still be a method after being installed (#136)", function () {
-                this.clock = lolex.install();
-                assert.isFunction(global.performance.mark);
-            });
+            /* For instance, Safari 9 has performance.now(), but no performance.mark() */
+            if (performanceMarkPresent) {
+                it("should let performance.mark still be callable after lolex.install() (#136)", function () {
+                    this.clock = lolex.install();
+                    refute.exception(function () {
+                        global.performance.mark("a name");
+                    });
+                });
+            }
 
             it("should not alter the global performance properties and methods", function () {
                 // In Phantom.js environment, Performance.prototype has only "now" method.
@@ -1926,14 +1933,6 @@ describe("lolex", function () {
                 delete Performance.prototype.someFunc2;
                 delete Performance.prototype.someFunc3;
             });
-
-            it("should not throw an error on calling performance.mark", function () {
-                this.clock = lolex.install();
-                assert.isFunction(global.performance.mark);
-                refute.exception(function () {
-                    global.performance.mark("a name");
-                });
-            });
         }
 
         if (Object.getPrototypeOf(global)) {
@@ -2260,7 +2259,7 @@ describe("lolex", function () {
         });
     });
 
-    if (performancePresent) {
+    if (performanceNowPresent) {
         describe("performance.now()", function () {
             it("should start at 0", function () {
                 var clock = lolex.createClock(1001);