Source:  Twitter logo

I'm trying to do unit testing to a component using enzyme shallow rendering. Trying to test state activeTab of the component and it throws TypeError: Cannot read property state. my component Accordion. Accordion component jsx code

 class Accordion extends Component {
    constructor(props) {
        super(props)
        this.state = {
            activeTab: 0
        }
    }

    static defaultProps = {
        tabs: [{title: 'Status'}, {title: 'Movement'}]
    }

    render() {
        const { tabs } = this.props
            , { activeTab } = this.state
        return (
            <div className={`accordion`}>
                {tabs.map((t, i) => {
                    const activeClass = activeTab === i ? `accordion--tab__active` : ''
                    return(
                        <section key={i} className={`accordion--tab ${activeClass}`}>
                            <header className={`accordion--header`}>
                                <h4 className={`accordion--title`}>
                                    <button onClick={() => {this._selectAccordion(i)}}>{t.title}</button>
                                </h4>
                            </header>
                            <div className="accordion--content">
                                {t.title}
                                Content
                            </div>
                        </section>
                    )
                })}
            </div>
        )
    }
    _selectAccordion = activeTab => {this.setState({activeTab})}
}

export default Accordion

and Accordion.react.test.js

import { shallow } from 'enzyme'
import Accordion from './components/Accordion'

test('Accordion component', () => {
    const component = shallow(<Accordion name={`Main`}/>)
    expect(component.state('activeTab')).equals(0)
})

This could be a this scoping issue. With event handlers in React, you have to bind the event handler in the constructor to "this". Here is some info from React's docs about it:

You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.

This is not React-specific behavior; it is a part of how functions work in JavaScript. Generally, if you refer to a method without () after it, such as onClick={this.handleClick}, you should bind that method.

class Accordion extends Component {
    constructor(props) {
        super(props)
        this.state = {
            activeTab: 0
        }

        // This binding is necessary to make `this` work in the callback
        this._selectAccordion = this._selectAccordion.bind(this);
    }

    static defaultProps = {
        tabs: [{title: 'Status'}, {title: 'Movement'}]
    }

        _selectAccordion(activeTab){
            this.setState({activeTab : activeTab})
        }

    render() {
        const { tabs } = this.props,
        { activeTab } = this.state
        return (
            <div className={`accordion`}>
                {tabs.map((t, i) => {
                    const activeClass = activeTab === i ? `accordion--tab__active` : ''
                    return(
                        <section key={i} className={`accordion--tab ${activeClass}`}>
                            <header className={`accordion--header`}>
                                <h4 className={`accordion--title`}>
                                    <button onClick={() => {this._selectAccordion(i)}}>{t.title}</button>
                                </h4>
                            </header>
                            <div className="accordion--content">
                                {t.title}
                                Content
                            </div>
                        </section>
                    )
                })}
            </div>
        )
    }

}
3 users liked answer #0dislike answer #03
Dream_Cap profile pic
Dream_Cap

Your tests should verify how the component works but not "how to change a state". You need to throw new props into your component and get a result, and the result is expected.

I've tested my components with snapshots

This is an example of my current project

describe('<Component />', () => {
  it('Page rendered', () => {
    const rendered = renderComponent({
      ...testProps,
      loadDataList,
      loading: true,
    });

    expect(rendered).toMatchSnapshot();
  });
});
1 users liked answer #1dislike answer #11
Daniel Rosenberg profile pic
Daniel Rosenberg

Copyright © 2022 QueryThreads

All content on Query Threads is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).