From b9252413cafb0a3510486a6c1e8ab5a25e40f836 Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Sun, 6 Jun 2021 23:51:55 +0100 Subject: [PATCH] Tests: Fix flaky dump test "Circular reference with arrays" There were two issues here: * The test relied on non-default maxDepth of null or > 10 since its example involves recurion 10 levels deep, and the default maxDepth is 5. * There is a bug in `QUnit.dump.parse()` where, if the input value cannot be mapped to a formatter function, it returns a function instead of a string. This bug was introduced nearly ten years ago in commit 818b2beda, where `error` was replaced with a function that had a different purpose than what was there before, and this one use of it as fallback was not updated. Unfortunately, I am unable to say what value causes this to happen. I can consistently reproduce the issue in Safari 9.1 via BrowserStack, but only if I don't open the console, don't run a subset of the test, and don't modify any of the surrounding code. I have tried dozens upon dozens of clever ways to store values during the parse() function call in temporary variables and alert() them but as soon as I tried to capture anything that would help, the bug would stop happening. I can only conclude that there must be some kind of memory or JIT corruption in the JavaScript engine of Safari 9.1 that has some extremely specific conditions attached to it. Conditions that we did not meet before the last few commits, and are meeting now. ``` [OS X El Capitan, Safari 9.1] Error: "Circular reference with arrays" failed Died on test #1 @http://localhost:8899/test/main/dump.js:279:11: expected.indexOf is not a function. (In 'expected.indexOf("[object Array]")', 'expected.indexOf' is undefined) ``` --- src/dump.js | 8 +++++++- test/main/dump.js | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/dump.js b/src/dump.js index 3a3292cd2..7192bee51 100644 --- a/src/dump.js +++ b/src/dump.js @@ -104,7 +104,10 @@ export default ( function() { stack.pop(); return res; } - return ( parserType === "string" ) ? parser : this.parsers.error; + if ( parserType === "string" ) { + return parser; + } + return "[ERROR: Missing QUnit.dump formatter for type " + objType + "]"; }, typeOf: function( obj ) { let type; @@ -180,6 +183,9 @@ export default ( function() { error: function( error ) { return "Error(\"" + error.message + "\")"; }, + + // This has been unused since QUnit 1.0.0. + // @todo Deprecate and remove. unknown: "[Unknown]", "null": "null", "undefined": "undefined", diff --git a/test/main/dump.js b/test/main/dump.js index ab0b47c7d..0ae030f8f 100644 --- a/test/main/dump.js +++ b/test/main/dump.js @@ -3,6 +3,8 @@ QUnit.module( "dump", { afterEach: function() { + + // Restore default QUnit.dump.maxDepth = null; } } ); @@ -239,6 +241,8 @@ function chainwrap( depth, first, prev ) { QUnit.test( "Check dump recursion", function( assert ) { var noref, nodump, selfref, selfdump, parentref, parentdump, circref, circdump; + // QUnit.dump.maxDepth = 20; + noref = chainwrap( 0 ); nodump = QUnit.dump.parse( noref ); assert.equal( nodump, "{\n \"first\": true,\n \"wrap\": undefined\n}" ); @@ -263,6 +267,8 @@ QUnit.test( "Check dump recursion", function( assert ) { QUnit.test( "Check equal/deepEqual recursion", function( assert ) { var noRecursion, selfref, circref; + // QUnit.dump.maxDepth = 20; + noRecursion = chainwrap( 0 ); assert.equal( noRecursion, noRecursion, "I should be equal to me." ); assert.deepEqual( noRecursion, noRecursion, "... and so in depth." );