在 Jest (React-Redux) 中测试 SVG 元素

Testing for SVG element in Jest (React-Redux)

我有一个为 Reddit 应用程序定义的 User 组件,如下所示:

// User.js

import React from "react";
import { useSelector } from "react-redux";
import { selectUsername, selectAuthState } from "./userSlice";
import Reddit from "../../api/Reddit";

const User = () => {
    const userID = useSelector(selectUsername);
    const authState = useSelector(selectAuthState);
    const { isLoading } = useSelector(state => state.user)

    const handleAuth = (e) => {
        e.preventDefault();
        Reddit.getAccessToken();
    }

    if (isLoading) {
        return (
            <svg className="spinner" viewBox="0 0 50 50">
              <circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"></circle>
            </svg>
        )
    } else if (authState) {
        return (
            <a id="reddit-username" target="_blank" rel="noreferrer" href={`https://www.reddit.com/user/${userID}`} aria-label="Current user ID">{userID}</a>
        )
    } else {
        return (
            <a id="reddit-username" href="/" onClick={handleAuth} aria-label="Connect the web app with your Reddit account">Link with Reddit</a>
        )
    }
}

export default User;

到目前为止,组件的测试文件布局如下:

// User.spec.js

import React from 'react';
import { render } from '@testing-library/react';
import { Provider } from 'react-redux';
import { store } from '../../app/store';
import User from "../../features/User/User";

test("renders 'Link with Reddit' link by default", () => {
  const { getByText } = render( 
    <Provider store={store}>
      <User />
    </Provider>
  );

  expect(getByText("Link with Reddit")).toBeInTheDocument();
});

我正在尝试编写用于在组件 isLoading 时呈现 SVG 元素的测试,但我不知道如何进行,因为我对 React-Redux 中的测试还很陌生。我应该如何完成它?

您可以为每个具有不同状态的测试用例提供 redux 存储。这样选择器将 return 状态切片具有不同的值。这允许您测试使用这些变量的不同代码分支。

例如

User.jsx:

import React from 'react';
import { useSelector } from 'react-redux';

const selectUsername = (state) => state.user.name;
const selectAuthState = (state) => state.auth;

export const User = () => {
  const userID = useSelector(selectUsername);
  const authState = useSelector(selectAuthState);
  const { isLoading } = useSelector((state) => state.user);

  const handleAuth = (e) => {
    e.preventDefault();
  };

  if (isLoading) {
    return (
      <svg className="spinner" viewBox="0 0 50 50">
        <circle className="path" cx="25" cy="25" r="20" fill="none" strokeWidth="5"></circle>
      </svg>
    );
  } else if (authState) {
    return (
      <a
        id="reddit-username"
        target="_blank"
        rel="noreferrer"
        href={`https://www.reddit.com/user/${userID}`}
        aria-label="Current user ID"
      >
        {userID}
      </a>
    );
  } else {
    return (
      <a id="reddit-username" href="/" onClick={handleAuth} aria-label="Connect the web app with your Reddit account">
        Link with Reddit
      </a>
    );
  }
};

User.test.jsx:

import { User } from './User';
import React from 'react';
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { Provider } from 'react-redux';
import { combineReducers, createStore } from 'redux';

function renderUI(reducers) {
  const rootReducer = combineReducers(reducers);
  const store = createStore(rootReducer);
  return render(
    <Provider store={store}>
      <User />
    </Provider>
  );
}

describe('70249367', () => {
  test('should render spinner', () => {
    const { container } = renderUI({
      user: (state = { name: '', isLoading: true }) => {
        return state;
      },
    });
    expect(container.querySelector('.spinner')).toBeInTheDocument();
  });

  test("renders 'Link with Reddit' link by default", () => {
    const { getByText } = renderUI({
      user: (state = { name: '', isLoading: false }) => {
        return state;
      },
    });
    expect(getByText('Link with Reddit')).toBeInTheDocument();
  });

  test('should render username', () => {
    const { getByText } = renderUI({
      user: (state = { name: 'teresa teng', isLoading: false }) => {
        return state;
      },
      auth: (state = {}) => state,
    });
    expect(getByText('teresa teng')).toBeInTheDocument();
  });
});

测试结果:

 PASS  examples/70249367/User.test.jsx (8.809 s)
  70249367
    ✓ should render spinner (27 ms)
    ✓ renders 'Link with Reddit' link by default (7 ms)
    ✓ should render username (3 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   94.74 |      100 |      80 |   93.33 |                   
 User.jsx |   94.74 |      100 |      80 |   93.33 | 13                
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        9.405 s

包版本:

"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.2.2",
"jest": "^26.6.3",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-redux": "^7.2.2",
"redux": "^4.1.0",