Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

reactjs - React Testing Library / Redux - How to mock cookies?

Issue

I'm able to mock the cookie in Jest, but it won't change the state of my components once the cookie is mocked.

For example, when a user visits my app, I want to check if a cookie of ACCESS_TOKEN exists, if it exists, render a saying "Hi, Username".

When testing, I'm able to create the cookie and get the values with console.log(), but my component won't render the because the test does not think redux-store has the cookie.

Here's what my redux-store looks like (Redux store is not the problem, all my tests that does not rely on cookies and soley relies on store are working):

Root.tsx

export const store = createStore(
    reducers,
    { authStatus: { authenticated: Cookies.get("ACCESS_TOKEN") } },
    //if our inital state (authStauts) has a cookie, keep them logged in
    composeWithDevTools(applyMiddleware(reduxThunk))
);

const provider = ({ initialState = {}, children }) => {
    return <Provider store={store}>{children}</Provider>;
};

export default provider

App.tsx

import Root from "./Root"; //root is provider variable in Root.tsx
ReactDOM.render(
    <React.StrictMode>
        <Root>
            <App />
        </Root>
    </React.StrictMode>,
    document.getElementById("root")
);

Welcome.tsx

const Welcome =(props) => {

    return(
      <div>
        {props.authStatus && <h3> Hello USERNAME</h3>}
     </div>
    }
   }

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

export default connect(mapStateToProps, {})(Welcome);

Here's my test:

import Cookies from "js-cookie"

beforeEach(async () => {
   //Before the component renders, create a cookie of ACCESS_TOKEN.

    //Method 1 (Works, console.log() below would show the value, but component won't render):
    //jest.mock("js-cookie", () => ({ get: () => "fr" }));

    //Method 2 (Works, console.log() below would show the value, but component won't render):
    //Cookies.get = jest.fn().mockImplementation(() => "ACCESS_TOKEN");

    //Method 3 (Works, console.log() below would show the value, but component won't render)):
    // Object.defineProperty(window.document, "cookie", {
    //     writable: true,
    //     value: "myCookie=omnomnom",
    // });


    app = render(
        <Root>
            <MemoryRouter initialEntries={["/"]} initialIndex={0}>
                <Routes />
            </MemoryRouter>
        </Root>
    );
    console.log("Cookie Val", Cookies.get());
    app.debug(); //I want to see that the <h3> is rendered, but it's not being rendered.
});

Why is this occurring?

Resources used:

How to mock Cookie.get('language') in JEST

Use Jest to test secure cookie value

question from:https://stackoverflow.com/questions/65877050/react-testing-library-redux-how-to-mock-cookies

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I'm not exactly sure how did you combine things together but I'm gonna drop you a full example that you can follow and fix your code as bellow, please check inline comments:

// Provider.jsx
import React from 'react';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import Cookies from "js-cookie";

// the reducer I assume as same as you created
const authReducer = (state = {}, action) => {
  return {
    ...state,
    ...action.payload,
  }
}

const store = createStore(
    authReducer,
    { authStatus: { authenticated: Cookies.get("ACCESS_TOKEN") } }
);

export default ({ initialState = {}, children }) => {
    return <Provider store={store}>{children}</Provider>;
};

// Routes.jsx
// should be the same as you did
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import Welcome from "./Welcome";

export default (props) => {
    return (
        <Switch>
          <Route exact path="/" component={Welcome} />
        </Switch>
    )
}

Finally the test file:

// index.test.js
import React from 'react';
import Cookies from "js-cookie"
import "@testing-library/jest-dom"
import { screen, render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import Routes from "./Routes";
import Provider from "./Provider";

// Mock your cookie as same you did 
// but should be the same level with `import` things
jest.mock("js-cookie", () => ({ get: () => "fr" }), {
   // this just for being lazy to install the module :)
   virtual: true
});

it('should pass', () => {
    render(
        <Provider>
            <MemoryRouter initialEntries={["/"]} initialIndex={0}>
                <Routes />
            </MemoryRouter>
        </Provider>
    );

    expect(screen.queryByText('Hello USERNAME')).toBeInTheDocument()
})

PS: The link I created the test for you: https://repl.it/@tmhao2005/js-cra (ref at src/Redux to see full example)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...