Home > Enterprise >  React mock asynchronous axios with jest doesn't work
React mock asynchronous axios with jest doesn't work

Time:06-18

I'm trying to test the component below using mock axios, however, it looks like the components are not rendered as expected, could someone help me on that? I have been stuck for quite a while. The component is fetching an api every 1 second.

const RealtimePrice = () => {
  var [cryptoFeed, setCryptoFeed] = useState<cryptoFeed>([]);
  var [currency, setCurrency] = useState(currencyList[0]);
  var [cryptoSearch, setCryptoSearch] = useState("");

  const url = `https://api.coingecko.com/api/v3/coins/markets?ids=${ids}&vs_currency=${currency}`;
  const intervalRef = useRef<NodeJS.Timer>();

  const onCurrencyChangeHandler = useCallback((newValue: string) => {
    setCurrency(newValue);
  }, []);

  const onCryptoSearchChangeHandler = useCallback((newValue: string) => {
    setCryptoSearch(newValue);
  }, []);

  useEffect(() => {
    const getCryptoFeed = () => {
      axios.get(url).then((response: any) => {
        if (response.data) {
          console.debug("The state is set");
          setCryptoFeed(response.data);
        } else {
          console.debug("The state is not set");
          setCryptoFeed([]);
        }
      });
    };

    getCryptoFeed();
    intervalRef.current = setInterval(getCryptoFeed, 1000);
    return () => {
      clearInterval(intervalRef.current);
    };
  }, [url]);

  const priceBlocks = cryptoFeed
    .filter((crypto) =>
      crypto.name.toLowerCase().includes(cryptoSearch.toLowerCase())
    )
    .map((crypto: any) => {
      return (
        <PriceBlock
          key={crypto.id}
          id={crypto.id}
          name={crypto.name}
          price={crypto.current_price}
          volume={crypto.total_volume}
          change={crypto.price_change_24h}
        ></PriceBlock>
      );
    });

  return (
    <div className={styles.container}>
      <div className={styles["header-section"]}>
        <h1>Cryptocurrency Realtime Price</h1>
        <div className="input-group">
          <Selectbox
            onChange={onCurrencyChangeHandler}
            defaultOption={currencyList[0]}
            options={currencyList}
          />
          <Inputbox
            placeHolder="Enter crypto name"
            onChange={onCryptoSearchChangeHandler}
          />
        </div>
      </div>
      <div className={styles.priceblocks}>{priceBlocks}</div>
    </div>
  );
};

The test is the defined as the following, findByText gives error, it couldn't find the element.

import { render, screen } from "@testing-library/react";
import RealtimePrice from "../RealtimePrice";

describe("Realtime Price", () => {
  it("should render the Bitcoin price block", async () => {
    render(<RealtimePrice />);
    const pb = await screen.findByText("Bitcoin");
    expect(pb).toBeInTheDocument();
  });
});

And in package.json I have set

  "jest": {
    "collectCoverageFrom": [
      "src/**/*.{js,jsx,ts,tsx}"
    ],
    "resetMocks": false
  }

In src/mocks/axios.js

const mockGetResponse = [
  {
    id: "bitcoin",
    name: "Bitcoin",
    price: 20000,
    volume: 12004041094,
    change: -12241,
  },
  {
    id: "solana",
    name: "Solana",
    price: 87,
    volume: 200876648,
    change: 122,
  },
];

const mockResponse = {
  get: jest.fn().mockResolvedValue(mockGetResponse),
};

export default mockResponse;

enter image description here

enter image description here

CodePudding user response:

With our comments seems clear the issue is that mock is not returning a proper response.data (that's why u are setting an empty array as the state)

Try doing:

const mockResponse = {
  get: jest.fn().mockResolvedValue({data: mockGetResponse}),
};
  • Related