@nestjs/testing doesn't work with vitest

See original GitHub issue

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

When trying to run vitest with @nestjs/testing, it throws errors due to UserService being undefined inside of UserController. I tried doing deep digging into nestjs, comparing jest and vitest but can’t really get enough info for debugging. Decided to create this issue to help tracking/fixing https://github.com/vitest-dev/vitest/issues/708

Minimum reproduction code

https://github.com/wight554/vitest-nestjs-testing

Steps to reproduce

npx vitest run src/users/users.controller.vitest.spec.ts

Expected behavior

vitest should work with @nestjs/testing

Package

Other package

vitest

NestJS version

8.2.3

Packages versions

 _   _             _      ___  _____  _____  _     _____
| \ | |           | |    |_  |/  ___|/  __ \| |   |_   _|
|  \| |  ___  ___ | |_     | |\ `--. | /  \/| |     | |
| . ` | / _ \/ __|| __|    | | `--. \| |    | |     | |
| |\  ||  __/\__ \| |_ /\__/ //\__/ /| \__/\| |_____| |_
\_| \_/ \___||___/ \__|\____/ \____/  \____/\_____/\___/


[System Information]
OS Version     : macOS Monterey
NodeJS Version : v14.19.0
NPM Version    : 6.14.16 

[Nest CLI]
Nest CLI Version : 8.1.5 

[Nest Platform Information]
platform-express version : 8.2.3
schematics version       : 8.0.5
sequelize version        : 8.0.0
testing version          : 8.2.3
common version           : 8.2.3
core version             : 8.2.3
cli version              : 8.1.5

Node.js version

v14.19.0

In which operating systems have you tested?

  • macOS
  • Windows
  • Linux

Other

No response

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

5reactions
jmcdo29commented, Feb 18, 2022

It is actually the problem, believe it or not. Esbuild has partial decorator support, but it does not support emitDecoratorMetadata, which is how Nest automagically knows how to inject providers based on classes. With the @Exclude(), class-transformer is reading metadata specifically set for the property, not anything about the property type. For the @InjectModel(), once again, metadata is manually set for the parameter so Nest knows the injection token to use. If we were to create a new service Users2Service, like so:

import { Injectable } from "@nestjs/common";

@Injectable()
export class Users2Service {
  foo(): string {
    return "foo";
  }
}

And inject it into the UsersService and add a user2Foo to call the foo method


@Injectable()
export class UsersService {
  constructor(
    @InjectModel(User)
    private readonly userModel: typeof User,
    private readonly user2: Users2Service
  ) {}

  user2foo(): string {
    return this.user2.foo();
  }
...
}

and then create a users.service.vitest.spec.ts like so:

import { Test, TestingModule } from "@nestjs/testing";
import { User } from "./models/user.model";
import { UsersService } from "./users.service";
import { getModelToken } from "@nestjs/sequelize";
import { Users2Service } from "./user2.service";

import { beforeEach, describe, it, expect } from "vitest";
import * as vi from "vitest";

const usersArray = [
  {
    firstName: "firstName #1",
    lastName: "lastName #1",
  },
  {
    firstName: "firstName #3",
    lastName: "lastName #2",
  },
];

const oneUser = {
  firstName: "firstName #1",
  lastName: "lastName #1",
};

describe("UserService", () => {
  let service: UsersService;
  let model: typeof User;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UsersService,
        {
          provide: getModelToken(User),
          useValue: {
            findAll: vi.fn(() => usersArray),
            findOne: vi.fn(),
            create: vi.fn(() => oneUser),
            remove: vi.fn(),
            destroy: vi.fn(() => oneUser),
          },
        },
        {
          provide: Users2Service,
          useValue: {
            foo: () => "test foo",
          },
        },
      ],
    }).compile();

    service = module.get<UsersService>(UsersService);
    model = module.get<typeof User>(getModelToken(User));
  });

  it("should be defined", () => {
    expect(service).toBeDefined();
  });

  describe("user2foo", () => {
    it("should return test foo", () => {
      vi.expect(service.user2foo()).toBe("test foo");
    });
  });
});

And run it using npx vitest run src/users/users.service.vitest.spec.ts we’ll get the error that

 FAIL  src/users/users.service.vitest.spec.ts > UserService > user2foo > should return test foo
TypeError: Cannot read properties of undefined (reading 'foo')
 ❯ UsersService.user2foo src/users/users.service.ts:16:22
     14|
     15|   user2foo(): string {
     16|     return this.user2.foo();
       |                      ^
     17|   }
     18|
 ❯ src/users/users.service.vitest.spec.ts:104:24

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯

Test Files  1 failed (1)
     Tests  1 failed | 1 passed (2)
      Time  1.64s (in thread 17ms, 9434.40%)

Meaning that Nest was not able to inject the Users2service because it doesn’t know what type to use.


You can use @Inject() on every one of your dependencies to set the token yourself, so that Nest isn’t trying to read the metadata emitted from the decorator, or you can use a tool that doesn’t use esbuild, because it will not support this feature.

0reactions
wight554commented, Feb 18, 2022

Thanks much, now it’s crystal clear for me. Will see how can this be fixed from vite side

Read more comments on GitHub >

github_iconTop Results From Across the Web

vitest doesn't work properly with @nestjs/testing #708 - GitHub
Describe the bug Running vitest on any sample app from https://github.com/nestjs/nest/tree/master/sample won't run well with testing modules ...
Read more >
Testing | NestJS - A progressive Node.js framework
Automated testing is considered an essential part of any serious software development effort. Automation makes it easy to repeat individual tests or test...
Read more >
Test your TypeScript type with Vitest : r/javascript - Reddit
Unfortunately NestJS doesn't support vitest.
Read more >
Method unit testing failing in nestjs - Stack Overflow
controller.currentUser is a function. It takes in the Request object and returns request.user . Your test should look something like
Read more >
Testing Vite with minimal config using Vitest - LogRocket Blog
Let's discuss how Vitest works, compare it with a popular test suite configuration (Jest and Babel), explore the ways Vitest can simplify ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found