react-textarea-autosize icon indicating copy to clipboard operation
react-textarea-autosize copied to clipboard

Can't mount with Enzyme

Open delucca opened this issue 4 years ago • 5 comments

Hi!

I'm trying to unit test a simple component that I've coded using this lib, but as soon as I try to mount it (instead of shallow) I got the following error:

 FAIL  src/components/KeyResult/Single/Sections/AddComment/input.spec.tsx
  component interations
    ✕ should use a full rounded box when the input has a single line (48 ms)
    ○ skipped should descrease the border radius based on the number of lines of the input
    ○ skipped should change the border color if the input is focused
    ○ skipped should change the box shadow if the input is focused
    ○ skipped should keep the same border color if the input is not focused
    ○ skipped should not have a box shadow if the input is not focused
    ○ skipped should keep the same border color if the input was focused, but it is not anymore
    ○ skipped should not have a box shadow if the input was focused, but it is not anymore
    ○ skipped should display a spinner if the component is being loaded
    ○ skipped should display a spinner if the user submitted the form

  ● component interations › should use a full rounded box when the input has a single line

    TypeError: The provided value is not of type 'Element'.

      at Object.exports.convert (node_modules/jsdom/lib/jsdom/living/generated/Element.js:26:9)
      at Window.getComputedStyle (node_modules/jsdom/lib/jsdom/browser/Window.js:644:19)
      at getSizingData (node_modules/react-textarea-autosize/dist/react-textarea-autosize.cjs.dev.js:113:22)
      at resizeTextarea (node_modules/react-textarea-autosize/dist/react-textarea-autosize.cjs.dev.js:183:109)
      at Object.<anonymous> (node_modules/jest-react-hooks-shallow/src/mock-use-effect/mock-use-effect.ts:33:31)
      at TextareaAutosize (node_modules/react-textarea-autosize/dist/react-textarea-autosize.cjs.dev.js:213:11)
      at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:14803:18)

  console.error
    Error: Uncaught [TypeError: The provided value is not of type 'Element'.]
        at reportException (/home/delucca/Code/delucca/execution-mode/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:62:24)
        at innerInvokeEventListeners (/home/delucca/Code/delucca/execution-mode/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:333:9)
        at invokeEventListeners (/home/delucca/Code/delucca/execution-mode/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
        at HTMLUnknownElementImpl._dispatch (/home/delucca/Code/delucca/execution-mode/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
        at HTMLUnknownElementImpl.dispatchEvent (/home/delucca/Code/delucca/execution-mode/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
        at HTMLUnknownElement.dispatchEvent (/home/delucca/Code/delucca/execution-mode/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34)
        at Object.invokeGuardedCallbackDev (/home/delucca/Code/delucca/execution-mode/node_modules/react-dom/cjs/react-dom.development.js:237:16)
        at invokeGuardedCallback (/home/delucca/Code/delucca/execution-mode/node_modules/react-dom/cjs/react-dom.development.js:292:31)
        at beginWork$1 (/home/delucca/Code/delucca/execution-mode/node_modules/react-dom/cjs/react-dom.development.js:23203:7)
        at performUnitOfWork (/home/delucca/Code/delucca/execution-mode/node_modules/react-dom/cjs/react-dom.development.js:22157:12) TypeError: The provided value is not of type 'Element'.
        at Object.exports.convert (/home/delucca/Code/delucca/execution-mode/node_modules/jsdom/lib/jsdom/living/generated/Element.js:26:9)
        at Window.getComputedStyle (/home/delucca/Code/delucca/execution-mode/node_modules/jsdom/lib/jsdom/browser/Window.js:644:19)
        at getSizingData (/home/delucca/Code/delucca/execution-mode/node_modules/react-textarea-autosize/dist/react-textarea-autosize.cjs.dev.js:113:22)
        at resizeTextarea (/home/delucca/Code/delucca/execution-mode/node_modules/react-textarea-autosize/dist/react-textarea-autosize.cjs.dev.js:183:109)
        at Object.<anonymous> (/home/delucca/Code/delucca/execution-mode/node_modules/jest-react-hooks-shallow/src/mock-use-effect/mock-use-effect.ts:33:31)
        at /home/delucca/Code/delucca/execution-mode/node_modules/jest-mock/build/index.js:444:39
        at Object.<anonymous> (/home/delucca/Code/delucca/execution-mode/node_modules/jest-mock/build/index.js:452:13)
        at Object.mockConstructor (/home/delucca/Code/delucca/execution-mode/node_modules/jest-mock/build/index.js:166:19)
        at TextareaAutosize (/home/delucca/Code/delucca/execution-mode/node_modules/react-textarea-autosize/dist/react-textarea-autosize.cjs.dev.js:213:11)
        at renderWithHooks (/home/delucca/Code/delucca/execution-mode/node_modules/react-dom/cjs/react-dom.development.js:14803:18)

      at VirtualConsole.<anonymous> (node_modules/jsdom/lib/jsdom/virtual-console.js:29:45)
      at reportException (node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:28)
      at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:333:9)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
      at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)

  console.error
    The above error occurred in the <ForwardRef(TextareaAutosize)> component:
        in ForwardRef(TextareaAutosize) (created by KeyResultSectionAddCommentInput)
        in div (created by Box)
        in Box (created by KeyResultSectionAddCommentInput)
        in KeyResultSectionAddCommentInput
        in form (created by Form)
        in Form
        in Formik (created by WrapperComponent)
        in WrapperComponent

    Consider adding an error boundary to your tree to customize error handling behavior.
    Visit https://fb.me/react-error-boundaries to learn more about error boundaries.

      at logCapturedError (node_modules/react-dom/cjs/react-dom.development.js:19527:21)
      at logError (node_modules/react-dom/cjs/react-dom.development.js:19564:5)
      at update.callback (node_modules/react-dom/cjs/react-dom.development.js:20708:5)
      at callCallback (node_modules/react-dom/cjs/react-dom.development.js:12490:12)
      at commitUpdateQueue (node_modules/react-dom/cjs/react-dom.development.js:12511:9)
      at commitLifeCycles (node_modules/react-dom/cjs/react-dom.development.js:19883:11)
      at commitLayoutEffects (node_modules/react-dom/cjs/react-dom.development.js:22803:7)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 9 skipped, 10 total
Snapshots:   0 total
Time:        2.214 s
Ran all test suites matching /AddComment\/input/i.

IMPORTANT: I've already added common JSDom properties to my jest global. Here is my setup tests file:

import enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import enableHooks from 'jest-react-hooks-shallow'
import fetch from 'node-fetch'
import { DOMWindow, JSDOM } from 'jsdom'

enableHooks(jest)

enzyme.configure({
  adapter: new Adapter(),
})

interface JestGlobal extends NodeJS.Global {
  fetch: typeof fetch
  document: Document
  window: DOMWindow
  navigator: Navigator
}

declare let global: JestGlobal

global.fetch = fetch

jest.mock('react-intl', () => {
  const reactIntl = jest.requireActual('react-intl')
  const intl = reactIntl.createIntl({
    locale: 'en',
  })

  return {
    ...reactIntl,
    useIntl: () => intl,
  }
})

const dom = new JSDOM('<!doctype html><html><body></body></html>')
global.window = dom.window
global.document = global.window.document
global.navigator = global.window.navigator

delucca avatar Feb 09 '21 17:02 delucca

My suspicion is that your test environment doesn't assign the internal ref correctly. Maybe this would work: https://github.com/Andarist/react-textarea-autosize#how-to-test-it-with-jest-and-react-test-renderer-if-you-need-ref but I can't be sure.

Andarist avatar Feb 09 '21 18:02 Andarist

My suspicion is that your test environment doesn't assign the internal ref correctly. Maybe this would work: https://github.com/Andarist/react-textarea-autosize#how-to-test-it-with-jest-and-react-test-renderer-if-you-need-ref but I can't be sure.

Oh, I see. So I need to assign the ref to use autoFocus?

Strange, I'm not assigning it but the autoFocus is working 🤔

For reference, this is how I'm using the TextareAutosize component:

...
      <TextareaAutosize
        autoFocus
        value={values.text}
        maxRows={14}
        style={{
          resize: 'none',
          width: '100%',
          padding: '0.5rem 1rem',
          outline: 'none',
        }}
        onHeightChange={handleHeightChange as any}
        onFocus={handleFocus}
        onBlur={handleBlur}
        onChange={handleChange}
      />
...

(btw, the onHeightChange type is wrong, it considers that the callback function should receive only a single height attribute, but actually it passes 2 arguments)

My test was just a simple test, mounting it. Like:

it('sample', () => {
  const wrapper = enzyme.mount(<KeyResultAddComment />)
})

So, I need to add something like the ref={(tag) => (this.textarea = tag)} snippet in my TextareAutosize component to fix this? Before this post my understanding was that I would need it if I want to programmatically change the focus of my input.

delucca avatar Feb 09 '21 18:02 delucca

autoFocus "just works" because we forward that prop to the underlying DOM element.

(btw, the onHeightChange type is wrong, it considers that the callback function should receive only a single height attribute, but actually it passes 2 arguments)

We type it as a function that is called with 2 arguments: https://github.com/Andarist/react-textarea-autosize/blob/90196efc7d05821ffd3823af26fea5b7c8f04217/src/index.tsx#L22

So, I need to add something like the ref={(tag) => (this.textarea = tag)} snippet in my TextareAutosize component to fix this?

No. You might need to provide a mock for the ref - just how it has been done in the linked section. Don't confuse this with getting access to the ref in your code. This is just an oddity that might be required in tests and not in your application code. I'm not sure if that's the problem - it's the only thing that comes to my mind right now though and I don't have time to setup a project with Enzyme to test this stuff out.

Andarist avatar Feb 10 '21 06:02 Andarist

No. You might need to provide a mock for the ref - just how it has been done in the linked section. Don't confuse this with getting access to the ref in your code. This is just an oddity that might be required in tests and not in your application code. I'm not sure if that's the problem - it's the only thing that comes to my mind right now though and I don't have time to setup a project with Enzyme to test this stuff out.

Sorry, but I'm not quite sure how can I do that. I'm mounting the entire component (not only TextareaAutosize). So, why should I pass ref only during tests? Also, there are any examples on how to do it? I don't know how to mock that ref only in my test suite.

Thanks for your attention, time and patience :)

delucca avatar Feb 10 '21 18:02 delucca

@delucca Same. Have you resolved this issue yet?

wonder-boooy avatar Nov 16 '23 04:11 wonder-boooy