Jest, Enzyme: Invariant Violation: Вы не должны использовать <Route>или withRouter () вне <Router> - PullRequest
0 голосов
/ 25 апреля 2018

У меня есть <UserListComponent />, который выводит один компонент <Contact /> и список контактов, представленных <Contacts />.

Проблема в том, что в тесте для <UserListComponent />, когда я пытаюсь его смонтировать, тест выдает ошибку Invariant Violation: You should not use <Route> or withRouter() outside a <Router>

withRouter(), используемую в компоненте <Contacts />.

Как можно смоделировать ContactsComponent без маршрутизатора при тестировании родительского компонента?

Я обнаружил похожую проблему https://www.bountysource.com/issues/49297944-invariant-violation-you-should-not-use-route-or-withrouter-outside-a-router, но она описывает только ситуацию, когда компонент покрывается самим withRouter(), не дети.

UserList.test.jsx

const mockResp = {
  count: 2,
  items: [
    {
      _id: 1,
      name: 'User1',
      email: 'email1@gmail.com',
      phone: '+123456',
      online: false
    },
    {
      _id: 2,
      name: 'User2',
      email: 'email2@gmail.com',
      phone: '+789123',
      online: false
    },
    {
      _id: 3,
      name: 'User3',
      email: 'email3@gmail.com',
      phone: '+258369147',
      online: false
    }
  ],
  next: null
}

describe('UserList', () => {
  beforeEach(() => {
    fetch.resetMocks()
  });

  test('should output list of users', () => {
    fetch.mockResponseOnce(JSON.stringify(mockResp));

    const wrapper = mount(<UserListComponent user={mockResp.items[2]} />);

    expect(wrapper.find('.contact_small')).to.have.length(3);
  });

})

UserList.jsx

export class UserListComponent extends PureComponent {
  render() {
    const { users, error } = this.state;
    return (
      <React.Fragment>
        <Contact
          userName={this.props.user.name}
          content={this.props.user.phone}
        />
        {error ? <p>{error.message}</p> : <Contacts type="contactList" user={this.props.user} contacts={users} />}
      </React.Fragment>
    );
  }
}

Contacts.jsx

class ContactsComponent extends Component {
  constructor() {
    super();
    this.state = {
      error: null,
    };
  }

  render() {
    return (
      <React.Fragment>
        <SectionTitle title="Contacts" />
        <div className="contacts">
         //contacts
        </div>
      </React.Fragment>
    );
  }
}

export const Contacts = withRouter(ContactsComponent);

Ответы [ 5 ]

0 голосов
/ 04 августа 2019

A хранит историю вашего «URL» в памяти (не читает и не пишет в адресную строку). Полезно в тестах и ​​не браузерных средах, таких как React Native.

У меня есть похожая ошибка, решение оборачивает компонент с помощью Маршрутизатор памяти

import { MemoryRouter } from 'react-router'

<MemoryRouter>
  <App/>
</MemoryRouter>
0 голосов
/ 05 апреля 2019

У меня была такая же проблема, и первый комментарий помог мне, но есть много кода, у меня есть лучший способ, как решить эту проблему.Смотрите мое решение ниже:

    import React from 'react';
import { shallow, mount } from 'enzyme';
import SisuSignIn from '../../../components/Sisu/SisuSignIn.js';
import { MemoryRouter } from 'react-router-dom';

const Container = SisuSignIn;

let wrapper;

beforeEach(() => {
  wrapper = shallow(<Container />);
});

describe('SisuSignIn', () => {
  it('renders correctly', () => {
    expect(wrapper).toMatchSnapshot();
  });
  it('should render one <h1>', () => {
    const wrapper = mount(
      <MemoryRouter>
        <SisuSignIn auth={{ loading: false }} />
      </MemoryRouter>
    );
    expect(wrapper.find('div').length).toBe(12);
  });
});
0 голосов
/ 25 мая 2018

Чтобы протестировать компонент (с Jest), который содержит <Route> и withRouter, вам необходимо импортировать маршрутизатор в тест, а не в ваш компонент

import { BrowserRouter as Router } from 'react-router-dom';

и использовать его следующим образом

app = shallow(
    <Router>
        <App />
    </Router>);
0 голосов
/ 10 октября 2018

Вам нужно обернуть App BrowserRouter или его эквивалентом, см. ниже пример простого тестового примера компонента приложения, использующего React Router

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";

it("renders without crashing", () => {
  const div = document.createElement("div");
  ReactDOM.render(
<BrowserRouter>
  <App />
</BrowserRouter>,
div
  );
  ReactDOM.unmountComponentAtNode(div);
})
0 голосов
/ 20 мая 2018

Функция утилиты для переноса монтирования в контекст

Обертывание монтирования с Router в тестах работает, но есть ситуации, когда вы не хотите, чтобы Router был родительским компонентом в вашем монтировании. Поэтому в настоящее время я внедряю контекст в монтирование с помощью функции-оболочки:

import { BrowserRouter } from 'react-router-dom';
import Enzyme, { shallow, mount } from 'enzyme';

import { shape } from 'prop-types';

// Instantiate router context
const router = {
  history: new BrowserRouter().history,
  route: {
    location: {},
    match: {},
  },
};

const createContext = () => ({
  context: { router },
  childContextTypes: { router: shape({}) },
});

export function mountWrap(node) {
  return mount(node, createContext());
}

export function shallowWrap(node) {
  return shallow(node, createContext());
}

Это может быть файл, называемый contextWrap.js, в каталоге помощников по тестированию.

Пример описания блока:

import React from 'react';
import { TableC } from '../../src/tablec';
import { mountWrap, shallowWrap } from '../testhelp/contextWrap';
import { expectedProps } from './mockdata'

describe('Table', () => {
  let props;
  let component;
  const wrappedShallow = () => shallowWrap(<TableC {...props} />);

  const wrappedMount = () => mountWrap(<TableC {...props} />);

  beforeEach(() => {
    props = {
      query: {
        data: tableData,
        refetch: jest.fn(),
      },
    };
    if (component) component.unmount();
  });

  test('should render with mock data in snapshot', () => {
    const wrapper = wrappedShallow();
    expect(wrapper).toMatchSnapshot();
  });

  test('should call a DeepTable with correct props', () => {
    const wrapper = wrappedMount();
    expect(wrapper.find('DeepTable').props()).toEqual(expectedProps);
  });

});

Вы также можете использовать этот шаблон для переноса подкомпонентов в другие типы контекста, например, если вы используете response-intl, material-ui или ваши собственные типы контекста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...