I'm not sure if my CognitoService class is being exported as expected to my JEST configuration because I'm still having this issue. I tried changing the way that the class is being exported without any good results, also I reviewed my jest.config.js several times but everything seems to be ok, any ideas?
This is the issue on my test console (jest):
TypeError: cognito_utils_1.CognitoService is not a constructor
23 | );
24 |
> 25 | const cognitoService: CognitoService = new CognitoService(
| ^
26 | COGNITO_URL,
27 | COGNITO_USERS_CLIENT_ID,
this is my unit test: index.test.ts
import { handler } from './index';
import { Context, APIGatewayProxyCallback } from 'aws-lambda';
import { CognitoService } from '@mylib/cognito-utils';
const createMockContext = (): Context => ({
...
});
const createMockCallback = (): APIGatewayProxyCallback => (error, result) => {};
describe('handler', () => {
beforeEach(() => {
jest.resetModules();
});
it('should return ...', async () => {
const event = {
httpMethod: 'PUT',
request: {
...
}
};
// HERE IS THE ERROR /////////////////////////////////////
const mockGetUserBySub = jest.fn().mockResolvedValue(null);
jest.mock('@mylib/cognito-utils', () => {
return {
CognitoService: jest.fn().mockImplementation(() => {
return {
getUserBySub: mockGetUserBySub
}
})
}
});
// HERE IS THE ERROR /////////////////////////////////////
const context = createMockContext();
const callback = createMockCallback();
const result = await handler(event, context, callback);
expect(result.statusCode).toBe(404);
expect(result.body).toEqual(JSON.stringify({ message: 'User not found in cognito' }));
});
});
this is the handler that I want to test: index.ts
import { Handler } from 'aws-lambda';
import { CognitoService } from '@mylib/cognito-utils';
export const handler: Handler = async (event) => {
const cognitoService: CognitoService = new CognitoService(
COGNITO_URL,
COGNITO_USERS_CLIENT_ID,
COGNITO_USERS_POOL_ID,
COGNITO_REGION,
);
const { id: userId } = await cognitoService.getUserBySub('123123');
if (!userId) {
return {
statusCode: 404,
body: JSON.stringify({ message: 'User not found in cognito' }),
};
}
return {
statusCode: 404,
body: JSON.stringify({ message: userId }),
};
};
and this is my cognitoService class: cognito-service.ts
import {
CognitoIdentityProviderClient,
CognitoIdentityProviderClientConfig,
} from '@aws-sdk/client-cognito-identity-provider';
import { UserMetadataAttributes } from '@mylib/models-common';
export class CognitoService {
identityProviderClient: CognitoIdentityProviderClient;
constructor(
private COGNITO_URL: string,
private COGNITO_CLIENT_ID: string,
private COGNITO_POOL_ID: string,
private COGNITO_REGION: string,
) {
const config: CognitoIdentityProviderClientConfig = {
region: COGNITO_REGION,
endpoint: COGNITO_URL,
};
this.identityProviderClient = new CognitoIdentityProviderClient(config);
}
async getUserBySub(sub: string): Promise<UserMetadataAttributes> {
if (sub) {
...
}
throw new Error('User sub required');
}
}
You can't use
jest.mockinside of a test. It has to be a the top level. How jest's mocking actually works under the hood is:jest.mockstatementsNote that this also adds an implicit constraint that you can't reference values outside of the mock function (with some caveats around
const, but life will be easier if you just assume there are no exceptions :) )Try something like:
Also note that if there are other things in that lib that you don't want to mock, you can preserve them like:
Additional $0.02; your class doesn't actually allow
nullas a result. If you're mocking this case, then you likely don't have strict mode enabled. You should really consider doing that. It eliminates whole classes of errors around incorrect types, including null/undefined. Half of the language is disabled without it, resulting in code that's not valid JS, and not valid TS either.