Invalid Chai property: toMatchSnapshot -- React.js Jest testing
Asked Answered
P

4

10

I'm getting an error: Invalid Chai property: toMatchSnapshot when I try to use Jest + Enzyme's snapshot testing. I've updated my React version to 16.2 and I use enzyme-to-json library with Enzyme 3.

Code is below:

import React from 'react';
import ReactDOM from 'react-dom';
import ConnectedApp, { App } from './App';
import { ConnectedRouter } from 'react-router-redux';
import { Provider } from 'react-redux';
import { expect } from 'chai';
import { mount, shallow } from 'enzyme';
import createHistory from 'history/createMemoryHistory'
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import toJson from 'enzyme-to-json';

describe('App tests', () => {
  const middlewares = [thunk];
  const mockStore = configureMockStore(middlewares);
  let store, container, history, wrapper;

  const initialState = {
    output: true
  }

  beforeEach(() => {
    store = mockStore(initialState);
    history = createHistory();
    wrapper = mount(
      <Provider store={store}>
        <ConnectedRouter history={history}>
          <ConnectedApp />
        </ConnectedRouter>
      </Provider>
    )  
  });

  it('+++capturing Snapshot of App', () => {
    expect(toJson(wrapper)).toMatchSnapshot();
  });
})

I've also tried this with Jest's render like so:

import renderer from 'react-test-renderer';

it('renders correctly', () => {
  var component = <Provider store={store}>
                    <ConnectedRouter history={history}>
                      <ConnectedApp />
                    </ConnectedRouter>
                   </Provider>
  const tree = renderer
    .create(component)
    .toJSON();
  expect(tree).toMatchSnapshot();
});

But I still get the Invalid Chai property: toMatchSnapshot error. Anyone know what's up?

Pancake answered 16/12, 2017 at 6:5 Comment(0)
T
7

This isn't an issue with the renderer you are using. The problem is that you are using chai expectations instead of the expectation library that ships with jest. The chai API has no toMatchSnapshot method. To fix it you can do the following:

  1. Stop using chai and use the jest expectations exclusively. This may simply be a matter of removing line 6: import { expect } from 'chai'

However, if you need to continue to use chai (i.e. you have a lot of chai tests already written and you don't want to do a major overhaul all at once) you can do two things:

  1. Alias either the the chai or jest expect functions in your test setup file e.g. global.chaiExpect = chai.expect
  2. Monkey-patch the global expect function so that you can use both the chai and the jest API like in this blog post: https://medium.com/@RubenOostinga/combining-chai-and-jest-matchers-d12d1ffd0303

    The relevant bit is this:

// Make sure chai and jasmine ".not" play nice together
const originalNot = Object.getOwnPropertyDescriptor(chai.Assertion.prototype, 'not').get;
Object.defineProperty(chai.Assertion.prototype, 'not', {
  get() {
    Object.assign(this, this.assignedNot);
    return originalNot.apply(this);
  },
  set(newNot) {
    this.assignedNot = newNot;
    return newNot;
  },
});

// Combine both jest and chai matchers on expect
const originalExpect = global.expect;

global.expect = (actual) => {
  const originalMatchers = originalExpect(actual);
  const chaiMatchers = chai.expect(actual);
  const combinedMatchers = Object.assign(chaiMatchers, originalMatchers);
  return combinedMatchers;
}; 
Touchback answered 18/12, 2017 at 18:35 Comment(4)
that's what I thought was happening. But I just used the regular create-react-app configuration -- it should ship with Jest fully configured right? Not sure where / why Chai pops into the photo. Do you know how to disable chai?Pancake
On line 6 you are importing the expect function from chai. You can likely simply remove that and it will use the global expectTouchback
Thx @Touchback for your clarification. But just one very naive doubt I have, the workaround that you gave i.e. global.chaiExpect = chai.expect. This one do I need to change in my .spec.js file because I am not able to find test setup file in my project. Please help me in this.Heyes
@AlokRanjan You can configure jest in your package.json or with a jest.config.js file. There's lots of stuff you can configure but for this issue you can provide a setupFilesAfterEnv array in the config, which includes the setup file that you want to run. Create a testConfig.js file at the root of your project with the above monkeypatch and then include it in your jest.config.js file like this javascript modules.exports = { setupFilesAfterEnv: [ '<rootDir>/testConfig.js', ], } See: jestjs.io/docs/en/configuration#setupfilesafterenv-arrayTouchback
K
1

For those transitioning away from chai (which would be hijacking expect() from jest in the top level setupTests.js file) the simpler solution is to load jest's expect() again on top of the current test file like so:

import { expect } from "@jest/globals";

That is, until you can't fully do away with any

global.expect = chai.expect;

somewhere in the code, setupTests.js for example.

Keturahkeung answered 19/2, 2022 at 3:35 Comment(0)
E
0

Its Simple.Just write your test scripts (something.spec.js) in to another file without importing 'chai' . It will work like a charm. No need for messy stuffs.Keep it Simple !

Embryectomy answered 3/2, 2018 at 19:43 Comment(0)
H
-2

This is partially related to this post & root cause given by other authors are quite accurate and very informative.

I also faced same problem as discussed in this post, when I was trying to use expect(container).toHaveLength(1);

I solved this issue by changing my way to write assertion in Jest way like, expect(container).to.have.length(1);

So basically we need to find way to change our assertion to write in Jest way, if we are using Jest.

Hope it may help someone.

Heyes answered 4/8, 2020 at 18:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.