Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wrappedComponent doesn't actually pass context values down in tests #2189

Open
2 of 13 tasks
heath-freenome opened this issue Jul 15, 2019 · 19 comments
Open
2 of 13 tasks

Comments

@heath-freenome
Copy link

heath-freenome commented Jul 15, 2019

Given the following:

import { shallow } from 'enzyme';
import React, { Component } from 'react';
import PropTypes from 'prop-types';

const FooContext = React.createContext();

class Foo extends Component {
  static contextType = FooContext;

  render() {
    const { value1, value2 } = this.context;
    return (<div>
      <span>Value 1: {value1}</span>
      <span>Value 2: {value2}</span>
    </div>);
  }
}

const someValues = { value1: '1', value2: '2' };

function FooProvider({ children }) {
  return (<FooContext.Provider values={someValues}>
    {children}
  </FooContext.Provider>);
}

FooProvider.propTypes = {
  children: PropTypes.node
};

describe('Foo', () => {
  let spans;
  beforeAll(() => {
    const wrapper = shallow(<Foo/>, { wrappingComponent: FooProvider });
    spans = wrapper.find('span');
  });
  it('the first is someValues.value1', () => {
    const first = spans.at(0);
    expect(first).toExist();
    expect(first).toHaveText(`Value 1: ${someValues.value1}`);
  });
  it('the second is someValues.value2', () => {
    const second = spans.at(1);
    expect(second).toExist();
    expect(second).toHaveText(`Value 2: ${someValues.value2}`);
  });
});

Current behavior

Foo
✕ the first is someValues.value1 (17ms)
✕ the second is someValues.value2 (13ms)

● Foo › the first is someValues.value1

Expected <span> components text to match (using ===), but it did not.
Expected HTML: "Value 1: 1"
Actual HTML: "Value 1: "

  49 |     const first = spans.at(0);
  50 |     expect(first).toExist();
> 51 |     expect(first).toHaveText(`Value 1: ${someValues.value1}`);
     |                   ^
  52 |   });
  53 |   it('the second is someValues.value2', () => {
  54 |     const second = spans.at(1);

  at Object.toHaveText (app/javascript/tests/temp/foo.test.jsx:51:19)

● Foo › the second is someValues.value2

Expected <span> components text to match (using ===), but it did not.
Expected HTML: "Value 2: 2"
Actual HTML: "Value 2: "

  54 |     const second = spans.at(1);
  55 |     expect(second).toExist();
> 56 |     expect(second).toHaveText(`Value 2: ${someValues.value2}`);
     |                    ^
  57 |   });
  58 | });
  59 | 

Expected behavior

The two tests pass. It seems like the values set into the context in FooProvider don't actually get passed to Foo

Your environment

node: 12.4.0

API

  • shallow
  • mount
  • render

Version

library version
enzyme 3.10.0
react 16.8.6
react-dom 16.8.6
react-test-renderer 16.8.6
adapter (below) 1.14.0

Adapter

  • enzyme-adapter-react-16
  • enzyme-adapter-react-16.3
  • enzyme-adapter-react-16.2
  • enzyme-adapter-react-16.1
  • enzyme-adapter-react-15
  • enzyme-adapter-react-15.4
  • enzyme-adapter-react-14
  • enzyme-adapter-react-13
  • enzyme-adapter-react-helper
  • others ( )
@ljharb
Copy link
Member

ljharb commented Jul 16, 2019

contextType is not yet supported.

@heath-freenome
Copy link
Author

Is there an ETA on that?

@DavidLozzi
Copy link

My workaround is to add the provider in the test:

const wrapper = render(<FooContext.Provider values={someValues}>
    <Foo/>
  </FooContext.Provider>);

and changing it to a render from shallow, which introduces some other fun to work through

@JawsomeJason
Copy link

const wrapper = render(<FooContext.Provider values={someValues}>

That should be value, no?

@mjancarik
Copy link

I created module for workaround https://www.npmjs.com/package/shallow-with-context. The module works well in our projects.

@heath-freenome
Copy link
Author

@ljharb Status update?

@heath-freenome
Copy link
Author

Wow, 1.5 years later and it seems like this has stalled. No wonder some people have been saying enzyme isn't the best testing library for React anymore

@ljharb
Copy link
Member

ljharb commented Feb 10, 2021

@heath-freenome that's really not called for or helpful. PRs are quite welcome, and if your company's business depends on this project that's maintained for free by a single developer, perhaps there's some business value in investing resources in improving it.

@heath-freenome
Copy link
Author

@ljharb Sorry about that. I'm just frustrated. For the most part, I've switched the bulk of my implementations to using the useContext() hook inside of stateless functional components and implemented test-only version of that hook which I mock in using jest. I've just run into a case where I need to use contextType within a class component while building server-side rendering and just crashed into this issue again...

@ljharb
Copy link
Member

ljharb commented Feb 11, 2021

I would love to have full contextType support, but the release of npm 7 broke tests on master, so I'm scrambling to fix that so everything else is unblocked. In the meantime, a PR would be very helpful.

@heath-freenome
Copy link
Author

heath-freenome commented Feb 11, 2021

I don't know enough about enzyme to be helpful in anyway right now. I'm also debating solving this current problem using a hooks approach

@ljharb
Copy link
Member

ljharb commented Feb 11, 2021

Hooks don't work in class components, so i'm not sure that's going to help you much :-/

@heath-freenome
Copy link
Author

heath-freenome commented Feb 11, 2021

The idea is to avoid needing a class component... Or at least contexts inside of components

@forivall
Copy link

Right now, i have a dirty solution using patch-package:

patches/enzyme-adapter-react-16+1.15.6.patch

diff --git a/node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js b/node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js
index 5fc24a5..cfb2bbb 100644
--- a/node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js
+++ b/node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js
@@ -847,7 +847,13 @@ var ReactSixteenAdapter = /*#__PURE__*/function (_EnzymeAdapter) {
             });
             var _renderedEl = renderedEl,
                 Component = _renderedEl.type;
-            var context = (0, _enzymeAdapterUtils.getMaskedContext)(Component.contextTypes, unmaskedContext);
+            var context;
+            if (Component.contextType) {
+              var Provider = adapter.getProviderFromConsumer(Component.contextType);
+              context = providerValues.has(Provider) ? providerValues.get(Provider) : getProviderDefaultValue(Provider);
+            } else {
+              context = (0, _enzymeAdapterUtils.getMaskedContext)(Component.contextTypes, unmaskedContext);
+            }
 
             if (isMemo(el.type)) {
               var _el$type = el.type,

patches/react-test-renderer+16.14.0.patch

diff --git a/node_modules/react-test-renderer/cjs/react-test-renderer-shallow.development.js b/node_modules/react-test-renderer/cjs/react-test-renderer-shallow.development.js
index df5c5d4..081bd45 100644
--- a/node_modules/react-test-renderer/cjs/react-test-renderer-shallow.development.js
+++ b/node_modules/react-test-renderer/cjs/react-test-renderer-shallow.development.js
@@ -770,7 +770,7 @@ function () {
     var previousElement = this._element;
     this._rendering = true;
     this._element = element;
-    this._context = getMaskedContext(elementType.contextTypes, context); // Inner memo component props aren't currently validated in createElement.
+    this._context = elementType.contextType ? context : getMaskedContext(elementType.contextTypes, context);
 
     if (reactIs.isMemo(element) && elementType.propTypes) {
       currentlyValidatingElement = element;

I'm not sure if this is the correct semantics, as i've never used the legacy contextTypes api, but i think this is what a PR would need to do. Seems like some change to react-shallow-renderer would also be needed, and an update of enzyme to use the extracted react-shallow-renderer directly, instead of react-test-renderer/shallow (seems like this is also waiting on enzymejs/react-shallow-renderer#16 too?)

thanks for the hard work ljharb!

@ljharb
Copy link
Member

ljharb commented Mar 11, 2021

@forivall with a test case, that seems like most of a PR to enzyme already; we don't have to wait for react-test-renderer to update - we can patch it at runtime in the adapter (we already do things like this for a few cases where react itself is broken).

@forivall
Copy link

awesome. i'll submit a PR when i have a few more extra cycles in the next few days (hopefully i remember).

@ljharb
Copy link
Member

ljharb commented Mar 11, 2021

More than happy to help with the final parts of the fix once the tests are good (and failing)

unverbraucht added a commit to unverbraucht/react-shallow-renderer that referenced this issue Mar 14, 2021
unverbraucht added a commit to unverbraucht/enzyme that referenced this issue Mar 14, 2021
…request context via setting .contextType, according to patches posted in enzymejs#2189 (comment). Adds changes to ReactSixteenAdapter and simple test case.
@unverbraucht
Copy link

Hi all, I added the patch posted by @forivall (thanks!) and a simple test case in #2507, please have a look. @ljharb I have no clue on how to patch react-test-renderer, I manually patched the locally installed shallow-renderer as mentioned by @forivall, can you assist here?

@pabloimrik17
Copy link

Any updates?

pablopalacios pushed a commit to pablopalacios/enzyme that referenced this issue Mar 20, 2022
…request context via setting .contextType, according to patches posted in enzymejs#2189 (comment). Adds changes to ReactSixteenAdapter and simple test case.
pablopalacios pushed a commit to pablopalacios/react-shallow-renderer that referenced this issue Oct 6, 2022
ljharb pushed a commit to unverbraucht/react-shallow-renderer that referenced this issue Oct 7, 2022
ljharb pushed a commit to pablopalacios/enzyme that referenced this issue Mar 14, 2023
Add support for passing context to React class based components that request context via setting .contextType, according to patches posted in enzymejs#2189 (comment). Adds changes to ReactSixteenAdapter and simple test case.

Co-authored-by: Kevin Read <me@kevin-read.com>
Co-authored-by: Pablo Palacios <pablo.palacios@holidaycheck.com>
ljharb pushed a commit to pablopalacios/enzyme that referenced this issue Mar 14, 2023
Add support for passing context to React class based components that request context via setting .contextType, according to patches posted in enzymejs#2189 (comment). Adds changes to ReactSixteenAdapter and simple test case.

Co-authored-by: Kevin Read <me@kevin-read.com>
Co-authored-by: Pablo Palacios <pablo.palacios@holidaycheck.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants