Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write test with swr

when user type some text in input search data-testid = 'loading' must be removed, now console return Unable to find an element by: [data-testid="loading"] can some one sugesstion me to writting test with swr or suggestion for me how to mock response from swr

this is my component file

import axios from "axios";
import { useEffect, useState } from "react";
import useSWR from "swr";
import "./styles.css";

const useDebounce = (newValue) => {
  const [value, setValue] = useState("");
  useEffect(() => {
    const timeout = setTimeout(() => {
      setValue(newValue);
    }, 500);
    return () => clearTimeout(timeout);
  }, [newValue]);
  return value;
};

export const fetcher = async (url) => {
  const { data } = await axios.get(url);
  return data;
};
export default function App() {
  const [query, setQuery] = useState("react");
  const searchQuery = useDebounce(query);
  const { data: repos } = useSWR(
    `https://api.github.com/search/repositories?q=${searchQuery}&per_page=1&page=1`,
    fetcher
  );
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <input
        testId="search"
        data-testid="search"
        id="search-input"
        placeholder="search"
        onChange={(event) => setQuery(event.target.value)}
      />
      {!repos ? (
        <div data-testid="loader" testId="loader">
          <h2 id="loading">loading</h2>
        </div>
      ) : (
        repos?.items?.map((user) => {
          return (
            <div
              data-testid="repo-item"
              style={{
                margin: "1rem",
                height: "40px",
                background: "lightpink"
              }}
            >
              {user.name}
            </div>
          );
        })
      )}
    </div>
  );
}

this is my test file

import {
  render,
  screen,
  waitForElementToBeRemoved
} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import App from "./App";
import { act } from "react-dom/test-utils";

describe("test", () => {
  beforeEach(() => {
    jest.resetAllMocks();
    jest.useFakeTimers();
  });
  it("happy render", () => {
    expect(() => render(<App />)).not.toThrow();
  });

  it("renders after search", async () => {
    render(<App />);
    userEvent.type(screen.getByTestId("search"), "vue");
    act(() => {
      jest.runAllTimers();
    });
    await waitForElementToBeRemoved(() => screen.getByTestId("loader"));
  });
});
like image 453
Miin Miinny Avatar asked Nov 15 '22 20:11

Miin Miinny


1 Answers

You can mock axios.get() method and its resolved/rejected value rather than mocking useSWR hook. Then, test the behaviour of the component such as what was rendered when data was returned, and what was rendered when no data was available.

E.g.

App.tsx:

import axios from 'axios';
import React from 'react';
import { useEffect, useState } from 'react';
import useSWR from 'swr';

const useDebounce = (newValue) => {
  const [value, setValue] = useState('');
  useEffect(() => {
    const timeout = setTimeout(() => {
      setValue(newValue);
    }, 500);
    return () => clearTimeout(timeout);
  }, [newValue]);
  return value;
};

export const fetcher = async (url) => {
  const { data } = await axios.get(url);
  return data;
};

export default function App() {
  const [query, setQuery] = useState('react');
  const searchQuery = useDebounce(query);
  const { data: repos } = useSWR(
    `https://api.github.com/search/repositories?q=${searchQuery}&per_page=1&page=1`,
    fetcher
  );
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <input
        data-testid="search"
        id="search-input"
        placeholder="search"
        onChange={(event) => setQuery(event.target.value)}
      />
      {!repos ? (
        <div data-testid="loader">
          <h2 id="loading">loading</h2>
        </div>
      ) : (
        repos?.items?.map((user) => {
          console.log('user: ', user);
          return (
            <div key={user.id} data-testid="repo-item">
              {user.name}
            </div>
          );
        })
      )}
    </div>
  );
}

App.test.tsx:

import React from 'react';
import { render, screen, waitForElementToBeRemoved } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import App from './App';
import { act } from 'react-dom/test-utils';
import axios from 'axios';

describe('test', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    jest.useFakeTimers();
  });
  it('happy render', () => {
    expect(() => render(<App />)).not.toThrow();
  });

  it('renders after search', async () => {
    jest.spyOn(axios, 'get').mockResolvedValueOnce({
      data: {
        items: [
          { id: 1, name: 'react' },
          { id: 2, name: 'jestjs' },
        ],
      },
    });
    render(<App />);
    userEvent.type(screen.getByTestId('search'), 'vue');
    act(() => {
      jest.runAllTimers();
    });
    await waitForElementToBeRemoved(() => screen.getByTestId('loader'));
  });
});

test result:

 PASS  examples/67958776/App.test.tsx (8.166 s)
  test
    ✓ happy render (42 ms)
    ✓ renders after search (58 ms)

  console.log
    user:  { id: 1, name: 'react' }

      at examples/67958776/App.tsx:45:19
          at Array.map (<anonymous>)

  console.log
    user:  { id: 2, name: 'jestjs' }

      at examples/67958776/App.tsx:45:19
          at Array.map (<anonymous>)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |       80 |     100 |     100 |                   
 App.tsx  |     100 |       80 |     100 |     100 | 44                
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        8.873 s
like image 91
slideshowp2 Avatar answered Dec 09 '22 17:12

slideshowp2