tape-testing / tape

tap-producing test harness for node and browsers
MIT License
5.77k stars 307 forks source link

Cannot test JSON.parse with doesNotThrow #512

Closed pszabop closed 4 years ago

pszabop commented 4 years ago

The following test fails complaining that JSON.parse is not a function. I'm quite sure JSON.parse is a function, I printed out typeof JSON.parse and got function.

Yet if I put illegal JSON in the test executes the JSON.parse and fails as expected.

How does one test that some result is parseable JSON?

node version: v8.11.1 tape version: 5.0.0

test('ensure JSON.parse can be tested for throwing or not', async function(t) {
  t.doesNotThrow(JSON.parse('{}'), undefined, 'JSON.parse should not throw on an empty brackets');
}); 
# ensure JSON.parse can be tested for throwing or not
not ok 2 JSON.parse should not throw on an empty brackets
  ---
    operator: throws
    expected: |-
      undefined
    actual: |-
      [TypeError: Function expected]
    at: Anonymous function (/home/test/hello.js:23:3)
    stack: |-
      TypeError: Function expected
         at Test.prototype.doesNotThrow (/home/test/node_modules/tape/lib/test.js:642:9)
         at bound (/home/test/node_modules/tape/lib/test.js:84:21)
         at Anonymous function (/home/test/hello.js:23:3)
         at Generator.prototype.next (native code)
         at Anonymous function (/home/test/node_modules/tape-promise/index.compiled.js:86:9)
         at bound (/home/test/node_modules/tape/lib/test.js:84:21)
         at Test.prototype.run (/home/test/node_modules/tape/lib/test.js:101:5)
         at bound (/home/test/node_modules/tape/lib/test.js:84:21)
         at next (/home/test/node_modules/tape/lib/results.js:83:17)
         at runCallback (timers.js:794:7)
  ...
test('ensure JSON.parse can be tested to throw', async function(t) {
  t.doesNotThrow(JSON.parse(''), undefined, 'JSON.parse should throw on an empty string');
});
# ensure JSON.parse can be tested to throw
not ok 3 SyntaxError: JSON.parse Error: Unexpected input at position:0
  ---
    operator: error
    at: onetime (/home/test/node_modules/onetime/index.js:30:3)
    stack: |-
      SyntaxError: JSON.parse Error: Unexpected input at position:0
         at Anonymous function (/home/test/hello.js:27:3)
         at Generator.prototype.next (native code)
         at Anonymous function (/home/test/node_modules/tape-promise/index.compiled.js:86:9)
         at bound (/home/test/node_modules/tape/lib/test.js:84:21)
         at Test.prototype.run (/home/test/node_modules/tape/lib/test.js:101:5)
         at bound (/home/test/node_modules/tape/lib/test.js:84:21)
         at next (/home/test/node_modules/tape/lib/results.js:83:17)
         at runCallback (timers.js:794:7)
         at tryOnImmediate (timers.js:752:5)
         at processImmediate (timers.js:729:5)
  ...
Raynos commented 4 years ago

t.doesNotThrow needs a function

test('ensure JSON.parse can be tested for throwing or not', async function(t) {
  t.doesNotThrow(function noThrow() {
    JSON.parse('{}')
  }, undefined, 'JSON.parse should not throw on an empty brackets');
});
pszabop commented 4 years ago

JSON.parse() is a function according to console.log(typeof JSON.parse)

The odd part is intentionally giving JSON.parse() bad input does throw, which means it was executed.

pszabop commented 4 years ago

The workaround works, I added this to my tape hello world test where I document workarounds for interesting test cases.

/*
 * @see https://github.com/substack/tape/issues/512
 *
 */
test('ensure JSON.parse can be tested to not throw', async function(t) {
  t.doesNotThrow(function() { JSON.parse('{}') }, undefined, 'JSON.parse should not throw on an empty brackets');
});

test('ensure JSON.parse can be tested to throw', async function(t) {
  t.throws(function () { JSON.parse('') }, undefined, 'JSON.parse should throw on an empty string');
});
ljharb commented 4 years ago

@pszabop that's not a workaround, that's what's necessary. What you pass to doNotThrow is a function that may or may not throw - JSON.parse is a function, but that's not what you passed. You passed JSON.parse(something), which is either an object, or, it's already thrown an exception.

This is true in every single test runner, period - a "throw" or "does not throw" assertion can only be tested against the only thing in the language that can be later invoked (to throw or not), a function.