fief-dev / fief-js

Fief client for JavaScript
https://docs.fief.dev/integrate/javascript/
MIT License
8 stars 2 forks source link

React Testing Library: ReferenceError: TextEncoder is not defined #4

Closed michaldev closed 1 year ago

michaldev commented 1 year ago

I have a problem with testing widget which use "useFiefTokenInfo" in react. I use "react testing library".

image

Additional info:

"@testing-library/react": "^13.4.0",
"react": "^18.2.0",

and default config from your docs.

Test (just render view):

test("renders component", async () => {
  const { getByLabelText } = render(<Settings />);
  screen!.debug();
});
frankie567 commented 1 year ago

The problem is that Jest runs with a Node environment, but the library tries to use browser's API. The solution is to monkey patch them with their Node equivalent. Actually, we do this here:

https://github.com/fief-dev/fief-js/blob/e3ccbf67012ee4a424dc383445ed0bcf9cce8469/src/browser.test.ts#L1-L23

That said, it would be probably easier for you during unit tests to completely mock useFiefTokenInfo, so you can simulate any value you need without having to care about the implementation details:

const mockUseFiefTokenInfo = jest.fn();
jest.mock('@fief/fief/react', () => {
    return jest.fn(() => ({
       useFiefTokenInfo: mockUseFiefTokenInfo
    }))
})
michaldev commented 1 year ago

I've already tried mock from the beginning, but I get the same error (if I try beforeAll) or this: TypeError: (0 , _react2.useFiefTokenInfo) is not a function

Full Test Code:

import { render, screen } from "@testing-library/react";
import React from "react";
import Settings from "../pages/settings";

const mockUseFiefTokenInfo = jest.fn(() => {
  return { access_token: "test" };
});

jest.mock("@fief/fief/react", () => {
  return jest.fn(() => ({
    useFiefTokenInfo: mockUseFiefTokenInfo,
  }));
});

it("renders without crashing", () => {
  render(<Settings />);
  // expect(screen.getByText("Settings")).toBeInTheDocument();
});
frankie567 commented 1 year ago

Jest is really contrived sometimes 😕 Here is what I came up with, seems to work:

/**
 * @jest-environment jsdom
 */
import { render, screen } from '@testing-library/react';
import React from 'react';
import { useFiefTokenInfo } from '@fief/fief/react';

const Settings: React.FC = () => {
  const tokenInfo = useFiefTokenInfo();
  return (
    <div>{tokenInfo?.access_token}</div>
  );
};

jest.mock('@fief/fief/react', () => ({
  useFiefTokenInfo: jest.fn().mockReturnValue({ access_token: 'MOCK_ACCESS_TOKEN' }),
}));

it('renders without crashing', () => {
  render(<Settings />);
  expect(screen.getByText('MOCK_ACCESS_TOKEN')).toBeTruthy();
  expect(useFiefTokenInfo).toHaveBeenCalled();
});
michaldev commented 1 year ago

Thank you, works :+1: