vitest: CTRL+C does not immediately stop running tests

Describe the bug

<kbd>CTRL</kbd>+<kbd>C</kbd> does not immediately stop Vitest when tests are slow or stuck.

I’ve seen Vitest being impossible to terminate when tests are stuck because of an issue with fake timers for example, I had to completely close the terminal. When test are just particularly slow it’s frustrating that Vitest doesn’t immediately stops when pressing <kbd>CTRL</kbd>+<kbd>C</kbd>. I think this affects bail: 1 too, not 100% sure.

Jest does not have this issue.

Reproduction

https://stackblitz.com/edit/vitest-dev-vitest-c5wvvm?file=test%2Fsuite1.test.ts,test%2Fslow.test.ts,test%2Fsuite2.test.ts,vite.config.ts,test%2Fsuite0.test.ts&initialPath=__vitest__/

  1. run npm run test:run slow
  2. press <kbd>CTRL</kbd>+<kbd>C</kbd> when the test runs
  3. Vitest hangs and does not immediately terminate image

System Info

System:
    OS: Windows 10 10.0.22621
    CPU: (64) x64 AMD Ryzen Threadripper 3970X 32-Core Processor
    Memory: 17.54 GB / 31.86 GB
  Binaries:
    Node: 20.2.0 - C:\Program Files\nodejs\node.EXE
    npm: 9.6.7 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Spartan (44.22621.1778.0), Chromium (114.0.1823.43)
    Internet Explorer: 11.0.22621.1
  npmPackages:
    @vitejs/plugin-react: ^4.0.0 => 4.0.0
    @vitest/coverage-v8: ^0.32.0 => 0.32.0
    vite: ^4.3.5 => 4.3.9
    vitest: ^0.32.0 => 0.32.0

Used Package Manager

npm

Validations

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 1
  • Comments: 25 (24 by maintainers)

Most upvoted comments

I’ve been debugging this for a while and I think the root cause is identified now. In #3407 I assumed that signal-exit would be the one who handled multiple process.on('SIGINT') handlers, so that on first SIGINT it would call the one defined in Vitest and on second SIGINT it would call its own. But this does not seem to be the case. It looks like this weird SIGINT handling is coming from pnpm and does not happen on Windows. 😕

Testing following script gives different SIGINT handling depending on OS and package manager:

// index.mjs
setInterval(() => process.stdout.write("."), 500);
process.on("SIGINT", () => console.log("SIGINT received"));

// Helper to force exit after 10 seconds just to that we don't get stuck forever
setTimeout(() => {
  console.log("Forcing timeout exit");
  process.exit(0);
}, 10_000);
{
  "scripts": {
    "start": "node index.mjs"
  }
}

Running the script above and hitting CTRL + C twice, with 1s delay between:

  • Expected: When CTRL + C is pressed, the message should be printed. Process should not terminate as SIGINT is intercepted.

  • MacOS + pnpm@8.6.2: Process terminates on second CTRL + C. Handler is called twice on first CTRL + C.

  • MacOS + npm@9.3.1: Process does not terminate. Handler is called twice on each CTRL + C.

  • MacOS + yarn@1.22.19: On first CTRL + C the script moves to background and cursor is moved to terminal. The logging leaks from background process to terminal. SIGINT handler is called only once.

  • MacOS + node@18.14.0, as in node index.mjs: Handler is called only once. Process does not terminate. This works correctly. ✅

  • Windows 11 + pnpm@8.6.2: On first CTRL + C the script moves to background and cursor is moved to terminal. The logging leaks from background process to terminal. SIGINT handler is called only once.

  • Windows 11 + npm@9.5.1: Same as pnpm above.

  • Windows 11 + node©18.16.0: Same as on Mac, correct behaviour. ✅

So I guess we should not count on catching SIGINT at all. Maybe we should instead capture keys with process.stdin.on('keypress' even when in run mode, and simply call process.exit when second key press is caught.

I’m now able to reproduce this using the minimal example from above. This is clearly a Windows bug as on macOs the test case exits on second CTRL + c immediately.

https://github.com/vitest-dev/vitest/assets/14806298/9dba47fe-b251-444b-be90-08ec9da16e96