-2

My Angular app uses the oidc-client UserManager class to manage OAuth authentication.

I have a service as below

export class AuthService {
  private userManager: UserManager
  private readonly configService: ConfigService;
  constructor(configService: ConfigService) {
    this.configService = configService;
  }
...
  async load(): Promise<any> {
    config = this.configService.getConfig();
    this.userManager = new UserManager(config);
    const user = await this.userManager.getUser();
...

And my spec file setup is as below:

  beforeEach(() => {
    const spy = jasmine.createSpyObj('UserManager', ['getUser']);
    spy.getUser.and.returnValue(mockUser);
    const configSpy = jasmine.createSpyObj('ConfigService', ['getConfig']);
    configSpy.getConfig.and.returnValue(mockConfig);

    TestBed.configureTestingModule({
      providers: [
        AuthenticationService,
        { provide: UserManager, useValue: spy },
        { provide: AppConfigService, useValue: configSpy }
      ]
    });
    authService = TestBed.inject(AuthenticationService);
    appConfigSpy = TestBed.inject(ConfigService) as jasmine.SpyObj<ConfigService>;
    userManagerSpy = TestBed.inject(UserManager) as jasmine.SpyObj<UserManager>;
  });

...and my first test case is :

    it('should initialise the user manager', async () => {
      // arrange 
      userManagerSpy.getUser.and.resolveTo(mockUser);
      appConfigSpy.getConfig.and.returnValue(mockConfig);

      // act
      await authService.load();

      // assert
      expect(userManagerSpy).toHaveBeenCalled();
    });

I'm getting a 404 error when running tests and I'm guessing the new UserManager(config) and/or the this.userManager.getUser() is trying to make an httpRequest when I want it to return the mock values.

How do I spyOn userManager and mock the return value from getUser()?

My understanding was that the TestBed.configureTestModule providers is for setting up the services which are DI'd into the service, not members of the service itself.

atamata
  • 997
  • 3
  • 14
  • 32
  • How are you injecting `UserManager` ? You can just mock that class – Fcmam5 Feb 27 '23 at 15:49
  • I must confess it's not my code and UserManager is not being injected, I've updated my code to for clarity – atamata Feb 27 '23 at 15:51
  • Still, we do not know how are you injecting this value, this is not a [minimal-reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) – Fcmam5 Feb 27 '23 at 16:05
  • Apologies, I've added more context to my question. The only thing that's being injected is the service which retrieves configuration – atamata Feb 27 '23 at 16:27

1 Answers1

0

You need to spy on a constructor. In JS world you can do something like this

spyOn(window, 'UserManager').andReturn(...);

Topic about spying on constructor: Spying on a constructor using Jasmine

Instead of ... You can create a spy/mock and later check if #getUser() function was called. Or you can simply create Moco implementation for #getUser().

However remember that "Everytime a mock returns a mock a fairy dies". In other words - this is not the best way to write test and it indicates problem with code quality. If the UserManager was created inside function - it's not the service and I think it should not have logic.

Maybe you can refactor the code in a way that the config is used to call method of a service injected in constructor of AuthService?