Home > front end >  Problems mocking static class property
Problems mocking static class property

Time:04-22

I have a class that should log some things. The logger is defined like this.

export class Logger {
  public static client = ClientStrategy.create();

  public async logSth(msg: string) {
    params = {"testThing": msg};
    await Logger.client.updateItem(params);
}
export class ClientStrategy {
  public static create() {
    return new DatabaseClient(); // not important here just a factory, with a method updateItem
  }
}

I am trying to mock this in a jest test. I am trying to do mock this client strategy and a create method for this. But it is not working as I would have expected.

jest.mock("./ClientStrategy");
const mockClientStrategy = jest.mocked(ClientStrategy, false);

describe("Logger", () => {

    beforeEach(() => {
    jest.spyOn(<any>mockDatabaseClientStrategy, "create").mockImplementation(() => {
      return {
        updateItem: () => {
          return {}
        } 
      };
    });
  });

   
  it("should log sth", async () => {
    const response = await Logger.logSth("testMsg");
    expect(response).not.tobeUndefined();
  });
});

but I get Cannot read property "logSth" of undefined. Can you help me what am I doing wrong here? I think that my mock should work fine, but unfortunately I got undefined for this.

CodePudding user response:

Both jest.mock() and jest.spyOn() will work. But there is no need to use them together for your case. So let's just use the jest.spyOn() to solve your problem.

Since the ClientStrategy.create will execute when you import the Logger class, you need to add spy on ClientStrategy.create before importing the Logger class.

Besides, the logSth method is an instance method, NOT a class method.

E.g.

Logger.ts:

import { ClientStrategy } from './ClientStrategy';

console.log('ClientStrategy.create: ', ClientStrategy.create);
export class Logger {
  public static client = ClientStrategy.create();

  public async logSth(msg: string) {
    const params = { testThing: msg };
    return Logger.client.updateItem(params);
  }
}

Logger.test.ts:

import { ClientStrategy } from './ClientStrategy';
// import { Logger } from './Logger';

describe('Logger', () => {
  let mockClient;
  let Logger: typeof import('./Logger').Logger;
  beforeEach(async () => {
    mockClient = {
      updateItem: jest.fn(),
    };
    jest.spyOn(ClientStrategy, 'create').mockReturnValue(mockClient);
    Logger = await import('./Logger').then((m) => m.Logger);
  });
  afterEach(() => {
    jest.restoreAllMocks();
  });

  it('should log sth', async () => {
    mockClient.updateItem.mockResolvedValueOnce('fake value');
    const logger = new Logger();
    const response = await logger.logSth('testMsg');
    expect(response).toEqual('fake value');
  });
});

ClientStrategy.ts:

export class ClientStrategy {
  public static create() {
    return { updateItem: async (params) => 'real value' };
  }
}

Test result:

 PASS  stackoverflow/71938329/Logger.test.ts
  Logger
    ✓ should log sth (22 ms)

  console.log
    ClientStrategy.create:  [Function: mockConstructor] {
      _isMockFunction: true,
      getMockImplementation: [Function (anonymous)],
      mock: [Getter/Setter],
      mockClear: [Function (anonymous)],
      mockReset: [Function (anonymous)],
      mockRestore: [Function (anonymous)],
      mockReturnValueOnce: [Function (anonymous)],
      mockResolvedValueOnce: [Function (anonymous)],
      mockRejectedValueOnce: [Function (anonymous)],
      mockReturnValue: [Function (anonymous)],
      mockResolvedValue: [Function (anonymous)],
      mockRejectedValue: [Function (anonymous)],
      mockImplementationOnce: [Function (anonymous)],
      mockImplementation: [Function (anonymous)],
      mockReturnThis: [Function (anonymous)],
      mockName: [Function (anonymous)],
      getMockName: [Function (anonymous)]
    }

      at Object.<anonymous> (stackoverflow/71938329/Logger.ts:3:9)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.57 s, estimated 11 s

You can uncomment the import { Logger } from './Logger'; statement and comment the import() to check the log. You will see unmocked ClientStrategy.create method:

console.log
    ClientStrategy.create:  [Function: create]
  • Related