代码之家  ›  专栏  ›  技术社区  ›  Lennert Hofman

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

  •  3
  • Lennert Hofman  · 技术社区  · 7 年前

    我是react和任何javascript测试框架的新手。

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

    从componentWillMount调用函数getItems()。

    是否可以等到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;
    

    项目详细信息。测验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');
    
        });
    });
    
    2 回复  |  直到 7 年前
        1
  •  5
  •   qnilab    5 年前

    上述答案可行,但需要测试实现细节:

    • 根据经验,访问包装器实例( .instance() )和呼叫 update() 在我看来,这不是在测试行为,而是在测试实现
    • 让方法返回一个承诺并在执行该期望之前等待该承诺会破坏方法的隐私:这会使代码难以重构

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

    const wait = () => new Promise(resolve => setTimeout(resolve));
    
    it('does something', () => {
      renderFnThatCallsAPromiseInternally();
    
      return wait().then(() => {
        expect(somethingDependentOnPromiseExecution).to.be.present();
      });
    });
    

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

    希望这有帮助。

        2
  •  2
  •   Lennert Hofman    7 年前

    你能试试吗:

    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');    
        });
    });
    

    如果没有帮助,我想你需要从你的职能中回报承诺( base on this example ):

    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'); 
            })
        });
    });