How to manage Apollo-wrapped children in test cases when mounting the React component

For the past few months, I've been immersed in working with ApolloJS within React (using react-apollo) and have encountered various tricks and challenges when it comes to unit testing components wrapped with Apollo.

When testing a component directly wrapped with Apollo, I make sure to export and test the component before applying the HoC returned by graphql. In cases where a component has an Apollo-wrapped descendant, I rely on Enzyme's shallow rendering to prevent the descendant from mounting whenever possible. If full-DOM rendering using mount is necessary, I utilize a MockedProvider from Apollo's testing utilities to avoid errors related to accessing this.context within descendants.

However, one scenario continues to pose a challenge: testing a component with Apollo-wrapped descendants using full-DOM rendering while still needing to make assertions regarding the component instance itself (such as state or instance methods). The use of a mocked provider for avoiding issues with descendants results in assertions on the wrapper being performed on the MockedProvider instance rather than the intended component being tested.

Here’s an example:

import { mount } from 'enzyme'
import { MockedProvider } from 'react-apollo/lib/test-utils'

// This component contains descendants that are Apollo-wrapped and require access to `this.context` from an Apollo provider
import Assignments from 'app/components/assignments

...

describe('<Assignments />', function() {
  it('sets sorted assignments in initial state', function() {
    const assignments = [...]

    const wrapper = mount(
      <MockedProvider>
        <Assignments assignments={assignments} />
      </MockedProvider>
    )

    // Test fails due to wrapper referencing the MockedProvider instance instead of the Assignments instance
    expect(wrapper.state('assignments')).to.eql([...])
  })
})

I've explored potential solutions through Enzyme to access the child component instance instead of the root, but it seems unsupported. Additionally, I’ve been searching for alternatives to utilizing the MockedProvider in these scenarios without success.

If anyone has devised a workaround for this issue or recommends a different approach when dealing with nested Apollo-wrapped components, your insights would be greatly appreciated.

Answer №1

I have successfully resolved the issue I was facing. The issue with Apollo-wrapped descendants of mounted components causing errors stemmed from an error being thrown when attempting to access this.context.client. In this situation, Apollo's MockedProvider creates an Apollo client (or utilizes one provided) and makes it accessible to its children through context.

I discovered that Enzyme's mount method allows for specifying the component's context. Although I had previously attempted to use this feature, it was not until I combined it with the appropriate childContextTypes that the context was effectively passed down to the mounted component's descendants. This utilization of Enzyme options eliminated the necessity for utilizing the MockProvider.

To demonstrate the solution based on my original question's example:

import React from 'react'
import { mount } from 'enzyme'

// Here lies an Apollo client configured in a separate module
// with a mocked network interface. Further specifics are omitted here,
// but more information can be provided upon request
import mockedClient from 'test/mocked_client'

// This particular component has descendants enveloped by Apollo
// and thus requires access to `this.context` facilitated by an Apollo provider
import Assignments from 'app/components/assignments

...

describe('<Assignments />', function() {
  it('establishes sorted assignments in initial state', function() {
    const assignments = [...]

    const wrapper = mount(
      <Assignments assignments={assignments} />,
      {
        context: { client: mockedClient },
        childContextTypes: {
          client: React.PropTypes.object.isRequired
        }
      }
    )

    // The test now succeeds!
    expect(wrapper.state('assignments')).to.eql([...])
  })
})

This explanation may prove beneficial to individuals encountering a similar scenario!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Differences in React projects utilizing materialize-css compared to those using react-toolbox or material-ui

Is there a difference in technical benefits or code reliability when directly using material-css in JSX versus utilizing JSX specific libraries like material-ui or react-toolbox? Conversely, could using JSX libraries like material-ui or react-toolbox provi ...

Ways to address the Generic Object Injection Sink eslint error (security/detect-object-injection)

I am seeking a solution to resolve this issue without needing to deactivate eslint. Moreover, I am eager to comprehend the cause of the error. const getMappedCard = (cardName: CardName) => { const mappedCards = { Mastercard: <Mastercard /> ...

Guide to importing the Slider Component in React using Material-UI

I am trying to incorporate the Slider Component from @material-ui/core into my React project. However, when I attempt to import the Slider using this code: import Slider from '@material-ui/lab/Slider';, it gives me an error stating Module not fou ...

Implement React-intl into the designated placeholder within the object

Currently facing an issue with the const inputProps in my code. I attempted to integrate React-intl into the react-autosuggest placeholder input, but now the placeholder text displays as: [Object object]. The getStepContent function is defined as follow ...

Having trouble with the React Github page not functioning correctly

https://i.stack.imgur.com/Ezc00.png I have developed a react app for ticket management and set up a proxy in the package.json file to connect with the backend. This setup works fine on localhost, but when I deploy the app to GitHub pages, it fails to conn ...

Puzzled by the specialized link feature

As I delve into the world of React and Next.js, I find myself working on the link component. Initially, I had a grasp on basic routing in next.js which seemed pretty straightforward. However, things took a confusing turn when I stumbled upon this code: imp ...

The height and alignment of the <a> tag and <p> element vary within a flex container

Currently, I am in the process of constructing a bottom navigation bar for a blog page. This navigation bar will allow users to easily navigate between the last blog entry, the main blog home/index, and the upcoming post. However, when the user reaches the ...

The comparison between importing TypeScript and ES2015 modules

I am currently facing an issue with TypeScript not recognizing the "default export" of react. Previously, in my JavaScript files, I used: import React from 'react'; import ReactDOM from 'react-dom'; However, in TypeScript, I found tha ...

The plugin registration failed for 'html-webpack-plugin-before-html-processing' as the specified hook could not be located

An error occurred: Plugin could not be registered at 'html-webpack-plugin-before-html-processing'. The hook was not found. BREAKING CHANGE: There must be a hook at 'this.hooks'. To create a compatibility layer for this hook, hook into & ...

I encountered a TypeScript error in React Native when attempting to use "className" with TypeScript

Although I've been using React for a while, React Native is new to me. I recently started using tailwind with import { View, Text } from "react-native"; import React from "react"; export default function Navigation() { return ...

Guide on how to validate react-multiselect with the use of Yup validation schema

If the multiselect field is empty, the validation message 'Product is required' is not being displayed. How can I validate this field? Here is the validation schema: validationSchema={ Yup.object().shape({ productID: Yup.string().requi ...

Having trouble getting Global.css to apply on your Next.js pages/components?

Hello, I am just starting to work with nextjs. I defined a css class in my styles/globals.css file: .section-sidebar-filter-name { margin: 0 0 .5rem; } In my pages/_app.js file, I have imported the styles like this: import '../styles/globals.css&a ...

Issues with routing on Zeit Now platform are causing a 404 NOT FOUND error when attempting to reload pages that are not the

Recently, I purchased a Next.js template from Themeforest and attempted to deploy it to Zeit Now. This particular project is set up as a monorepo using Lerna and Yarn workspace. The code for the Next.js app can be found inside the packages/landing folder. ...

Creating trendy designs with styled components: A guide to styling functional components as children within styled parent components

I am looking to enhance the style of a FC styled element as a child inside another styled element. Check out the sandbox example here const ColorTextContainer = styled.div` font-weight: bold; ${RedBackgroundDiv} { color: white; } `; This resul ...

"Although the child route has been loaded, it has not been displayed

Looking for a straightforward site that uses react-router for "code splitting"? Check out the source code here. The route defined in app.js is as follows: const rootRoute = { component: 'div', childRoutes: [ { path: '/', c ...

Struggling to successfully upload a file using express and fileupload, but I am having trouble getting it to function properly

This is my first attempt at uploading files to the server, following a tutorial to build both frontend and backend in React. Unfortunately, I'm facing some difficulties getting it to work properly. I've made adjustments to my backend and tested ...

"Building a dynamic form with ReactJS, Redux Form, and Material UI - Implementing an

Currently working on a nested form framework that utilizes the redux form and material UI framework. The components have been developed up to this point - https://codesandbox.io/s/bold-sunset-uc4t5 My goal is to incorporate an autocomplete field into the ...

403 You are prohibited from adding more Parents in Google Drive API for React Native

For the past 4 months, my code with react-native-google-drive-api-wrapper was functioning perfectly. However, recently I encountered an issue where I am unable to upload files to any folder in Google Drive using my React Native app. Strangely, I can still ...

The conflict between Material UI's CSSBaseline and react-mentions is causing issues

Wondering why the CSSBaseline of Material UI is causing issues with the background color alignment of React-mentions and seeking a solution (https://www.npmjs.com/package/react-mentions) Check out this setup: https://codesandbox.io/s/frosty-wildflower-21w ...

Creating interactive form fields using React

How can I update nested fields in react forms? First, create a new item using handleAddShareholder. Next, delete an existing item with handleRemoveShareholder. To change details of an item, use handleShareholderNameChange. You can then add a new array ...