material-ui-pickers: [Typescript] TypeError: Utils is not a constructor

Environment

Tech Version
material-ui-pickers 2.0.4
material-ui 1.2.2
React 16.5.0
Browser Chrome / Node
Peer library moment -> 2.22.2

Steps to reproduce

  1. Given the following component:
import MomentUtils from "@date-io/moment";
import DatePicker from "material-ui-pickers/DatePicker";
import MuiPickersUtilsProvider from "material-ui-pickers/MuiPickersUtilsProvider";
import * as moment from "moment";
import "moment/locale/es";
import * as React from "react";
moment.locale("es");

export function CustomDatePicker(props) {
  const { date, handleDateChange, ...rest } = props;
  return (
    <MuiPickersUtilsProvider utils={MomentUtils} moment={moment} locale="es">
      <DatePicker
        value={date}
        onChange={handleDateChange}
        {...rest}
      />
    </MuiPickersUtilsProvider>
  );
}

export default CustomDatePicker;
  1. When mounted in a test using Jest + Enzyme like this:
it("renders without crashing", () => {
  let elem = mount(
    <CustomDatePicker
      date={new Date().toString()}
      handleDateChange={e => console.log(e)}
    />
  );
});
  1. I get the following runtime error: TypeError: Utils is not a constructor. If I use shallow instead then the test passes, but I get this warning: Warning: Failed prop type: The prop 'utils' is marked as required in 'MuiPickersUtilsProvider', but its value is 'undefined' in MuiPickersUtilsProvider.

In the real world, A.K.A outside of my tests the actual component seems to mount and work without issues, but this messes up not only my unit tests but all my integration tests.

Expected behavior

MuiPickersUtilsProvider shouldn’t complain, my component should mount inside the test, and the test should pass.

Live example

I’m trying to reproduce this here, but MuiPickersUtilsProvider just refuses to render (?) 🤔 https://codesandbox.io/s/20j8zl8zzj

Thanks in advance for your help y’all!

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 16 (7 by maintainers)

Commits related to this issue

Most upvoted comments

So I played around with a bunch of combinations in tsconfig.json and tsconfig.test.json for module, esModuleInterop and allowSyntheticDefaultImports.

The winning combo for my project was:

tsconfig.json

{
"compilerOptions": {
    "outDir": "build/dist",
    "module": "esnext",
    "target": "es5",
     ...
    "allowSyntheticDefaultImports": true
  },
}

tsconfig.test.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs",
    "esModuleInterop": true
  }
}

I hope that helps anybody facing the same issue. I think the issue can now be closed.

What’s funny is that I cannot replicate what I have on my real-life project. In this project the following happens:

  1. Using import MomentUtils from "@date-io/moment" works for the actual rendering with React-DOM, but breaks my tests.

  2. Using import * as MomentUtils from "@date-io/moment"; makes the tests pass, but breaks the rendering of with React-DOM.

In both cases (respectively) the error is that instead of the MomentUtils(_a) { … } constructor function, the component receives an object that contains the constructor, like so {default: MomentUtils(_a) { … }}. I can make it work in this case by passing it like so utils={MomentUtils.default}, but because the import result is always the other way around on my tests I always break either the tests or the real thing… 🤔 this is driving me nuts hahaha!

EDIT — Correction: calling import MomentUtils from "@date-io/moment" results in MomentUtils being nothing in the test env?