Hone logo
Hone
Problems

Mastering Jest's beforeEach Hook for Efficient Test Setup

This challenge focuses on understanding and implementing Jest's beforeEach hook in TypeScript. This hook is crucial for ensuring that your tests are independent and repeatable by executing specific setup logic before each individual test within a describe block. Mastering beforeEach will significantly improve your test suite's organization and reduce code duplication.

Problem Description

You are tasked with writing a series of Jest tests for a simple Counter class. This Counter class has methods to increment, decrement, and reset its internal value. To ensure each test starts with a fresh Counter instance, you need to utilize the beforeEach hook to create and initialize a new Counter object before every test runs.

What needs to be achieved:

  1. Define a Counter class with increment, decrement, and reset methods.
  2. Write Jest tests for the Counter class.
  3. Implement a beforeEach hook within a describe block to instantiate a new Counter object before each test.

Key requirements:

  • The Counter class should maintain an internal value property.
  • The increment method should increase the value by 1.
  • The decrement method should decrease the value by 1.
  • The reset method should set the value back to 0.
  • Each test should operate on a separate instance of the Counter class.

Expected behavior:

  • When increment is called, the counter's value should increase.
  • When decrement is called, the counter's value should decrease.
  • When reset is called, the counter's value should become 0.
  • Tests should not interfere with each other. For example, a test that increments the counter should not affect the starting value of the next test.

Edge cases to consider:

  • Decrementing the counter when its value is already 0. The behavior should be to simply remain at 0.

Examples

Let's assume we have a Counter class defined as follows (you will need to implement this):

class Counter {
  private value: number = 0;

  increment(): void {
    this.value++;
  }

  decrement(): void {
    if (this.value > 0) {
      this.value--;
    }
  }

  reset(): void {
    this.value = 0;
  }

  getValue(): number {
    return this.value;
  }
}

Test Scenario 1: Initial Value

Test Code Snippet:

// Assuming Counter class is imported and beforeEach is set up
describe('Counter', () => {
  let counter: Counter; // Declare counter here

  beforeEach(() => {
    counter = new Counter(); // Instantiate in beforeEach
  });

  test('should initialize with a value of 0', () => {
    expect(counter.getValue()).toBe(0);
  });
});

Explanation: The beforeEach hook creates a new Counter instance, setting its initial value to 0. The test then asserts that getValue() returns 0.

Test Scenario 2: Incrementing

Test Code Snippet:

// Assuming Counter class is imported and beforeEach is set up
describe('Counter', () => {
  let counter: Counter;

  beforeEach(() => {
    counter = new Counter();
  });

  test('should increment the value', () => {
    counter.increment();
    expect(counter.getValue()).toBe(1);
  });

  test('should increment the value multiple times', () => {
    counter.increment();
    counter.increment();
    expect(counter.getValue()).toBe(2);
  });
});

Explanation: Each test block in this describe block will have a fresh Counter instance due to beforeEach. The tests verify that calling increment correctly updates the value.

Test Scenario 3: Decrementing and Resetting

Test Code Snippet:

// Assuming Counter class is imported and beforeEach is set up
describe('Counter', () => {
  let counter: Counter;

  beforeEach(() => {
    counter = new Counter();
  });

  test('should decrement the value', () => {
    counter.increment(); // Start with 1
    counter.decrement();
    expect(counter.getValue()).toBe(0);
  });

  test('should not decrement below zero', () => {
    counter.decrement(); // Start with 0
    expect(counter.getValue()).toBe(0);
  });

  test('should reset the value to 0', () => {
    counter.increment();
    counter.increment();
    counter.reset();
    expect(counter.getValue()).toBe(0);
  });
});

Explanation: These tests demonstrate decrementing behavior, including the edge case of decrementing from zero, and the functionality of the reset method. Crucially, beforeEach ensures that each of these operations starts with a fresh counter.

Constraints

  • Your solution should be written in TypeScript.
  • You must use Jest as the testing framework.
  • You must implement the beforeEach hook to manage the Counter instance.
  • The Counter class should be a simple, non-async class.

Notes

  • The goal is to demonstrate your understanding of how beforeEach helps maintain test isolation and reduces setup boilerplate.
  • Think about how you would declare the variable that will hold your Counter instance within the describe block.
  • The beforeEach hook can be used for more complex setup tasks than just instantiation, such as mocking dependencies or setting up API stubs. This challenge focuses on the fundamental use case.
Loading editor...
typescript