Jest.js 如何使用axios API调用测试react应用?

tkclm6bt  于 2023-05-11  发布在  Jest
关注(0)|答案(1)|浏览(178)

我正在尝试测试一个组件,它可以渲染使用axios从unpsplash API获取的图像。然而,测试一直失败,但应用程序正在工作。
测试抛出的错误是:元素应有属性:src=”https://via.placeholder.com/300x300.png?text=robin“已收到:src=”https://via.placeholder.com/200x300/86efac?text=Loading...”
我想这一定意味着我没有正确地模拟axios请求,或者这与延迟加载有关?
我的测试:

import { screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../utils/utils-for-tests";
import axios from "axios";
import BirdImg from "../components/BirdImg";

class IntersectionObserver {
  observe() {
    return null;
  }

  disconnect() {
    return null;
  }
}

window.IntersectionObserver = IntersectionObserver;

jest.mock("axios", () => ({
  get: jest.fn(),
}));

const mockLoadedResponse = {
  data: {
    results: [
      {
        urls: {
          thumb: "https://via.placeholder.com/300x300.png?text=robin",
        },
      },
    ],
  },
};
test("shows the image", async () => {
  axios.get.mockResolvedValue(mockLoadedResponse);

  renderWithProviders(<BirdImg name="robin" />);
  const birdImage = await screen.findByRole("img");

  await waitFor(() => {
    expect(birdImage).toBeInTheDocument();
    expect(birdImage).toHaveAttribute(
      "src",
      "https://via.placeholder.com/300x300.png?text=robin"
    );
  });
});

我想测试的组件:

import { useEffect, useRef, useState } from "react";
import { fetchBirdImg } from "../api/unsplash";

function BirdImg({ name }) {
  const imgRef = useRef(null);
  const [loaded, setLoaded] = useState(false);
  const [error, setError] = useState(false);

  useEffect(() => {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          fetchBirdImg(name).then((data) => {
            imgRef.current.src = data[0].urls.thumb;
            setLoaded(true);
          });

          observer.unobserve(imgRef.current);
        }
      });
    });

    observer.observe(imgRef.current);

    return () => observer.disconnect();
  }, [name]);

  let imgSrc;

  if (loaded === false) {
    imgSrc = `https://via.placeholder.com/200x300/86efac?text=Loading...`;
  }
  if (loaded) {
    imgSrc = imgRef.current.src;
  }
  if (error === true) {
    imgSrc = `https://via.placeholder.com/200x300/86efac?text=Error`;
  }

  return (
    <img
      ref={imgRef}
      onLoad={() => {
        setLoaded(true);
      }}
      onError={() => {
        setError(true);
      }}
      src={imgSrc}
      alt={name}
      className="w-20"
    />
  );
}

export default BirdImg;
The api call:

import axios from "axios";

async function fetchBirdImg(name) {
  const response = await axios.get(
    "https://api.unsplash.com/search/photos?per_page=1&orientation=portrait",

    {
      headers: {
        Authorization: "auth key",
      },
      params: { query: `${name}` },
    }
  );
  return response.data.results;
}

export { fetchBirdImg };
yfjy0ee7

yfjy0ee71#

您还应该模拟IntersectionObserver()构造函数和unobserve()方法
您可以简单地模拟fetchBirdImg API函数,而不是axios
例如:
目录结构:

⚡  tree -L 2 -I 'node_modules'
.
├── BirdImg.jsx
├── BirdImg.test.jsx
└── api.js

BirdImg.test.jsx

import React from 'react';
import { screen, waitFor, render } from '@testing-library/react';
import '@testing-library/jest-dom';
import BirdImg from './BirdImg';
import { fetchBirdImg } from './api';

jest.mock('./api');

const mockLoadedResponse = [{ urls: { thumb: 'https://via.placeholder.com/300x300.png?text=robin' } }];
test('shows the image', async () => {
  let _callback;
  const intersectionObserverEntries = [{ isIntersecting: true }];
  class IntersectionObserver {
    constructor(callback) {
      _callback = callback;
    }
    observe() {
      return null;
    }
    unobserve() {
      return null;
    }
    disconnect() {
      return null;
    }
  }

  fetchBirdImg.mockResolvedValueOnce(mockLoadedResponse);
  window.IntersectionObserver = IntersectionObserver;

  render(<BirdImg name="robin" />);
  const birdImage = screen.getByRole('img');
  expect(birdImage).toHaveAttribute('src', 'https://via.placeholder.com/200x300/86efac?text=Loading...');
  _callback(intersectionObserverEntries);
  await waitFor(() => {
    expect(birdImage).toBeInTheDocument();
    expect(birdImage).toHaveAttribute('src', 'https://via.placeholder.com/300x300.png?text=robin');
  });
});

我们声明了一个_callback变量来保存真实的的回调函数,并在示例化IntersectionObserver类之后用模拟的intersectionObserverEntries对象手动调用它。
测试结果:

PASS  stackoverflow/76189869/BirdImg.test.jsx (20.943 s)
  ✓ shows the image (89 ms)

-------------|---------|----------|---------|---------|-------------------
File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------|---------|----------|---------|---------|-------------------
All files    |   83.87 |       75 |   66.67 |   86.21 |                   
 BirdImg.jsx |   88.89 |       75 |      75 |      92 | 34,38             
 api.js      |      50 |      100 |       0 |      50 | 4-13              
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        22.404 s
Ran all test suites related to changed files.

相关问题