vitest icon indicating copy to clipboard operation
vitest copied to clipboard

CTRL+C does not exit tests in watch mode

Open floratmin opened this issue 1 year ago • 13 comments

Describe the bug

When I am running tests in watch mode and make some minor changes in the test files, after a while, vitest can not exit watch mode. Hitting CTRL+C multiple times does not work either. I tried to isolate the problem, but strangely this only happens when some tests are run together. Running vitest with pnpm run test:server or pnpm run test:native does not make vitest hang. But running pnpm run test:only which is a combination of both previous tests makes vitest hang after a while. In the only-native.spec.ts file I am using Fastify native, in the only-server.spec.ts file Fastify is completely mocked out.

Reproduction

fastify-vitest-shutdown

System Info

System:
    OS: Linux 5.15 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish)
    CPU: (16) x64 AMD Ryzen 7 5700G with Radeon Graphics
    Memory: 15.87 GB / 30.73 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 20.8.0 - ~/.nvm/versions/node/v20.8.0/bin/node
    npm: 10.1.0 - ~/.nvm/versions/node/v20.8.0/bin/npm
    pnpm: 8.14.0 - ~/.local/share/pnpm/pnpm
  Browsers:
    Chrome: 120.0.6099.216
  npmPackages:
    vite: ^5.0.11 => 5.0.11 
    vitest: ^1.2.0 => 1.2.0

Used Package Manager

npm

Validations

floratmin avatar Jan 14 '24 11:01 floratmin

I tried the reproduction case on Github Codespaces but wasn't able to reproduce the issue.

make some minor changes in the test files

Could you write down more specific steps describing what exactly has to be changed in test files?

AriPerkkio avatar Jan 14 '24 14:01 AriPerkkio

I mean any changes which trigger a reload of the test watcher, like changing one letter in a test description or making a change for a test to fail. I also could not reproduce the failure on github codespaces, but realized that this happens on my machine only when node is version 20 or 21. With node 16 or 18 I can not reproduce this behavior. I also wiped the whole pnpm file cache and reinstalled everything but it did not make any difference.

floratmin avatar Jan 15 '24 08:01 floratmin

I am also seeing this (and have been for a number of weeks) but I am struggling to narrow down what exactly causes the issue.

For me, I start vitest with the vitest command and all is well for a short while. However, after a few minutes of making changes to my code, the test watcher becomes unresponsive and I can't quit using q or crtl-c. I have to close the terminal instance and then issue a SIGSTOP to kill the underlying process. The offending process is also running at 100% CPU when the problem occurs.

I am on node 20, using Kitty terminal emulator on OSX. Vitest v1.

acurrieclark avatar Jan 16 '24 15:01 acurrieclark

this happens on my machine only when node is version 20 or 21.

I'm unable to reproduce this locally using Node v21 with MacOS.

AriPerkkio avatar Jan 16 '24 15:01 AriPerkkio

I created a Dockerfile in which I can reproduce the same error. I added it to my repository. If I build and run the Dockerfile and connect to it from two terminals, then I can run pnpm run test:only in one terminal and edit the statusCode to be 20 with vim src/only-native.spec.ts, than after saving the file, the test runner hangs in the other terminal.

floratmin avatar Jan 16 '24 16:01 floratmin

I can reproduce this issue using the provided Dockerfile. Is fastify or some of your dependencies using Node's native fetch? It seems that as soon as I switch Vitest to use --pool=forks the issue goes away.

This looks very much like a duplicate of https://github.com/vitest-dev/vitest/issues/3077 (and https://github.com/vitest-dev/vitest/issues/2008).

image

It's not really CTRL + c that stops working - it's the whole Node process being stuck. See https://github.com/nodejs/undici/issues/2026.

AriPerkkio avatar Jan 21 '24 17:01 AriPerkkio

I am not using in any way fetch from node. What cached my eyes is that the @types/node for version 20 imports the undici-types package. The version for node 18 does not import this package. But this package contains only types. When I use node prior to version 20 or set the flag --pool=forks this issue does not happen.

floratmin avatar Jan 22 '24 16:01 floratmin

What cached my eyes is that the @types/node for version 20 imports the undici-types package. The version for node 18 does not import this package.

The types for node 18 do as of more recent versions; this is definitely unrelated to the issue.

jakebailey avatar Jan 22 '24 16:01 jakebailey

I am not using in any way fetch from node.

It's possible that the root cause of https://github.com/nodejs/undici/issues/2026 that makes node:worker_threads stuck is not directly fetch - it could be other module like ReadableStream or similar. Maybe one of your dependencies is using those.

AriPerkkio avatar Jan 22 '24 16:01 AriPerkkio

I mocked all dependencies out, except the package effection and Fastify, which imports nothing from any other package. It is still the same issue: fastify-vitest-shutdown

floratmin avatar Jan 23 '24 14:01 floratmin

I tried to make a minimal reproduction. When I remove one of the following things than it seems not to fail (with this minimal example it can take many repeated changes before it hangs):

  • kysely which is not used in the function
  • yield* createPool(...);
  • Remove any of the fastify.register(routesBenchmark) or fastify.register(routesScope)
  • fastify.addSchema(schemas)

fastify-vitest-shutdown

floratmin avatar Jan 23 '24 18:01 floratmin

Using just fastify seems to be enough to make node:worker_threads stuck. Having contents below in two different test files and running them parallel in the docker reproduces the issue. Next step would be to look what fastify is doing under-the-hood and trying to replicate this hang without depending on fastify.

repro.test.ts
import { beforeEach, describe, expect, it, afterEach } from "vitest";
import Fastify, { FastifyInstance } from "fastify";

describe("Test native server", () => {
  async function buildFastify() {
    const fastify = await Fastify();

    fastify.get("/", function (_, reply) {
      reply.send({ hello: "world" });
    });

    return fastify;
  }
  let fastify: FastifyInstance;
  beforeEach(async () => {
    fastify = await buildFastify();
  });
  it("should work", async () => {
    fastify.inject(
      {
        method: "GET",
        url: "/",
      },
      (_, response) => {
        expect(response.statusCode).toBe(200);
      }
    );
    await new Promise((resolve) => setTimeout(() => resolve(undefined), 1));
  });
  afterEach(async () => {
    await fastify.close();
  });
});

AriPerkkio avatar Jan 24 '24 15:01 AriPerkkio

not in watch mode, but when using javascript debug terminal, i guess its more or less same issue https://github.com/vitest-dev/vitest/issues/5039

andrew-at-v avatar Jan 29 '24 06:01 andrew-at-v