apijestjsnestjssuperteste2e

Why does supertest/jest always call the same endpoint when I clearly insert a different path in my test? Is there some config I need to set?


this is my controller class:

@Crud({
  model: {
    type: InferenceFile,
  },
  query: {
    join: {
      model: {
        eager: true,
      },
      file: {
        eager: true,
      },
    },
  },
  params: {
    id: {
      type: 'uuid',
      primary: true,
      field: 'id',
    },
  },
})
@Controller('inference-files')
export class InferenceFilesController {
  constructor(private service: InferenceFilesService) {
  }

  @Get('list/:algorithmId')
  async getAllInferenceFiles(
    @Param('algorithmId') algorithmId: number,
    @Query('name') name: string,
    @Query('page') page: number = 0,
    @Query('size') limit: number = 1000,
  ) {
    return await this.service.findAllByAlgorithmId(algorithmId, name, {
      page,
      limit,
    });
  }

  @Get(':id')
  async get(@Param('id') id: string) {
    const result = await this.service.getFile(id);

    result.presignedUrl = await this.service.getPresignedDownloadUrl(result);
    result.presignedWordsUrl = await this.service.getPresignedWordsUrl(result);
    return result;
  }

  @Get('status')
  async getStatus(@Query('modelId') modelId: number) {
    return await this.service.getStatus(modelId);
  }
}

This is part of my test class where it goes wrong:

it('should return an array of inference file statuses', async () => {
    // Act
    let modelIdToPass = setUp.model1.id;
    const { body } = await supertest
      .agent(setUp.app.getHttpServer())
      .get(`/inference-files/status?${modelIdToPass}`)
      .set('Accept', 'application/json')
      .expect('Content-Type', /json/)
      .expect(200);

    // Assert
    expect(body).toEqual({
      'test-id-2': 'FINISHED',
    });
  });

  it('should return the inference file for the given id', async () => {
    // Act
    const { body } = await supertest
      .agent(setUp.app.getHttpServer())
      .get('/inference-files/' + TestConstants.INFERENCEFILE_ID_1)
      .set('Accept', 'application/json')
      .expect('Content-Type', /json/)
      .expect(200);

    // Assert
    expect(body).toEqual({
      'test-id-1': 'FINISHED',
    });
  });

  it('should return the inference file for the given algorithm id', async () => {
    // Act
    const { body } = await supertest
      .agent(setUp.app.getHttpServer())
      .get('/inference-files/list/' + 9)
      .set('Accept', 'application/json')
      .expect('Content-Type', /json/)
      .expect(200);

    // Assert
    expect(body).toBeDefined();
  });

Al of these tests call the same endpoint: @Get(':id') But when I comment two out of the three of them out, it succeeds.. Or better yet, it calls the remaining "Get" method. I have been looking for an answer for a whole day, but no one seems to have experienced the same problem..

When I look at the documentation online, it doesn't mention anything about routing for this. I also do not wish to mock the implementation (I've seen examples of the routing with express). But that is not what I'm looking for. I wish to test the whole flow, so it needs to call (all or most of) my methods. I use a separate database for testing, so no mocking needed.


Solution

  • Move the endpoint for @Get('status') above the one for @Get(':id') in your controller.

    Because :id comes first, it is assuming that status is actually an id value and is therefore invoking the wrong handler.

    When a request comes to your server all the routes are evaluated one at a time and the first matching route is selected to handle the request.

    This is a duplicate of Error on ordering of methods in controller Nestjs and How to deal with NestJS @Get() decorator? which were both asked recently