medev21
medev21

Reputation: 3041

Testing mobx react observer with react usecontext - React, Mobx

New to testing mobx with React. I'm testing a a simple side navigation bar, open/closes on hamburger menu. I have set up a store for the Navbar:

export class Store {

    toggle = false;

    setToggle(bool){
        this.toggle = bool;
    };
};

decorate(Store, {
    toggle: observable,
    setToggle: action
});

export default createContext(new Store());

And here is the Navbar component:

export default observer(() => {
    const store = useContext(Store); //SideNavStore is imported from mobx store folder

    const handleOnClick = () => {
        store.setToggle(false);
    }

    return(
        <div data-testid="test">
            <Drawer open={store.toggle} onClose={handleOnClick}>
                <div role="presentation">
                    <List>
                        {routes.map(route => {

                            return   <>
                                        <ListItem button onClick={handleOnClick}>
                                            <ListItemText primary={route.name}/>
                                        </ListItem>
                                    </>

                        })}
                    </List>
                </div>
            </Drawer>
        </div>
    );
});

This is App.js

export default () => {

    return (
      <div className="App">


        <Navbar ></Navbar>

      </div >
    )
  }

Test.js

describe('Navbar Interaction', () => {

    describe('Inpsecting Navbar Contents', () => {

        beforeEach(cleanup);

        class Store {
            sideNavToggle = true;
        }

        const DecoratedStore = decorate(Store,{
            sideNavToggle: observable
        });

        const renderWithStore = (store) => {
            render(
                    <Navbar />
            );
        }

        it('Expect links are present', () => {
            const store = new DecoratedStore();
            const { getByText } = renderWithStore(store);
            expect(getByText("My Dashboard")).toBeTruthy();
        });

    });
})

My test here fails because it can't find the text in the document, Drawer Open is set to false configured by the store.toggle. Trying to figure out how to inject the store or dummy store in the test, there are some tutorials about using Provider/Inject but that requires mobx-react and I believe they are deprecated; I would like to stick with mobx-react-lite. In renderWithStore, I'm stuck on how to pass the dummy store in the test. I could pass the store as a props but I believe that requires provider/inject which I don't want to do that if necessary. I rather import the store directly in the Navbar component using React.useContext. I don't see tests using React.useContext and Mobx Observer in the web. Has anyone encountered this type of scenario or can you provide a better approach? Also what is the best practice with using React and Mobx stores? Using React-testing-library for my tests. Your help is appreciated!

Upvotes: 3

Views: 2980

Answers (1)

LostInComputer
LostInComputer

Reputation: 15420

mobx-react-lite does advice users to prefer React.useContext over provider/inject.

Take a look at https://mobx-react.js.org/recipes-context

const storeContext = React.createContext<TStore | null>(null)

export const StoreProvider = ({ children }) => {
  const store = useLocalStore(createStore)
  return <storeContext.Provider value={store}>{children}</storeContext.Provider>
}

As for testing, if you want the component to use custom store or a mock store, you could do it by passing-in the store to StoreProvider. This how Redux users test their components.

export const StoreProvider = ({ store, children }) => {
  return <storeContext.Provider value={store}>{children}</storeContext.Provider>
}

Upvotes: 3

Related Questions