assert.notStrictEqual()

Throws an AssertionError when two values are strictly equal under Object.is().

Signature
assert.notStrictEqual(actual, expected[, message])
  • Added in Node.js v0.1.21

Parameters

ParameterTypeDescription
$actualanyThe value produced by the code under test.
$expectedanyThe value it must not equal, compared with Object.is().
$messageoptionalstring | Error | FunctionError message, an Error instance to throw instead, or a function called on failure.

Errors

Throws an AssertionError with code ERR_ASSERTION when Object.is(actual, expected) is true; if message is an Error instance, that error is thrown instead.

Changelog

  • PHP v26.0.0Message may now be a printf-like format string or function.
  • PHP v10.0.0The comparison used changed from strict equality (===) to Object.is().

assert.notStrictEqual() is the exact negation of assert.strictEqual(): it fails when Object.is(actual, expected) returns true. The same two Object.is() quirks apply, mirrored — notStrictEqual(NaN, NaN) throws, and notStrictEqual(0, -0) passes.

Its real job is reference identity

The most useful application is not "these numbers differ" but "this is not the same object". Cloning code, immutable-update helpers, and anything that promises not to mutate its input are all naturally tested by asserting the output is a different reference from the input, then asserting with assert.deepStrictEqual() that its contents are what you expect. Together those two lines pin down "a real copy, with the right data".

A weak assertion on its own

Any value at all other than expected satisfies it, including undefined from a function that silently returned nothing. Because of that it makes a poor primary assertion: it should sit alongside a positive check, not replace one. If you find yourself writing a long chain of notStrictEqual calls, the thing you actually want to express is usually a single positive assertion about the value.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Prove a clone helper returned a new object rather than the original reference
  • Assert a reducer produced fresh state instead of mutating the state passed in
  • Check that a retry produced a different token from the first attempt

Frequently asked questions

Why does assert.notStrictEqual(NaN, NaN) throw?

Because the comparison is Object.is(), which reports NaN as identical to NaN, so notStrictEqual treats them as equal and fails. Under a plain !== check the same expression would pass.

How do I assert that two objects are not the same object?

assert.notStrictEqual(a, b) does exactly that — it compares references, so it passes for any two distinct objects even if their contents match. To assert the contents differ as well, use assert.notDeepStrictEqual().

Does assert.notStrictEqual() compare object contents?

No. It only checks Object.is() identity, so two separate objects with identical properties always pass. Reach for assert.notDeepStrictEqual() when you need the structures themselves to differ.

More examples

Prove an update helper did not mutate its input

The three assertions together are what "immutable update" means: a different reference, an untouched input, and the expected output. The final line shows the limit of a shallow spread — after.tags is still the same array, so a test that only checks the top-level reference would miss a nested mutation.

Example · javascript
const assert = require('node:assert');

function withStatus(state, status) {
  return { ...state, status };
}

const before = { id: 7, status: 'pending', tags: ['a'] };
const after = withStatus(before, 'done');

// 1. A new top-level object was produced.
assert.notStrictEqual(after, before);
// 2. The input was left alone.
assert.deepStrictEqual(before, { id: 7, status: 'pending', tags: ['a'] });
// 3. The output has the change.
assert.deepStrictEqual(after, { id: 7, status: 'done', tags: ['a'] });

console.log('immutable update verified');

// The spread is shallow: nested values are still shared.
console.log('tags shared?', after.tags === before.tags); // true

Guarding against an accidental undefined

The notStrictEqual assertion is satisfied by undefined, so the buggy function passes it. The output demonstrates why a negative assertion should never stand alone: pair it with a positive check on the type or shape of the result.

Example · javascript
const assert = require('node:assert');

function nextToken(previous) {
  // Bug: forgot the return statement on one branch.
  if (previous === null) return 'token-1';
}

const t = nextToken('token-1');

// This passes — undefined is not strictly equal to 'token-1'.
assert.notStrictEqual(t, 'token-1');
console.log('notStrictEqual passed for value:', t); // undefined

// Which is why it needs a positive assertion beside it.
try {
  assert.strictEqual(typeof t, 'string');
} catch (err) {
  console.log('but the type check catches the bug:', err.code);
}

Inside the built-in test runner

Walking down the tree with notStrictEqual at every level is how you distinguish a deep clone from a shallow spread; a shallow copy would fail on the second assertion. The closing deepStrictEqual confirms the contents survived the copy intact.

Example · javascript
const test = require('node:test');
const assert = require('node:assert/strict');

function structuredCopy(value) {
  return structuredClone(value);
}

test('structuredCopy deep-copies nested objects', () => {
  const source = { user: { id: 1, roles: ['admin'] } };
  const copy = structuredCopy(source);

  assert.notStrictEqual(copy, source);
  assert.notStrictEqual(copy.user, source.user);
  assert.notStrictEqual(copy.user.roles, source.user.roles);
  assert.deepStrictEqual(copy, source);
});

// $ node --test
// ✓ structuredCopy deep-copies nested objects (0.9ms)

Discussion

  • Be the first to comment on this lesson.