Hone logo
Hone
Problems

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:

  1. Verify that formatUsername is called with the correct username.
  2. Mock the return value of formatUsername to 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.ts file containing the formatUsername function.
  • Create a test file (usernameUtils.test.ts) that imports the formatUsername function.
  • Use jest.spyOn to create a spy on the formatUsername function.
  • Assert that the spy was called with the expected username.
  • Use the spy's mockReturnValue method 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 formatUsername function.
  • The spy is called with the correct username during the test.
  • The spy's mockReturnValue is 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 formatUsername function should be a pure function (no side effects).
  • The test should only mock the formatUsername function'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.spyOn to create the spy.
  • mockReturnValue is the key to controlling the return value of the spied function during the test.
  • Remember to import the formatUsername function 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 mockImplementation method is used to spy on the function and then override its return value. This is different from mockReturnValue which only overrides the return value.
Loading editor...
typescript