Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Component Testing]: How to test a custom hook using useReactToPrint #665

Open
alamenai opened this issue Nov 20, 2023 · 12 comments
Open

[Component Testing]: How to test a custom hook using useReactToPrint #665

alamenai opened this issue Nov 20, 2023 · 12 comments
Labels

Comments

@alamenai
Copy link

Hi @gregnb ,

This could be a discussion rather than an issue.

I created a custom hook called usePrint and inside it, I used useReactToPrint hook. I want to create a test with Jest and Testing Library. However, I failed to find the way to make sure that the print is called properly.

My goal is to make sure the PDF preview will be opened when the print function is called.

  1. usePrint hook
import { useRef } from "react"
import { useReactToPrint } from "react-to-print"

export const usePrint = <T extends HTMLElement>() => {
  const componentRef = useRef<T>(null)

  const print = useReactToPrint({
    content: () => componentRef.current,
    pageStyle: "padding-inline: 2px",
    fonts: [
      {
        family: "Inter",
        source: "https://fonts.googleapis.com/css2?family=Inter&display=swap",
      },
    ],
  })

  return { print, componentRef }
}
  1. usePrint.spec.tsx
import { expect, jest } from "@jest/globals"
import { act, render, renderHook } from "@testing-library/react"
import { useReactToPrint } from "react-to-print"

import { usePrint } from "./usePrint"

jest.mock("react-to-print", () => ({
  useReactToPrint: jest.fn(),
}))

test("should the reference be null", () => {
  const { result } = renderHook(() => usePrint<HTMLDivElement>())
  expect(result.current.componentRef.current).toBeNull()
})

test("should inject useReactToPrint hook when call print", () => {
  const { result } = renderHook(() => usePrint<HTMLDivElement>())

  const { componentRef, print } = result.current
 
 // I want to make use that the `useReactToPrint` is called properly

// Also, I want to make sure that the PDF Preview is opened

  act(() => print())

  // This assertion fails
  expect(useReactToPrint).toHaveBeenCalled()
})

Thank you.

@MatthewHerbst
Copy link
Owner

The way I would do this: mock useReactToPrint such that it returns a jest.fn(). Then just check that it is called

@alamenai
Copy link
Author

Thank you @MatthewHerbst for your reply, could you please add more hints or examples? I tried to resolve the issue today, but I failed to pass the tests.

@MatthewHerbst
Copy link
Owner

MatthewHerbst commented Dec 18, 2023

Hello, apologies for the very delayed response. Did you manage to solve this? I believe it's just a question of rendering/mocking the things correctly

@alamenai
Copy link
Author

No, I told the team that I could not add the test but it works well without issues.

@MatthewHerbst
Copy link
Owner

So, I think you want something like the below. This is the pattern we use at my company for testing hooks. I haven't tried running this test with react-to-print but something like this is what you're looking for I believe. I should note that we use vitest instead of Jest but I think the pattern is the same. I realize this is very similar to what you have above, but maybe there's a small difference? We don't really use ack for example

import { act, renderHook } from "@testing-library/react-hooks";

import { usePrint } from "./usePrint"

jest.mock("react-to-print", () => ({
  useReactToPrint: jest.fn(),
}));

describe("usePrint", () => {
  test("calls `react-to-print` correctly", () => {
    const { result } = renderHook(() => usePrint());

    expect(useReactToPrint).toHaveBeenCalled();

    // If you also want to test that `react-to-print` properly calls `window.print` then you would need
    // to not use a mock version since `jest.fn()` doesn't call `window.print`. I would personally argue
    // that you shouldn't be testing 3rd party code though, so there's no reason for such a test
  });
});

I've been meaning to add proper unit tests to this library for a long time. Might try and get around to that over the holidays. PRs always accepted 😄

@charlieforward9
Copy link

I just spent a long time trying to figure out how to mock window.print with no luck. I am trying to test that my app properly displays the content modified within onBeforeGetContent and onAfterPrint, which I believe would be mocked away if I called:

vi.mock("react-to-print", () => ({
  useReactToPrint: jest.fn(),
}));

having unit tests in this library would be extremely helpful for reference.

@MatthewHerbst
Copy link
Owner

I just spent a long time trying to figure out how to mock window.print with no luck. I am trying to test that my app properly displays the content modified within onBeforeGetContent and onAfterPrint

I would generally advise against trying to mock and test 3rd party code. You should be testing that you pass the right props to useReactToPrint, not the react-to-print implementation details.

You could also put unit tests on your beforeGetContent and onAfterPrint functions by using a fake testing component: react-to-print doesn't pass these methods anything special, so you should be able to unit test your implementations without even calling useReactToPrint.

having unit tests in this library would be extremely helpful for reference

PR contributions are always welcome! 🙏😅

@charlieforward9
Copy link

I have been adopting Behavior Driven Development where the useReactToPrint hook call is a step in the greater 'behavior' of the user.

Do you have a recommendation for how I should be doing this?

PR contributions are always welcome! 🙏😅

At the time, I am far too overemployed to dedicate time to study/contribute to the hundreds of open source solutions I use. However, I am willing to offer a humble amount of financial support to sponsorable maintainers to encourage more contributions! Thank you very much for developing this functionality.

@MatthewHerbst
Copy link
Owner

MatthewHerbst commented May 6, 2024

Ha, appreciate that, but totally unnecessary right now, very much in the same boat 😄 With the upcoming changes in React 19 I'm debating making this entire library just a function, no hook/component needed since we don't actually hold onto any of your application state anyways. Should make testing 1000% simpler. Will keep you updated, I hope to do some work on that this coming week/weekend.

@alamenai
Copy link
Author

alamenai commented May 6, 2024

Hi @MatthewHerbst , thank you for your efforts. Do you have any future milestone in the future to add download feature in react-2-print. Also, I would sponsor you but it seems you did not activate the sponsorship feature for this library.

@MatthewHerbst
Copy link
Owner

Hey, apologies for the delayed response here, have been out-of-town.

Download gets tricky because it would likely require adding some sort of PDF generation library and those can be pretty heavy, especially when most users of react-to-print don't need it. I'd rather focus on adding better docs with a recommended solution (maybe an example in the code base) for how to do this, than to bake it right it. Happy to keep chatting about this and exploring it

Appreciate the sponsorship offers from you both. I'll think about what that might entail.

@MatthewHerbst
Copy link
Owner

MatthewHerbst commented Jul 16, 2024

Hey folks. I released v3.0.0-beta-1 yesterday which adds support for React 19 and modernizes the API. This should also make adding testing much simpler as the code has been mostly broken up into a bunch of pure util functions. I'll look at adding tests once I get v3.0.0 published. Also trying to get dual CJS+ESM publishing working but that's become a huge PITA, will likely save that for a v4

I did also add that sponsorship button 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants