oidc-client-ts icon indicating copy to clipboard operation
oidc-client-ts copied to clipboard

Unit tests and mock UserManager

Open flindby opened this issue 3 years ago • 3 comments

I'm migrating from oidc-client to oidc-client-ts and having trouble to adjust my unit tests.

Method under test:

public onUserExpired(callback: () => void) {
   this.userManager.events.addAccessTokenExpired(callback);
}

I want to verify that my registered callback is invoked upon access token expiration.

Previous test code:

it('registers callback for event: addAccessTokenExpired', async () => {
      // Arrange
      let addAccessTokenExpired!: () => void;
      mockUserManager.events = {
        addAccessTokenExpired: (callback: any) => (addAccessTokenExpired = callback),
      } as any;
      const authService = new AuthService(mockUserManager);

      // Act
      const mockCallback = jest.fn();
      authService.onUserExpired(mockCallback);
      addAccessTokenExpired();

      expect(mockCallback).toBeCalledTimes(1);
    });

New adjusted test code:

it('registers callback for event: addAccessTokenExpired', async () => {
      // Arrange
      const mockUserManager = new UserManager({
          authority: 'authority',
          redirect_uri: 'http://test.com',
          client_id: 'app',
          monitorSession: true,
          accessTokenExpiringNotificationTimeInSeconds: 60  
       }) as Mock<UserManager>;

      let addAccessTokenExpired!: () => void;
      mockUserManager.events.addAccessTokenExpired = (callback: any) => (addAccessTokenExpired = callback) as any;
      const authService = new AuthService(mockUserManager);

      // Act
      const mockCallback = jest.fn();
      authService.onUserExpired(mockCallback);
      addAccessTokenExpired();

      expect(mockCallback).toBeCalledTimes(1);
    });

but mockUserManager.events is undefined.

flindby avatar Aug 22 '22 12:08 flindby

I guess you need to mock events then too

pamapa avatar Aug 23 '22 15:08 pamapa

I guess you need to mock events then too

When I look att the source code for UserManager, it looks like events is initialized, so shouldn't need to mock it? https://github.com/authts/oidc-client-ts/blob/main/src/UserManager.ts#L91

flindby avatar Sep 19 '22 12:09 flindby

That code is in the constructor. Is the constructor called when mocked? The answer is yes, i can see it in your code snippet, strange...

Elsewhere in your code you make

 mockUserManager.events = {
        addAccessTokenExpired: (callback: any) => (addAccessTokenExpired = callback),
      } as any;

but events is a getter on _events....

In a dependent library react-oidc-context we mock UserManager like this https://github.com/authts/react-oidc-context/blob/main/test/mocks/oidc-client-ts.ts

const MockUserManager: typeof UserManager = jest.fn(function (this: { events: Partial<UserManagerEvents> }) {
    this.events = {
        ...
    };

    return this as UserManager;
});

pamapa avatar Sep 19 '22 14:09 pamapa