I have the following TypeScript object defined:
// HttpClient.ts
export type HttpResponse<T> = Response & {
data?: T;
}
async function get<T>(url: string, args: RequestInit = {}): Promise<HttpResponse<T>> {
return fetchRequest<T>(url, {...args, method: 'get'}) // fetchRequest returns value of type Promise<HttpResponse<T>>
}
export default {get} // default export represents an HttpClient object
I also have another file, getFeatureFlag.ts, that uses this HttpClient in its implementation:
// getFeatureFlag.ts
import HttpClient from '../httpClient'
export type FetchResponse<T = any, E = any> = {
data: Nullable<T>;
error: Nullable<E>;
}
export type FeatureFlag = {
toggleActive: boolean; // true/false denotes show/hide feature
}
export async function getFeatureFlag(flagName: string): Promise<FetchResponse<boolean, string>> {
const response = await HttpClient.get<FeatureFlag>(`/v1/toggles/${flagName}/`)
// ... rest of the implementation ...
}
I'm in the process of writing unit tests (using Jest) for this file under getFeatureFlag.test.ts and I have the following snippet within it:
// getFeatureFlag.test.ts
import HttpClient, {HttpResponse} from '../httpClient'
import {getFeatureFlag, FLAG_STORE, FeatureFlag} from '../index'
describe('getFeatureFlag', () => {
beforeEach(async () => {
// vv === THIS LINE IS WHAT THIS POST IS ABOUT === vv
jest.spyOn<HttpResponse<FeatureFlag>, 'get'>(HttpClient, 'get').mockImplementationOnce(() => ({
ok: true,
data: {
toggleActive: true,
},
}))
result = await getFeatureFlag(flagName)
})
it('then perform api request for feature flag data', () => {
expect(HttpClient.get).toHaveBeenCalledWith('/v1/toggles/featureFlag/')
})
})
From within the @types/jest definitions file, the spyOn function is defined as the following:
function spyOn<T extends {}, M extends FunctionPropertyNames<Required<T>>>(
object: T,
method: M
): Required<T>[M] extends (...args: any[]) => any
? SpyInstance<ReturnType<Required<T>[M]>, ArgsType<Required<T>[M]>>
: never;
I am having a lot of difficulty getting the TypeScript compiler to correctly read the below snippet without issue.
jest.spyOn<HttpResponse<FeatureFlag>, 'get'>(HttpClient, 'get').mockImplementationOnce(() => ({
ok: true,
data: {
toggleActive: true,
},
}))
With the above setup, the compiler tells me that get does not satisfy the constraint never and I am at a loss of how to resolve the typing problem here to get my test written/running correctly. The other thing I'm trying to do here is only return a Partial of HttpResponse because I obviously don't want to have to fill in every field within my unit test when they are not needed.
Has anyone been able to apply jest.spyOn correctly with generics to help with this issue?