redux 在“Connect(Items)"的上下文中找不到“store”,是否将根组件 Package 在inreact.js中< Provider>?

ryhaxcpt  于 2022-11-12  发布在  React
关注(0)|答案(2)|浏览(194)

我正在使用React Testing Library编写带有计数器的简单测试。我的测试失败是因为上面提到的与store有关的错误。
我尝试使用不同的方法来解决这个问题,比如创建一个mockStore,并将组件 Package 在ShallowProvider周围。我还尝试在index.js中创建存储,但我已经导入了store..我似乎无法指出这个问题。
如果有人能告诉我怎么修,我将非常感激。

下面是我的代码:

存储.js

import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import {composeWithDevTools} from 'redux-devtools-extension'

import rootReducer from './reducers'

const initialState = {

}

const middleware = [thunk]

const store = createStore(rootReducer, initialState, composeWithDevTools(applyMiddleware(...middleware)))

export default store;

索引.js:

import "./index.css";
import reportWebVitals from "./reportWebVitals";
import { Provider } from "react-redux";
import store from "./store/store";
import App from "./App";
import { BrowserRouter  } from "react-router-dom";

ReactDOM.render(
  <BrowserRouter>
    <Provider store={store}>
      <App />
    </Provider>
  </BrowserRouter>,
  document.getElementById("root")
);
 reportWebVitals();

账单测试js:

import { screen, fireEvent, act } from "@testing-library/react";
import BillList from "../BillList";
import Adapter from 'enzyme-adapter-react-16'
import configureMockStore from "redux-mock-store";
import { shallow, configure  } from "enzyme";
import { Provider } from "react-redux";

const mockStore = configureMockStore();
const store = mockStore({});

configure({adapter: new Adapter()});
describe("<BillList />", () => {
  // will display 1 by default because there will be already an item when the page renders
  test("display counter text", () => {
    shallow(
        <Provider store={store}>
            <BillList />
        </Provider>

        ) 

    expect(screen.queryByTestId("counter-text")).toBe("1");
  });

  // Button increments the price value by +1
  test("increment counter", () => {
   shallow(
   <Provider store={store}>
       <BillList />
       </Provider>

   ) 

    const btnIncrement = screen.queryByTestId("btn-increment");
    fireEvent.click(btnIncrement);

    expect(screen.queryByTestId("counter-text")).toBe("2");
  });

  // Button decrements the price value by -1

  test("decrement counter", () => {
    shallow(
        <Provider store={store}>
            <BillList />
        </Provider>

        ) 
    const btnDecrement = screen.queryByTestId("btn-decrement");
    fireEvent.click(btnDecrement);

    expect(screen.queryByTestId("counter-text")).toHaveTextContent("1");
  });

});

账单列表.js:

import React, { useState } from "react";
import "./Bill.css";
import { Link, useParams, Switch, Route } from "react-router-dom";
import { connect,} from "react-redux";

import { getItems } from "../store/actions/itemsActions";

function BillList({ items }) {
  const [counter, setCounter] = useState(1);
  const { id } = useParams();
  var ust = parseFloat(0.18);

  function Display(props) {
    return <label style={{ marginLeft: ".5rem" }}>{props.message}</label>;
  }

  return (
    <div className="bills">
      <div
        className="main-title"
        style={{
          textAlign: "center",
          justifyContent: "center",
          alignItems: "center",
          fontSize: 14,
        }}
      >
        <h1>Bakery</h1>
        <h1>Company Gbr</h1>
        <h1>Oranienburger Straße 120</h1>
        <h1>10119 Berlin</h1>
      </div>

      <div className="bills-container">
        {/* pass in the details  */}
        <div className="item-list">
          {items &&
          items.items
            .filter((item) => item.id === Number(id))
            .map((item) => (
              <React.Fragment key={item.id}>
                <div className="bill-time">
                  <div className="bill">
                    <h4>
                      {" "}
                      <strong>Bill: </strong>
                      {item.billNumber}
                    </h4>
                  </div>

                  <div className="time">
                    <h4>
                      {" "}
                      <strong>Time: </strong>
                      {item.created_datetime}
                    </h4>
                  </div>
                </div>
                <div className="lines-time">
                  ------------------------------------------------------------------------------------------
                </div>

                {/* Counter  */}
                <div className="price-total">
                  <div className="head-title">
                    <div className="title">
                      <h3>
                        {" "}
                        <strong>Title: {item.title} </strong>
                      </h3>
                    </div>
                    <div className="counter" data-testid="counter-text">
                      <strong>
                        <Display  message={counter} />x
                      </strong>
                    </div>
                    <div className="lines">------------</div>
                  </div>

                  <div className="increase">
                    <button onClick={() => setCounter(counter + 1)} data-testid="btn-increment">+</button>
                  </div>
                  <div className="decrease">
                    <button onClick={() => setCounter(counter - 1)} data-testid="btn-decrement">-</button>
                  </div>

                  {/* Price and total */}

                  <div className="price">
                    <h4>
                      <strong>Price: {parseFloat(item.price).toFixed(2)}€ </strong>
                    </h4>
                  </div>
                  <div className="a">A</div>

                  <div className="total">
                    <h4>Total: </h4>
                  </div>
                  <div className="total-price">
                    {parseFloat(item.price * counter).toFixed(2)}€
                  </div>
                  <div className="given">
                    <h4>Given: (iZettle)</h4>
                  </div>
                  <div className="given-price">
                    {parseFloat(item.price * counter).toFixed(2)}€
                  </div>
                  <div className="lines-taxes">
                    -------------------------------------------------------------------------------
                  </div>
                  <div className="gross">
                    <h4>
                      <strong>gross</strong>
                    </h4>
                  </div>
                  <div className="gross-price">{((parseFloat(item.price) * counter)).toFixed(2)}€</div>
                  <div className="taxes">
                    <h4>USt.%</h4>
                  </div>
                  <div className="percent">A=7%</div>
                  <div className="ust">
                    <h4>USt.</h4>
                  </div>
                  <div className="ust-percent">{(ust * counter).toFixed(2)} €</div>
                  {/* net - the USt */}
                  <div className="net">
                    <h4>net</h4>
                  </div>
                  <div className="net-result">

                    {(parseFloat(item.price) * counter - parseFloat(0.18 * counter)).toFixed(2)} €

                  </div>
                </div>
              </React.Fragment>
            ))}
        </div>
        {/* Paragraph */}
        <div className="terminal">
          <p> Table:  Counter</p>
          <p> Terminal:  Terminal 1</p>
          </div>

        <div className="TSE-Transaktion ">
          <p>
            TSE-Transaktion 
          </p>
          <p>TSE-Signatur-Nr. </p>
          <p>
          TSE-Start 
          </p>
          <p>
          TSE-Stop 
          </p>
          <p>
          TSE-Seriennummer
          </p>
          <p>
          TSE-Zeitformat
          </p>
          <p>
          TSE-Signatur 
          </p>
          <p>
          TSE-Hashalgorithmus
          </p>
          <p>
          TSE Status 
          </p>
        </div>

        <div className="right-side">
          <p>
          1831
          </p>
          <p>
          98009
          </p>
          <p>
          2020-04-21T09:29:38.00000Z
          </p>
          <p>
          2020-04-21T09:29:50.00000Z
          </p>
          <p>
          5f2897cc074ae841330658eadd324661159f53b7ffd29215
          </p>
          <p>
          utcTime
          </p>
          <p>
          bXkPffFOcetbFokYrOqr/7EYrAc0PH6r
          </p>
          <p>
          ecdsa-plain-SHA256
          </p>
          <p>
          In evaluation
          </p>

        </div>

        <div className="de11">
        <p>Ust-Id: DE11111111</p>
        </div>

        {/* Button */}
      </div>

      <div className="button-path">
        <Link data-testid="analyse-receipt-path" to="/">
          <div className="button">
            <button data-testid="analyse-receipt"  className="main-button">Analyse Receipt</button>
          </div>
        </Link>
      </div>

      <Switch>
        <Route path="/bills/:id" />
      </Switch>
    </div>
  );
}

const mapStateToProps = (state) => {
  return {
    items: state.items,
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    getItems: () => dispatch(getItems()),
  };
};

export default connect(mapStateToProps, mapDispatchToProps)  (BillList);
hxzsmxv2

hxzsmxv21#

您只测试该组件,因此无法访问Provider,因为它是父组件。您可以创建一个自定义 Package 器,以便在每个测试中使用Redux。使用下面的代码,您将使用reduxRender而不是标准的render

import { render} from '@testing-library/react'
import { Provider as ReduxProvider } from 'react-redux'
import store from './whereverYourStoreIs/store'

/**To be used whenever Redux is referenced */
const ReduxWrapper = ({ children }) => (
    <ReduxProvider store={store}>
      {children}
    </ReduxProvider>
)

/**Render used for Redux */
const reduxRender = (ui, options) =>
  render(ui, { wrapper: ReduxWrapper, ...options })
wj8zmpe1

wj8zmpe12#

试着模拟react-redux,在导入之后把它放在单元测试文件的顶部。

jest.mock('react-redux', () => ({
  connect: () => (ReactComponent) => ReactComponent,
}));

相关问题