Jest.js 如何使用@Query装饰器和验证管道测试Nestjs路由?

20jt8wwn  于 5个月前  发布在  Jest
关注(0)|答案(1)|浏览(82)

假设我有一个控制器,定义如下:

class NewsEndpointQueryParameters {
  @IsNotEmpty()
  q: string;

  @IsNotEmpty()
  pageNumber: number;
}

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get(['', 'ping'])
  ping(): PingEndpointResponse {
    return this.appService.ping();
  }

  @Get(['news'])
  getNews(
    @Query() queryParameters: NewsEndpointQueryParameters
  ): Observable<NewsEndpointResponse> {
    return this.appService.getNews(
      queryParameters.q,
      queryParameters.pageNumber
    );
  }
}

字符串
我希望能够测试在请求中发生了什么,例如,如果没有提供查询参数。
这是我的测试设置:

describe('AppController', () => {
  let app: TestingModule;
  let nestApp: INestApplication;
  let appService: AppService;

  beforeAll(async () => {
    app = await Test.createTestingModule({
      controllers: [AppController],
      providers: [AppService],
      imports: [HttpModule],
    }).compile();
    appService = app.get<AppService>(AppService);
    nestApp = app.createNestApplication();
    await nestApp.init();
    return;
  });

  describe('/', () => {
    test('Return "Pong!"', async () => {
      const appServiceSpy = jest.spyOn(appService, 'ping');
      appServiceSpy.mockReturnValue({ message: 'Pong!' });
      const response = await supertest(nestApp.getHttpServer()).get('/');
      expect(response.body).toStrictEqual({
        message: 'Pong!',
      });
      return;
    });
  });

  describe('/ping', () => {
    test('Return "Pong!"', async () => {
      const appServiceSpy = jest.spyOn(appService, 'ping');
      appServiceSpy.mockReturnValue({ message: 'Pong!' });
      const response = await supertest(nestApp.getHttpServer()).get('/ping');
      expect(response.body).toStrictEqual({
        message: 'Pong!',
      });
      return;
    });
  });

  describe('/news', () => {
    describe('Correct query', () => {
      beforeEach(() => {
        const appServiceSpy = jest.spyOn(appService, 'getNews');
        appServiceSpy.mockReturnValue(
          new Observable<NewsEndpointResponse>((subscriber) => {
            subscriber.next({
              data: [{ url: 'test' }],
              message: 'test',
              status: 200,
            });
            subscriber.complete();
          })
        );
        return;
      });

      test('Returns with a custom body response.', async () => {
        const response = await supertest(nestApp.getHttpServer()).get(
          '/news?q=test&pageNumber=1'
        );
        expect(response.body).toStrictEqual({
          data: [{ url: 'test' }],
          message: 'test',
          status: 200,
        });
        return;
      });

      return;
    });

    describe('Incorrect query', () => {
      test("Returns an error if 'q' query parameter is missing.", async () => {
        return;
      });

      test("Returns an error if 'pageNumber' query parameter is missing.", async () => {
        return;
      });

      return;
    });

    return;
  });

  return;
});


如果我做nx serve,然后curl 'localhost:3333/api/ping',我得到:

{"message":"Pong!"}


如果我做curl 'localhost:3333/api/news?q=test&pageNumber=1',我得到:

{"data":['lots of interesting news'],"message":"News fetched successfully!","status":200}


最后,如果我做curl 'localhost:3333/api/news?q=test',我得到:

{"statusCode":400,"message":["pageNumber should not be empty"],"error":"Bad Request"}


我如何复制最后一个案例?如果我使用supertest,就不会像上面那样返回错误。我还没有找到一种方法来模拟Controller的函数。

zbwhf8kr

zbwhf8kr1#

非常感谢@jmcdo29为我解释如何做到这一点。
代码:

beforeAll(async () => {
  app = await Test.createTestingModule({
    controllers: [AppController],
    providers: [
      AppService,
      { provide: APP_PIPE, useValue: new ValidationPipe() },
    ],
    imports: [HttpModule, AppModule],
  }).compile();
  appService = app.get<AppService>(AppService);
  nestApp = app.createNestApplication();
  await nestApp.init();
  return;
});

字符串
说明:

  • 我们需要在main.ts中对bootstrap()的行为进行建模。在我的例子中,in看起来像这样:
async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    cors: environment.nestCors,
  });
  app.useGlobalPipes(new ValidationPipe());
  const globalPrefix = 'api';
  app.setGlobalPrefix(globalPrefix);
  const port = process.env.PORT || 3333;
  await app.listen(port, () => {
    Logger.log('Listening at http://localhost:' + port + '/' + globalPrefix);
  });
}


除了导入AppModule,我们还可以像这样配置为测试而创建的应用程序:nestApp.useGlobalPipes(new ValidationPipe())(这需要在await nestApp.init()之前完成)

相关问题