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

3

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

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,就不会像上面那样返回错误。我还没有找到模拟控制器函数的方法。
1个回答

0
非常感谢@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.tsbootstrap()的行为模型。在我的情况下,它看起来像这样:
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);
  });
}

我们可以通过以下方式配置为测试创建的应用程序,而不是导入AppModulenestApp.useGlobalPipes(new ValidationPipe())(这需要在await nestApp.init()之前完成)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接