1

I have a follow up question to this: Test component with context and react hook

The top answer says, instead of creating a new context, use the AuthContext from context/AuthContext for <AuthContext.Provider>, as that's the context that the hook uses.

I'm confused as to what this means exactly (would have left a comment, but don't have enough rep to comment yet)-- would someone be able to show it to me via code sandbox?

Thanks!

1 Answer 1

0

It is simply saying to use the same React context that the custom hook/component is using, not some other "random" auth provider.

Example Auth Context:

export const useAuth = () =>  useContext(AuthContext);

export const AuthProvider = ({ children }) => {
  const [currentUser, setCurrentUser] = useState();
  const [loading, setLoading] = useState(true);

  const signup = (email, password) => {
    return auth.createUserWithEmailAndPassword(email, password);
  }

  const login = (email, password) => {
    return auth.signInWithEmailAndPassword(email, password);
  }

  const logout = () => auth.signOut();

  ...

  const value = {
    currentUser,
    signup,
    login,
    logout,
  };

  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  );
}

Example Consuming Component:

import { useAuth } from "../context/AuthContext"; // <-- specific context

export default function Dashboard() {
  const { currentUser, logout } = useAuth(); // <-- specific context

  ...

  return (
    <div>
      ...
    </div>
  );
}

The specific AuthProvider component needs to appear above the component in the React tree in order to provide the Context and state.

If for example, like the unit test, you create another React Context provider:

const AuthContext2 = createContext(); // AuthContext2 to disambiguate it here

And wrap the component in a AuthContext2.Provider then the component is still importing and consuming the AuthProvider exported from code above.

The answer is saying to also import the AuthProvider and wrap that for the unit test instead of creating an entirely new Context.

import { AuthProvider } from "../context/AuthContext";

const AllTheProviders = ({ children }) => {
  return (
    <Router>
      <AuthProvider>
        {children}
      </AuthProvider>
    </Router>
  );
};

const customRender = (ui, options) => {
  render(ui, { wrapper: AllTheProviders, ...options });
};

Update

where would I feed in mock values?

Refactor the Context provider you have to consume an "initial state" prop that is used to set the initial state the context uses. Refactor the custom test renderer to take additional arguments and pass them through to wrappers.

@musicformellons

could you maybe make that refactor part of the answer...?!

Sure, should probably be included.

export const AuthProvider = ({ children, initialState }) => {
  const [currentUser, setCurrentUser] = useState(initialState.currentUser);
  
  ...

  const value = {
    currentUser,
    signup,
    login,
    logout,
  };

  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  );
}

Test

import { AuthProvider } from "../context/AuthContext";

const AllTheProviders = ({ children }) => {
  return (
    <Router>
      <AuthProvider initialState={authState}>
        {children}
      </AuthProvider>
    </Router>
  );
};

const customRender = (ui, options, initialState) => {
  render(
    ui,
    {
      wrapper: props => (
        <AllTheProviders {...props} initialState={initialState} />
      ),
      ...options,
    },
  );
};
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for such a clear explanation, makes a lot more sense! Just one more clarification, where would I feed in mock values? I tried adding them as a value attribute i.e. <AuthProvider value={{ currentUser, signup, login, logout }}> but that seems to give me an error
@KylieHarr That's a good question... had me stumped for a minute... until I realized you could take a cue from how a "store" is passed as a prop to a Redux Provider. In other words, refactor the Context provider you have to consume an "initial state" prop that is used to set the initial state the context uses.
@DrewReese Uhm, could you maybe make that refactor part of the answer...?!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.