如何在酶中等待私人功能的承诺?

Len*_*man 7 fetch reactjs jestjs enzyme

我是 React 和任何 JavaScript 测试框架的新手。

我有一个简单的组件,可以从 API 检索项目并将其显示在屏幕上。

函数 getItems() 是从 componentWillMount 调用的。

是否可以等到 getItems() 完成后再做出断言?

项目详细信息.js

class ItemDetails extends Component {
    constructor(props) {
        super(props);
        this.state = {
            details: ''
        }
    }

    componentWillMount() {
        this.getItem();
    }

    getItem() {
        const itemId = this.props.match.params.id;
        fetch(`/api/items/${itemId}`)
            .then(res => res.json())
            .then(details => this.setState({ details }));
    }

    render() {
        const details = this.state.details;
        return (
            <div>
                <h1>{details.title}</h1>
                ...
            </div>
        );
    }
}

export default ItemDetails;
Run Code Online (Sandbox Code Playgroud)

ItemDetails.test.js

describe('ItemDetails', () => {
    it('should render a div with title', () => {
        const details = {
            _id: 1,
            title: 'ItemName'
        };
        fetch.mockResponseOnce(JSON.stringify(details));
        const wrapper = mount(<ItemDetails match={{ params: {id: 1} }} />);
        expect(wrapper.find('div').find('h1').text()).toBe('ItemName');

    });
});
Run Code Online (Sandbox Code Playgroud)

qni*_*lab 9

上面的答案有效,但它需要测试实现细节:

  • 根据经验,访问包装器(.instance())的实例并调用update()是测试的味道,在我看来,这些测试对被测代码的工作方式了解太多,它不是在测试行为,而是在测试实现
  • 让方法返回一个承诺并在执行期望之前等待该承诺会破坏方法的隐私:它使代码难以重构

您真正想要的是等待所有承诺得到解决,而不访问这些承诺的句柄(这会破坏隐私)。尝试这个

const wait = () => new Promise(resolve => setTimeout(resolve));

it('does something', () => {
  renderFnThatCallsAPromiseInternally();

  return wait().then(() => {
    expect(somethingDependentOnPromiseExecution).to.be.present();
  });
});
Run Code Online (Sandbox Code Playgroud)

这将等待所有内部承诺解决,前提wait是在调用排队承诺(呈现组件)的代码之后调用。原因在于 JS 事件循环的工作方式,它很挑剔,但 Jake Archibald 在本次演讲中对此进行了很好的解释:https ://www.youtube.com/watch?v=cCOL7MC4Pl0 。

希望有帮助。


Tom*_*zyk 3

你能尝试一下吗:

describe('ItemDetails', () => {
    it('should render a div with title', () => {
        const details = {
            _id: 1,
            title: 'ItemName'
        };
        fetch.mockResponseOnce(JSON.stringify(details));
        const wrapper = shallow(<ItemDetails match={{ params: {id: 1} }} />);      

        // manually call function
        wrapper.instance().getItem();
        // update to re-render component
        wrapper.update();

        expect(wrapper.find('div').find('h1').text()).toBe('ItemName');    
    });
});
Run Code Online (Sandbox Code Playgroud)

如果它没有帮助,我认为你需要从你的函数返回 Promise (基于这个例子):

getItem() {
    const itemId = this.props.match.params.id;
    return fetch(`/api/items/${itemId}`)
        .then(res => res.json())
        .then(details => this.setState({ details }));
}


describe('ItemDetails', () => {
    it('should render a div with title', () => {
        const details = {
            _id: 1,
            title: 'ItemName'
        };
        fetch.mockResponse(JSON.stringify(details)); //response gets called twice
        const wrapper = mount(<ItemDetails match={{ params: {id: 1} }} />);

        // return Promise so Jest will wait until it's finished
        return wrapper.instance().getItem().then(() => {
          wrapper.update();
        }).then(() => {
         expect(wrapper.find('div').find('h1').text()).toBe('ItemName'); 
        })
    });
});
Run Code Online (Sandbox Code Playgroud)