Server Tests

All right. This spun into a larger piece of work than I super wanted. In retrospect I should have set up users with tests then auth and tests then my hunts with tests. Opening a PR up against master at this point says we have 753 additions. There's a good amount of generated code, but still.

For example, using nest generate in the CLI to set up my module/service/controller combos did set up tests, but our coverage is abysmal.

Since I ran into inconsistencies with my DTOs, routes, entities, et cetera when finalizing my database tables I think it's best to make sure everything is tested and working as expected before going back to the front end to work on leveraging all this amazingly perfect code we've written.

Copilot, "write me tests"

I wonder about how to provide context to copilot best here.

Copilot, "add get user id testGuestUsername and expect not found error"

I wanted to add to the Delete test that Copilot originally made so I went into the body of the test and used inline copilot and it and voila.

Copilot, "merge coverage reports from unit tests and end to end tests"

Copilot tells me to use the jest-coverage-merge library which seems to not exist...

Copilot, "expect an exception"

When I ask Copilot to update my unit test to expect an error it tries to copy my end to end test setup and tests into my unit test. Okay...

End to End to Unit

Hmm. I'm having a little trouble separating my concerns with unit and end to end tests. I can unit test that the function handles the expected parameters, but I think I need end to end tests to make sure the parameters are being passed as expected.

I'm not sure what best practices are for testing methods with all these decorators in place.

For example, if I want only SuperUsers to have access to some endpoints, I can unit test my function that it checks the request object that is passed to it, but in my unit test I'm manually passing that request objects so I don't know for sure that it will correctly be handled when I'm getting an HTTP request or that it is loading the requesting user's object to the request object safely and that the endpoint is guarded.

I think I'll have some repeated code unless I want to rely only on end to end tests for some use cases. But that would be annoying for refactoring so maybe this is just how it is with tests.

Overall it's copy paste after solving how the test is written. I just wish copilot was able to help a little more so I wouldn't have to manually copy paste my unit tests, but as it stands Copilot keeps trying to turn my unit tests into end to end tests. If Copilot could roll its eyes at me for trying to write the same tests twice I feel like it would.

Because we have controllers and services a single end to end test could cover both of those instead of having unit tests written again for services. Is there a way to improve it? Am I overthinking it? Am I just not appreciating unit tests vs end to end tests the way I should?

Or maybe it's a code smell that I have some logic in my endpoints that could be pulled into their own functions and tested in isolation.

  @UseGuards(JwtAuthGuard)
  @Delete(':id')
  async remove(
    @Param('id') id: string,
    // req relies on user object being attached to the request by the JwtAuthGuard
    @Req() req: { user?: { role: UserRoles; id: number } },
  ) {
    const user = req.user
    const deleteTargetId = Number(id)

    if (
      !user ||
      (user.role !== UserRoles.SUPERUSER && user.id !== deleteTargetId)
    ) {
      throw new ForbiddenException('You are not allowed to delete this user')
    }

    await this.usersService.remove(deleteTargetId)
    return {
      message: `User with id ${id} deleted`,
      statusCode: 200,
    }
  }

What do you think the best way to test the above code would be?

I think I'll need to merge my unit and end to end test coverage reports.