I have TypeScript classes that look like this:
// value-service.ts
export class ValueService {
fetchValue(): Promise<string> { ... }
}
// broker.ts
import {ValueService} from ./value-service.js ;
export class Broker {
public readonly svc = new ValueService();
}
// consumer.ts
import {Broker} from ./broker.js ;
export class Consumer {
constructor (private readonly broker: Broker) { }
public async useValue() {
const val = await this.svc.fetchValue();
// Use val
return `${val}123`;
}
}
I d like to mock the implementation of ValueService#fetchValue
while writing tests for Consumer#useValue
. I believe this is close to correct but I don t think I m using the Jest mocking functions quite right:
import {jest} from @jest/globals ;
import {ValueService} from ./value-service.js ;
import {Broker} from ./broker.js
import {Consumer} from ./consumer.js ;
// "easy" mocking, methods return undefined unless overridden
jest.mock( ./value-service.js );
jest.mock( ./broker.js );
describe( Consumer , () => {
let instance: Consumer;
beforeEach(() => {
const broker = jest.mocked(new Broker());
instance = new Consumer(broker);
// fails at runtime, `broker.svc` is undefined
broker.svc.fetchValue.mockResolvedValueOnce( abc );
const mockSvc = jest.mocked(new ValueService());
mockSvc.fetchValue.mockResolvedValueOnce( abc );
// ts error, `broker.svc` property is readonly (can ts-ignore or anycast)
broker.svc = mockSvc;
// fails at runtime, svc property does not exist
jest.replaceProperty(broker, svc , mockSvc);
});
it( uses the value , async () => {
expect(await instance.useValue()).toBe( abc123 );
});
});
I d like to avoid having to make my own factory function for jest.mock(...)
, since the "automatic" mocks more or less do what I need. I only need a clean way of replacing this top level property on the mocked dependency.