Search code examples
javascriptnode.jsunit-testingassert

Not able to understand the difference between the node versions which is resulting the difference between asserts


When i run the below statements using different node versions I see a difference in the assert outcome. I am using v10.15.1 where the assert passes. But the same code in v14.18.1 throws error.

const assert = require('assert')
var err = new Error('some error');
var d = [{
    'error':[err]
}]
var expected = [{
    'error':[{}]
}]
assert.deepEqual(d,expected)

Error is as below:

    assert.js:118
  throw new AssertionError(obj);
  ^

AssertionError [ERR_ASSERTION]: Expected values to be loosely deep-equal:

[
  {
    error: [
      Error: some error
          at Object.<anonymous> (/Users/username/Desktop/repos/temp_files/test.js:2:11)
          at Module._compile (internal/modules/cjs/loader.js:1085:14)
          at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
          at Module.load (internal/modules/cjs/loader.js:950:32)
          at Function.Module._load (internal/modules/cjs/loader.js:790:12)
          at Function.executeUserEntryPoint [as r...

should loosely deep-equal

[
  {
    error: [
      []
    ]
  }
]
    at Object.<anonymous> (/Users/username/Desktop/repos/temp_files/test.js:9:8)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:12)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
    at internal/main/run_main_module.js:17:47 {
  generatedMessage: true,
  code: 'ERR_ASSERTION',
  actual: [
    {
      error: [
        Error: some error
            at Object.<anonymous> (/Users/username/Desktop/repos/temp_files/test.js:2:11)
            at Module._compile (internal/modules/cjs/loader.js:1085:14)
            at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
            at Module.load (internal/modules/cjs/loader.js:950:32)
            at Function.Module._load (internal/modules/cjs/loader.js:790:12)
            at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
            at internal/main/run_main_module.js:17:47
      ]
    }
  ],
  expected: [ { error: [ [] ] } ],
  operator: 'deepEqual'
}

I referred to the documentation for both the version but didn't find it useful.

v10

v14

I understand of course that the error object is empty in one but not in the other. But cannot find the reason why v10 ignores it and what changed later because of which the error is now caught


Solution

  • The behavior of assert.deepEqual was changed in Node.js 12 with this pull request. Part of the motivation behind the change was a requirement to align loose equal comparison with strict equal comparison whose behavior had been more predictable from the beginning. As a result, the assertion

    assert.deepEqual(new Error('test'), { });
    

    passes in Node.js < 12 but fails in Node.js 12 and later.

    The simple explanation is that Errors are objects without own enumerable properties. In older version of Node.js, the fact that an Error and an empty object literal ({ })are both objects without own enumerable properties was reason enough for both to compare loosely equal. The behavior changed in Node.js 12 where the documentation of deepEqual states:

    Error names and messages are always compared, even if these are not enumerable properties.

    Granted, this does not make the change you observed obvious in any way.