0

I have a following simple test for dummy Counter component:

describe("Counter", () => {
  it("initially displays 0", () => {
    render(<Counter />);
    expect(screen.getByText("Counter value is 0")).toBeInTheDocument();
  });

  it("displays the given initial value", () => {
    render(<Counter initialValue={10} />);
    expect(screen.getByText("Counter value is 10")).toBeInTheDocument();
  });

  it("has a button for incrementing the value", () => {
    render(<Counter />);
    userEvent.click(screen.getByRole("button", { name: "+1" }));
    expect(screen.getByText("Counter value is 1")).toBeInTheDocument();
  });

  describe("when the maxValue is given", () => {
    it("does not allow to increment the value above the given maximum", () => {
      render(<Counter initialValue={9} maxValue={10} />);
      userEvent.click(screen.getByRole("button", { name: "+1" }));
      expect(screen.getByText("Counter value is 10")).toBeInTheDocument();
      expect(screen.getByRole("button", { name: "+1" })).toBeDisabled();
    });
  });

  it("has a button for decrementing the value", () => {
    render(<Counter initialValue={2} />);
    userEvent.click(screen.getByRole("button", { name: "-1" }));
    expect(screen.getByText("Counter value is 1")).toBeInTheDocument();
  });

  it("does not allow to decrement the value below zero", () => {
    render(<Counter initialValue={0} />);
    expect(screen.getByRole("button", { name: "-1" })).toBeDisabled();

    userEvent.click(screen.getByRole("button", { name: "-1" }));
    expect(screen.getByText("Counter value is 0")).toBeInTheDocument();
  });

  it("has a button for resetting the value", () => {
    render(<Counter initialValue={2} />);
    userEvent.click(screen.getByRole("button", { name: "reset" }));
    expect(screen.getByText("Counter value is 0")).toBeInTheDocument();
  });
});

Is it a good practice to dry-up it with some handy helpers, like:

describe("<Counter /> component", () => {
  const getIncrementButton = () => screen.getByRole("button", { name: "+1" });

  const getDecrementButton = () => screen.getByRole("button", { name: "-1" });

  it("has a button for incrementing the value", () => {
    render(<Counter />);
    userEvent.click(getIncrementButton());
    expect(getValue()).toHaveTextContent("Counter value is 1");
  });

});

I did some research and I couldn't find any decent resources about such approach.

luacassus
  • 6,540
  • 2
  • 40
  • 58
  • Normally I'd say making your code more DRY is a good thing, but I think a caveat to this is it's probably not useful when you are only exchanging one line of code for another, you are still repeating yourself when getting *some* button/element to make assertions on. I don't see much that *can* be DRY'd up in your tests. – Drew Reese May 21 '20 at 15:05
  • I generally would agree with that, but if decided to change the button label, a lot of test will start to failing and I will have to change the label in several places in the test. Also I found that such helpers could help to avoid some annoying typos in the tests. – luacassus May 21 '20 at 15:09
  • Yeah, no disagreement there. What you describe is akin to creating a shallow/mount utility function that injects props into a component under test, a very common pattern. IMO anything that helps make maintaining your code easier is a positive. – Drew Reese May 21 '20 at 15:28

0 Answers0