Skip to content

[Feature]: Allow Callbacks Passed to before*/after* to Return Anything #6033

@ITenthusiasm

Description

@ITenthusiasm

Clear and concise description of the problem

Right now, I have an async function that I use to create and start a server:

async function startServer(port) {
  // ...
}

Within a test file, I have a setup that looks something like this

describe("Description", () => {
  let server: Awaited<ReturnType<typeof startServer>>;

  beforeAll(async () => {
    server = await startServer(port);
  });

  afterAll(() => {
    server.close();
  });

  // ...
});

For brevity, I'd like to write my code like this instead:

describe("Description", () => {
  let server: Awaited<ReturnType<typeof startServer>>;

  beforeAll(async () => (server = await startServer(port)));
  afterAll(() => server.close());
  // ...
});

But I can't, because the current types for before*/after* forbid returning an actual value.

Suggested solution

It would be great if these return types (for before* and after*) could be updated so that developers could shorthand their setup/teardown blocks. For simple setup/teardown steps, this would reduce the lines of code by 2 per function call (assuming a formatter like Prettier is being used).

Alternative

Currently, developers can circumvent the problem by using void. But the appearance of this operator in a codebase is usually considered a smell.

Additional context

I think that this change would make Vitest "more compatible" with Jest users (from a TypeScript perspective). However, I noticed from the docs that beforeAll accepts a cleanup function. So if this feature request was accepted, there'd probably need to be a proper typeof check put in place. (There might already be one in place.)


Search Words: before after promise
Related Issues: #2149

I can understand the reasoning for restricting before*, but I think it would still be nice if after* could be looser in its type (assuming that its return value is not operated on outside of a Promise check). Note: The after* consideration is why I'm keeping this issue separate instead of commenting on the old one.

However, if I may plead my case:

I think it's better to be strict in this case, because hooks implementation differs from jest, and if we don't throw for non-functions, users might wrongly think it is the same, and accidentally return a teardown function.

There are already footguns like this in Vitest. For example, the way that Vitest handles Promises returned from mock functions is different from what Jest does. I consider the difference a significant improvement, but it results in some tripping for developers migrating from Jest. At the end of the day, devs can't avoid reading the migration docs if they're coming from Jest.

If convenience can be afforded to developers by permitting 1-line arrow functions in all cases, I think it's potentially worth allowing the accident.

TypeScript types also don't allow anything but a void/undefined/null/function.

I think for this, the types could just be updated, correct? But that hinges on the previous concern.

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Approved

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions