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

Unable to cover the onClickAway function while testing #24783

Closed
2 tasks done
BrinsterAman opened this issue Feb 5, 2021 · 3 comments
Closed
2 tasks done

Unable to cover the onClickAway function while testing #24783

BrinsterAman opened this issue Feb 5, 2021 · 3 comments

Comments

@BrinsterAman
Copy link

BrinsterAman commented Feb 5, 2021

  • The issue is present in the latest release.
  • I have searched the issues of this repository and believe that this is not a duplicate.

Current Behavior 😯

I am unable to cover the ClickAwayListener's onClickAway function, though that function is getting triggered. I am using React testing library and Jest for testing.

Expected Behavior 🤔

Should cover lines while testing

Steps to Reproduce 🕹

I dont have issues using ClickAwayListener - it is working fine in code, but having issues while covering callback handler in unit tests.
Being proprietary code, cannot share in sandbox. Adding details to version of material and react and testing library below

Your Environment 🌎

`npx @material-ui/envinfo`
  Don't forget to mention which browser you used.
  Output from `npx @material-ui/envinfo` goes here.

"@material-ui/core ": "^4.11.0",
"@testing-library/dom": "^7.24.5",
"@testing-library/jest-dom": "^4.2.0",
"@testing-library/react": "^9.3.0",
"@testing-library/user-event": "^12.0.11",
"react": "^16.11.0",
"chrome": "^86.0.4240.75"

@BrinsterAman BrinsterAman added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Feb 5, 2021
@eps1lon
Copy link
Member

eps1lon commented Feb 5, 2021

We currently have to defer "arming" of the clickaway listener to work around a react bug. https://github.com/mui-org/material-ui/blob/f0e657bcd52071fb11b27437053ee6110a69b285/packages/material-ui/src/ClickAwayListener/ClickAwayListener.test.js#L23-L37 explains this in more detail and includes how you would "arm" the clickaway listener. The whole file should help you understand how to test clickaway logic implemented by our ClickawayListener.

Feel free to ask more questions here. I'm closing since we can't do much about it other than answer questions.

@bsides
Copy link

bsides commented Dec 21, 2021

Not trying to reopening this, but I'm still curious on how does it work? Should I have sinon and fakeTimers? Does anyone have a quicker way to do this without having to get another package?

@LFFATE
Copy link

LFFATE commented Jan 13, 2022

Should I have sinon and fakeTimers?

Possibly. But you can use jest fake timers. This is my way to test (jest + react-testing-library):

import React from 'react'
import '@testing-library/jest-dom'
import { render, waitFor, fireEvent } from '@testing-library/react'

beforeEach(() => {
  jest.useFakeTimers('modern')
})

afterEach(() => {
  jest.runOnlyPendingTimers()
  jest.useRealTimers()
})

import ClickOutsideListener, {IProps} from './ClickOutsideListener'

const setup = (customProps?: Partial<IProps>) => {

  const props: IProps = {
   ...{
      onClickOutside: jest.fn(),
    },
    ...customProps,
  }

  return {
    render: render(
      <>
        <ClickOutsideListener {...props}>
          <h1>Content by text</h1>
        </ClickOutsideListener>
        <div>
          <span>Any document text</span>
          <button>button outside</button>
        </div>
      </>
    ),
    props,
  }
}

const withIncreasedTimeout = { timeout: 5000 }

describe('ClickOutsideListener component', () => {
  it('should render content inside', async () => {
    const { render, props } = setup()
    jest.runAllTimers()
    const content = await waitFor(() => render.getByText('Content by text'), withIncreasedTimeout)

    expect(content).toBeInTheDocument()
    expect(props.onClickOutside).not.toBeCalled()
  })
  it('should call onClickOutside on outside click', async () => {
    const { render, props } = setup()
    jest.runAllTimers()
    const outsideElement = await waitFor(() => render.getByText('button outside'), withIncreasedTimeout)

    fireEvent.click(outsideElement)
    jest.runAllTimers()

    await waitFor(() => expect(props.onClickOutside).toBeCalledTimes(1), withIncreasedTimeout)
  })
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants