如何使用Enzyme测试react-truncate的展开收起功能
I've run into this exact issue before with react-truncate and Enzyme shallow rendering! The problem is that shallow rendering doesn't render the internal elements of the Truncate component, so your "Read more" link is hidden inside the ellipsis prop of Truncate and not directly accessible via shallow queries. Here's how to fix this and implement your full test flow:
Why Your Initial Approach Failed
When you use shallow(), Enzyme only renders your ReadMore component and stops at the Truncate component—it doesn't dive into Truncate's internal JSX. That's why your debug output only shows the Truncate element, and calling wrapper.toggleLines() returns undefined (you need to access the component instance first, but even then, you still need to trigger the click through the actual UI element or prop).
Solution 1: Use Full Rendering with mount()
The most straightforward way is to use mount() instead of shallow() to render the entire component tree, including the Truncate component's internal elements. This lets you directly query for the "Read more" and "Show less" links.
Here's the complete test code:
import React from 'react'; import { mount } from 'enzyme'; import ReadMore from './ReadMore'; describe('ReadMore Component', () => { const longText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.'; it('should initialize with expanded state as false', () => { const wrapper = mount(<ReadMore>{longText}</ReadMore>); expect(wrapper.state('expanded')).toBe(false); }); it('should set expanded to true when "Read more" is clicked', () => { const wrapper = mount(<ReadMore>{longText}</ReadMore>); // Find the "Read more" link and simulate click const readMoreLink = wrapper.find('a').filterWhere(node => node.text() === 'Read more'); readMoreLink.simulate('click', { preventDefault: () => {} }); expect(wrapper.state('expanded')).toBe(true); }); it('should set expanded back to false when "Show less" is clicked', () => { const wrapper = mount(<ReadMore>{longText}</ReadMore>); // First expand the component const readMoreLink = wrapper.find('a').filterWhere(node => node.text() === 'Read more'); readMoreLink.simulate('click', { preventDefault: () => {} }); // Now find and click "Show less" const showLessLink = wrapper.find('a').filterWhere(node => node.text() === 'Show less'); showLessLink.simulate('click', { preventDefault: () => {} }); expect(wrapper.state('expanded')).toBe(false); }); });
Solution 2: Use Shallow Rendering with Prop Access
If you prefer to keep using shallow() (for faster tests), you can access the ellipsis prop passed to Truncate, which contains your "Read more" link. You can then extract the onClick handler from that prop and trigger it directly:
import React from 'react'; import { shallow } from 'enzyme'; import ReadMore from './ReadMore'; import Truncate from 'react-truncate'; describe('ReadMore Component (Shallow)', () => { const longText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.'; it('should initialize with expanded state as false', () => { const wrapper = shallow(<ReadMore>{longText}</ReadMore>); expect(wrapper.state('expanded')).toBe(false); }); it('should set expanded to true when "Read more" is triggered', () => { const wrapper = shallow(<ReadMore>{longText}</ReadMore>); // Get the Truncate component from the shallow render const truncateComponent = wrapper.find(Truncate); // Extract the ellipsis prop, which is your span with the "Read more" link const ellipsisElement = truncateComponent.prop('ellipsis'); // Trigger the onClick handler of the link (pass a mock event) ellipsisElement.props.children.props.onClick({ preventDefault: () => {} }); expect(wrapper.state('expanded')).toBe(true); }); it('should set expanded back to false when "Show less" is triggered', () => { const wrapper = shallow(<ReadMore>{longText}</ReadMore>); // First expand the component const truncateComponent = wrapper.find(Truncate); const ellipsisElement = truncateComponent.prop('ellipsis'); ellipsisElement.props.children.props.onClick({ preventDefault: () => {} }); expect(wrapper.state('expanded')).toBe(true); // Now trigger the "Show less" link const showLessElement = wrapper.findWhere(node => node.prop('children') === 'Show less'); showLessElement.props().onClick({ preventDefault: () => {} }); expect(wrapper.state('expanded')).toBe(false); }); });
Key Notes
- When simulating clicks, always pass a mock
eventobject withpreventDefault()—yourtoggleLinesmethod callsevent.preventDefault(), so omitting this will throw an error. - For the "Show less" link in shallow rendering, you can use
findWhere()to locate the element by its child text, since it's rendered directly in yourReadMorecomponent's JSX.
内容的提问来源于stack exchange,提问作者user988544

