Stephen Fong
Stephen Fong

Reputation: 827

React mock asynchronous axios with jest doesn't work

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

Upvotes: 2

Views: 1084

Answers (1)

Toni Bardina Comas
Toni Bardina Comas

Reputation: 1798

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}),
};

Upvotes: 2

Related Questions