Testing Utility Functions with Jest Spies
This challenge focuses on using Jest spies to monitor and control the behavior of utility functions within a larger module. Spies are invaluable for isolating units of code during testing, allowing you to verify interactions and mock dependencies without altering the original function. You'll be creating a simple utility function and then using a Jest spy to track its calls and potentially modify its return value during testing.
Problem Description
You are tasked with testing a module that utilizes a utility function called formatUsername. This function takes a username string as input and adds a prefix "User: " to it. The formatUsername function is defined in a separate file called usernameUtils.ts. Your goal is to write a Jest test that uses a spy to:
- Verify that
formatUsernameis called with the correct username. - Mock the return value of
formatUsernameto a specific string for testing purposes. This allows you to isolate the logic that uses the formatted username, without relying on the actual formatting logic.
Key Requirements:
- Create a
usernameUtils.tsfile containing theformatUsernamefunction. - Create a test file (
usernameUtils.test.ts) that imports theformatUsernamefunction. - Use
jest.spyOnto create a spy on theformatUsernamefunction. - Assert that the spy was called with the expected username.
- Use the spy's
mockReturnValuemethod to return a predefined string during the test. - Assert that the code using the formatted username behaves as expected with the mocked return value.
Expected Behavior:
The test should pass only if:
- The spy is correctly created on the
formatUsernamefunction. - The spy is called with the correct username during the test.
- The spy's
mockReturnValueis used to control the return value. - The code under test correctly handles the mocked return value.
Examples
Example 1:
// usernameUtils.ts
export function formatUsername(username: string): string {
return `User: ${username}`;
}
// usernameUtils.test.ts
import { formatUsername } from './usernameUtils';
describe('formatUsername', () => {
it('should mock the return value of formatUsername', () => {
const spy = jest.spyOn(formatUsername, 'mockImplementation'); // Use mockImplementation to spy
const username = 'testuser';
const mockedReturnValue = 'Mocked User: testuser';
spy.mockReturnValue(mockedReturnValue);
const result = `Hello, ${formatUsername(username)}`;
expect(spy).toHaveBeenCalledWith(username);
expect(result).toBe(mockedReturnValue);
});
});
Example 2:
// usernameUtils.ts
export function formatUsername(username: string): string {
return `User: ${username}`;
}
// usernameUtils.test.ts
import { formatUsername } from './usernameUtils';
describe('formatUsername', () => {
it('should mock the return value of formatUsername and verify call', () => {
const spy = jest.spyOn(formatUsername, 'mockImplementation');
const username = 'anotheruser';
const mockedReturnValue = 'Mocked User: anotheruser';
spy.mockReturnValue(mockedReturnValue);
const result = `Welcome, ${formatUsername(username)}`;
expect(spy).toHaveBeenCalledWith(username);
expect(result).toBe(mockedReturnValue);
});
});
Constraints
- The
formatUsernamefunction should be a pure function (no side effects). - The test should only mock the
formatUsernamefunction's return value, not its implementation. - The test should be written in TypeScript.
- The username input should always be a non-empty string.
Notes
- Consider using
jest.spyOnto create the spy. mockReturnValueis the key to controlling the return value of the spied function during the test.- Remember to import the
formatUsernamefunction into your test file. - Think about how to structure your test to clearly demonstrate the mocking and verification of the spy. Focus on isolating the code that uses the formatted username.
- The
mockImplementationmethod is used to spy on the function and then override its return value. This is different frommockReturnValuewhich only overrides the return value.