vitest icon indicating copy to clipboard operation
vitest copied to clipboard

`expect` `toThrow` does not match empty string

Open dsogari opened this issue 1 year ago • 5 comments

Describe the bug

The toThrow method on the JestAssertion interface does not match the empty string when using a regular expression matcher (e.g., /^$/). Instead, it gives the following output:

AssertionError: expected [Function] to throw an error

- Expected: 
null


+ Received: 
""

Reproduction

https://stackblitz.com/edit/vitest-dev-vitest-otkry8?file=test%2Fbasic.test.ts

import { expect, test } from 'vitest';

test('should throw empty string', () => {
  expect(() => { throw '' }).toThrow(/^$/);
});

System Info

System:
    OS: Linux 5.15 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish)
    CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
    Memory: 5.31 GB / 7.60 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 20.11.0 - ~/.nvm/versions/node/v20.11.0/bin/node
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.0/bin/npm
    bun: 1.0.25 - ~/.bun/bin/bun
  npmPackages:
    vitest: ^1.3.0 => 1.3.0

Used Package Manager

npm

Validations

dsogari avatar Feb 18 '24 01:02 dsogari

I think this behavior is directly coming from chai:

https://github.com/vitest-dev/vitest/blob/7d9b1fb02338beef048487ef07f6083aa5559106/packages/expect/src/jest-expect.ts#L530-L532

Here is a reproduction: https://stackblitz.com/edit/vitest-dev-vitest-8a9pvm?file=repro-chai.mjs

Show code
import * as chai from 'chai';

try {
  chai
    .expect(() => {
      throw '';
    })
    .throws(/^$/);
} catch (e) {
  console.error(e);
}
// AssertionError: expected [Function] to throw an error
//     at eval (/home/projects/vitest-dev-vitest-8a9pvm/repro-chai.mjs:21:6)
//     at _0xba6ba0.run (https://vitestdevvitest8a9pvm-zty5.w-credentialless.staticblitz.com/blitz.a9c8a5a3.js:352:372622)
//     at _0x3775c6._evaluate (https://vitestdevvitest8a9pvm-zty5.w-credentialless.staticblitz.com/blitz.a9c8a5a3.js:352:378123)
//     at async ModuleJob.run (node:internal/modules/esm/module_job:181:2372) {
//   actual: '',
//   expected: null,
//   showDiff: true,
//   operator: 'strictEqual'
// }

try {
  chai
    .expect(() => {
      throw 'hello';
    })
    .throws(/^$/);
} catch (e) {
  console.error(e);
}
// AssertionError: expected [Function] to throw error matching /^$/ but got 'hello'
//     at eval (/home/projects/vitest-dev-vitest-8a9pvm/repro-chai.mjs:31:6)
//     at _0xba6ba0.run (https://vitestdevvitest8a9pvm-zty5.w-credentialless.staticblitz.com/blitz.a9c8a5a3.js:352:372622)
//     at _0x3775c6._evaluate (https://vitestdevvitest8a9pvm-zty5.w-credentialless.staticblitz.com/blitz.a9c8a5a3.js:352:378123)
//     at async ModuleJob.run (node:internal/modules/esm/module_job:181:2372) {
//   actual: 'hello',
//   expected: /^$/,
//   showDiff: true,
//   operator: 'strictEqual'
// }

hi-ogawa avatar Feb 22 '24 08:02 hi-ogawa

This'll probably be fixed in chaijs/chai#1609

43081j avatar Feb 26 '24 19:02 43081j

@43081j what if I want to throw undefined?

Just kidding 😄

dsogari avatar Feb 27 '24 04:02 dsogari

Seriously though, couldn't the initial value be a dummy object? Like this:

const noError = {};
var caughtErr = noError;
// ...
    caughtErr !== noError

dsogari avatar Feb 27 '24 04:02 dsogari

we could support undefined (via a flag rather than a dummy obj most likely) but i just figured nobody should really be doing that in the first place 🤔 tbh, all thrown errors these days should be Error instances

i feel like supporting that will only lead to confusion further down the line ("expected x not to throw but it threw undefined" etc)

43081j avatar Feb 27 '24 09:02 43081j

we released chai 5.1.1 recently which fixes this, and renovatebot already bumped the version here in vitest. this issue can be closed i think

43081j avatar May 11 '24 08:05 43081j