tsoa icon indicating copy to clipboard operation
tsoa copied to clipboard

Cannot mock authentication function since v6.4.0

Open jscn opened this issue 1 year ago • 1 comments

I'm using tsoa in conjunction with express and inversify and since 6.4.0 many of my tests are broken because I can no longer mock the authentication function. It's a bit convoluted (for reasons) but I'll try to describe the set up below:

My authentication logic is implemented as a method on a class that has a bunch of dependencies injected in the constructor via inversify. Since tsoa requires the authentication middleware to be a function, I have some code that rebinds and exports the relevant method on my authentication class as a function. That function is then referenced in the tsoa configuration. In my controller tests, I want to override the authentication code, and so I mock the relevant function using jest.spyOn.

This worked up until the change introduced in https://github.com/lukeautry/tsoa/commit/0dac399763fb077e960a1e1ee8ee648275c48ede where the authentication function is rebound and typecast to a local const in the generated code. I don't understand why rebinding the function to a locally scoped const should somehow un-mock the function in question, but that appears to be what's happening.

I'm open to the idea that I'm just holding this wrong, and there may be a simpler approach that isn't vulnerable to this problem.

Sorting

  • I'm submitting a ...

    • [x] bug report
    • [ ] feature request
    • [ ] support request
  • I confirm that I

    • [x] used the search to make sure that a similar issue hasn't already been submit

Expected Behavior

I should be able to mock the authentication code so that I can return a valid user, throw an error, whatever.

The class that implements authentication:

@injectable()
export class TsoaAuthentication {
  constructor(@inject(SomeService) private readonly service: SomeService ) {}

  async authenticate(request: ExpressRequest, securityName: string, scopes?: string[]) {
    // call the service, do the checks, return the user or throw.
  }
}

The file that makes the authentication code conform to the API described in https://tsoa-community.github.io/docs/authentication.html:

import { TsoaAuthentication } from './security';
import { iocContainer } from '../ioc/apiContainer';

const tsoaAuthentication = iocContainer.get(TsoaAuthentication);

/**
 * NB: The name of this export must be `expressAuthentication`.
 * See https://tsoa-community.github.io/docs/authentication.html
 */
export const expressAuthentication = tsoaAuthentication.authenticate.bind(tsoaAuthentication);

The test file:

import * as TsoaAuthenticationModule from '../../../authentication';

describe('the controller', () => {
    const mockSecurityMiddleware = jest
        .spyOn(TsoaAuthenticationModule, 'expressAuthentication')
        .mockResolvedValue(authenticatedUser);

   it('works', async () => {
    // ... test code relying on the authentication function to return authenticatedUser
  })
}

Current Behavior

The tests fail because the original implementation of the authentication function is executed at runtime, instead of the mock/spy. I know that it's related to the aforementioned commit, because I can fix the issue by opening the generated routes, commenting out the relevant line, and importing the original authentication function with the new name:

routesGen.ts:

import { expressAuthentication as expressAuthenticationRecasted  } from './../authentication';
...
// const expressAuthenticationRecasted = expressAuthentication as (req: ExRequest, securityName: string, scopes?: string[], res?: ExResponse) => Promise<any>;

Possible Solution

I don't understand what's happening well enough to suggest a solution

Context (Environment)

Version of the libraries:

  • @tsoa/runtime: 6.4.0
  • @tsoa/cli: 6.4.0
  • jest: 29.5.0
  • inversify: 6.0.1

Version of NodeJS: v18.20.2

jscn avatar Sep 17 '24 02:09 jscn

Hello there jscn 👋

Thank you for opening your very first issue in this project.

We will try to get back to you as soon as we can.👀

github-actions[bot] avatar Sep 17 '24 02:09 github-actions[bot]

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days

github-actions[bot] avatar Oct 18 '24 00:10 github-actions[bot]

@jscn what was the solution for this?

manvydas-tbol avatar Mar 07 '25 13:03 manvydas-tbol

So far my solution has been to not upgrade 😞

jscn avatar Apr 08 '25 01:04 jscn