enzymejs / enzyme

JavaScript Testing utilities for React
https://enzymejs.github.io/enzyme/
MIT License
19.95k stars 2.01k forks source link

.find not working, after click event, .html shows the component there #1496

Closed painedpineapple closed 6 years ago

painedpineapple commented 6 years ago

I have a button that, when clicked, triggers a <ul>. The actual component is working, but the test is not.

Components

export default class Nav extends React.Component<TProps, State> {
  constructor () {
    super()
    this.state = {
      servicesMenuOpen: false,
    }
  }
  toggleServicesMenu = (): void => this.setState(() => ({
    servicesMenuOpen: !this.state.servicesMenuOpen,
  }))
  render () {
    return (
      <Navigation
        desktop={this.props.desktop}
        route={this.props.route}
        pastHeader={this.props.pastHeader}
      >
        <Link to="/our-work/">Our Work</Link>
        <DropDownMenu><button onClick={this.toggleServicesMenu}>Our Services <Icon icon="keyboard_arrow_down" /></button>
          <ReactCSSTransitionGroup
            transitionName="animation-dropdown"
            transitionEnterTimeout={500}
            transitionLeaveTimeout={300}
          >
            {this.state.servicesMenuOpen ? <ServicesMenu /> : null}
          </ReactCSSTransitionGroup>
        </DropDownMenu>
        <Link to="/about-seamonster-studios/">About Us</Link>
        <Link to="/from-the-depths/">From the Depths...</Link>
        <Link to="/contact-seamonster-studios/">Contact Us</Link>
      </Navigation>
    )
  }
}

export const ServicesMenu = () => (
  <ul>
    <li><Link to="/web-design-uiux/">Web Design + UI/UX</Link></li>
    <li><Link to="/web-development/">Web Development</Link></li>
    <li><Link to="/ecommerce/">eCommerce</Link></li>
    <li><Link to="/design-studio/">Design Studio</Link></li>
    <li><Link to="/brand-lab/">Brand Lab</Link></li>
    <li><Link to="/assessment-consultation/">Assessment &amp; Consultation</Link></li>
  </ul>
)

Jest Test, with Enzyme

it('clicking <button> always toggles the <ul>', () => {
    const node = component().find('nav')
    const button = node.find('button')
    const dropdownWrapper = node.find('span')

    console.log(dropdownWrapper.html())

    button.simulate('click')

    console.log(dropdownWrapper.html())

    expect(dropdownWrapper.find('ul').length).toBeGreaterThan(0)
  })

Current behavior

Error –

 Nav › clicking <button> always toggles the <ServicesMenu>

    expect(received).toBeGreaterThan(expected)

    Expected value to be greater than:
      0
    Received:
      0

However, I know the <ul> is there, because when i console.log the .html() of the wrapper, i see it there.

Console.log before the simulated click

console.log src/components/Nav/Nav.test.js:55
      <span></span>

Console.log before the simulated click

onsole.log src/components/Nav/Nav.test.js:59
      <span><ul class="animation-dropdown-enter"><li><a href="/web-design-uiux/">Web Design + UI/UX</a></li><li><a href="/web-development/">Web Development</a></li><li><a href="/ecommerce/">eCommerce</a></li><li><a href="/design-studio/">Design Studio</a></li><li><a href="/brand-lab/">Brand Lab</a></li><li><a href="/assessment-consultation/">Assessment &amp; Consultation</a></li></ul></span>

Expected behavior

For .find('ul') to be found/have a length greater than 0

Your environment

API

Version

library version
Enzyme 3.3.0
React 16.2.0

Adapter

ljharb commented 6 years ago

simulate doesn't faithfully simulate anything; I'd recommend avoiding it. Use .prop('onClick')() instead.

Separately, in enzyme 3, you have to re-find from the root wrapper any time there's an update - so you can't reuse dropdownWrapper, and in fact you also have to store component() so you can find everything from there.

painedpineapple commented 6 years ago

Thanks @ljharb. I've updated my test with your suggestions, but i'm still getting the same outputs at both console.logs, as well as the test fails because it says the 'ul' has a length of 0, even though it can be seen in the log after the click.

Updated test:

it('clicking <button> always toggles the <ul>', () => {
    const node = component()

    console.log(node.find('nav').find('span').html())

    node.find('nav').find('button').prop('onClick')()

    console.log(node.find('nav').find('span').html())

    expect(node.find('nav').find('span').find('ul').length).toBeGreaterThan(0)
  })
ljharb commented 6 years ago

If you add node.update() after the onClick line? (If that doesn’t work, can you provide the code for the component function?)

ljharb commented 6 years ago

@logancalldev did you figure this out?

painedpineapple commented 6 years ago

Thanks for following up. The component's needs have actually changed, so this has become irrelevant. Thank you for your help!

carlafranca commented 1 year ago

I just found how to do it. You have to handle the click and not use the same variable to check the component prop

        const wrapper = mountWithTheme(
            <AccordionContainer>
                <Accordion title="Accordion 2" id="2" type="medium">
                    <div>Accordion content 2</div>
                </Accordion>
            </AccordionContainer>
        );
        //First click
        wrapper.find('.accordion-button').at(0).simulate('click');

        const button = wrapper.find('.accordion-button').at(0);
        const container = wrapper.find('.accordion-content').at(0);
        expect(button.prop('aria-expanded')).toBe(false); 
        expect(container.prop('aria-expanded')).toBe(true); 

        //Second click
        wrapper.find('.accordion-button').at(0).simulate('click');
        const buttonRefreshed = wrapper.find('.accordion-button').at(0);
        const containerfreshed = wrapper.find('.accordion-content').at(0);
        expect(buttonRefreshed.prop('aria-expanded')).toBe(false); 
        expect(containerfreshed.prop('aria-expanded')).toBe(false); 

When I was using the same variable to simulate the click, to validate it was all the same. Hope that helps other peeps that find this.