'How to test nextjs endpoint using Jest?
I have an endpoint that handles user signup:
import { createToken } './token'; // Unable to mock
import { sendEmail } './email'; // Unable to mock
export default async function signUp(
req: NextApiRequest,
res: NextApiResponse
): Promise<any> {
try {
// Generate a verification token
const token = await createToken(req.user);
// Email the token
await sendEmail(req.user, token);
return res.status(200).send({ done: true });
} catch (error: any) {
console.error(error);
return res.status(500).end(error.message);
}
}
How do I mock the imported dependencies for my jest unit tests?
import signup from './signup';
describe('signup', () => {
it('should return success', async () => {
const req: IncomingMessage = {} as unknown as IncomingMessage;
const res: ServerResponse = {
end: jest.fn(),
} as unknown as ServerResponse;
const actual = await signup(req, res);
...
});
});
Is it the case that Jest cannot actually mock these nested dependencies and some sort of DI pattern needs to be implemented here in the endpoint? If so, what DI patterns can I use to support unit tests for Nextjs endpoints?
Solution 1:[1]
It looks like In my case I have a lot of dependencies in my Next API endpoint.jest.mock doesn't support mocking dependencies for imports outside of the actual test file (.spec.ts & .test.ts).
I opted to use Nextjs's middleware pattern to test my endpoint logic instead.
// Helper method to wait for a middleware to execute before continuing
// And to throw an error when an error happens in a middleware
function runMiddleware(req: NextApiRequest, res: NextApiResponse, fn: Function) {
return new Promise((resolve, reject) => {
fn(req, res, (result: any) => {
if (result instanceof Error) {
return reject(result)
}
return resolve(result)
})
})
}
Extract the endpoint logic to the function and instead test only the extracted function.
// We test this function instead of the endpoint
export function post(
_createToken: Function,
_sendEmail: Function,
) {
return async function(req: NextApiRequest, res: NextApiResponse) {
...
}
}
Here is an outline for the test. My actual code depends on classes instead of functions but they amount to similar things.
describe('signup', () => {
let createToken: Function;
let sendEmail: Function;
beforeAll(() => {
createToken = jest.fn();
sendEmail = jest.fn();
});
it('should complete the happy path', async () => {
const req: NextApiRequest = {} as unknown as NextApiRequest;
const res: NextApiResponse = {} as unknown as NextApiResponse;
await (
await post(createToken, sendEmail)
)(req, res);
// expect
});
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
