2017-02-15 2 views
3

Я, похоже, не могу понять это. Я использую приложение create-react-app, и он встроен в тестовый runner Jest. Для всего синхронного кода это работает очень хорошо, но, когда насмехаются обещания, я не могу заставить его работать.Тестирование React Async with Jest и create-react-app

Реактивный компонент имеет форму, в которой я могу моделировать подачу.

Восстановить фрагменты кода компонента.

//Top of the page 
import {auth} from '../../lib/API_V2' 
// ... // 

// Handle submit runs when the form is submitted 
handleSubmit = (event) => { 
    console.log('submit') 
    event.preventDefault() 
    this.setState(prevState => ({ 
    ...prevState, 
    loading: true 
    })) 
    console.log('stateSet') 
    auth(this.state.userName, this.state.password) 
    .then(results => { 
     // NEVER RUNS 
     console.log('then') 
     // stuff omitted 
     this.setState(prevState => ({ 
     ...prevState, 
     loading: false 
     })) 
     this.props.afterAuth() 
    }) 
    .catch(() => { 
    // also never runs 
    // omitted 
    this.setState(prevState => ({ 
     ...prevState, 
     loading: false 
    })) 
    this.props.afterAuth() 
    }) 
} 

Код испытания

jest.mock('../../lib/API_V2') 
it.only(`should mock a login`,() => { 
    const myMock = jest.fn() 
    const authComp = mount(<AuthComponent afterAuth={myMock}/>) 

    authComp.find('.userName').simulate('change', {target: {value: 'userName'}}) 
    authComp.find('.password').simulate('change', {target: {value: 'password'}}) 
    expect(authComp.state().userName).toEqual('userName') 
    expect(authComp.state().password).toEqual('password') 
    authComp.find('[type="submit"]').get(0).click() 
    expect(myMock.mock.calls.length).toBe(1) // FAILS 
}) 

В API Lib возвращает обещание. Вместо этого у меня есть __mocks__/API_V2.js рядом с ним. Это выглядит так:

function auth (lastname, accountNumber) { 
    console.log('yay!?') 
    return new Promise((resolve) => { 
    resolve({ 
     accountNumber, 
     lastName: lastname 
    }) 
    }) 
}  

Мой тестовый код никогда не запускается. Если я вхожу в фальшивую функцию, я получаю function auth() {return mockConstructor.apply(this,arguments);}

Я попытался выполнить инструкции https://facebook.github.io/jest/docs/tutorial-async.html, но кажется, что мои макетные методы не вызываются. И ни один из них не является реальным методом. Вместо этого мой вызов auth() возвращает неопределенный.

У кого-нибудь есть идеи?

- Дополнительная информация -

src 
    Components 
    AuthComponent 
     AuthComponent.js 
     AuthComponent.test.js 
     index.js 
    Lib 
    API_V2 
     API_V2.js 
     index.js 
     __mocks__ 
     API_V2.js 
+0

Я закончил вручную насмешливый его вместо того, чтобы использовать каталог __mocks__. jest.mock ('../../ lib/API_V2,() => {auth: function ...}) – TheMcMurder

ответ

3

Я думаю, что вы ударяя ошибка, связанная с этим вопросом: https://github.com/facebook/jest/issues/2070

Так как вы на самом деле пытаетесь импортировать файл с именем API_V2/index.js, вам нужно чтобы высмеять index.js. Однако у вас будет очень плохое время, так как это будет действительный макет для каждого файла index.js, который вы пытаетесь высмеять.

Лучший способ сделать это на данный момент, чтобы переписать некоторые из кода, чтобы использовать зависимость инъекции и переходят в издеваться к тому, что нужно использовать { auth }

+0

По моему опыту это просто раздражало меня предупреждениями, но одно и то же имя насмешливо не получило «обмен». –

+0

> Однако у вас будет очень плохое время, так как это будет действительный макет для каждого файла index.js, который вы пытаетесь высмеять. Я не думаю, что это правильно. Если он поместил его в 'Lib/API_V2/__ mocks __/index.js', который должен работать и только издеваться над' Lib/API_V2/index.js' – kentcdodds

+0

Извините, просто посмотрел на указанную ошибку. Это раздражает. Может быть, просто переименуйте файл? ;-) – kentcdodds

2

В новом Promise от вашего издеваться, несмотря на то, вы немедленно решаете, это разрешение не происходит синхронно. Promise callback всегда запускается в виде микрозадачи , поэтому, когда вы имитируете клик в своем тесте, обратный вызов Promise в вашем макете еще не запущен (и поэтому myMock еще не был вызван). Вот почему ваше ожидание терпит неудачу.

Один (несколько хакерский) способ, которым вы могли бы обойти эту проблему, было бы с помощью setTimeout. setTimeout выдаст задание , и задачи всегда запускаются после микрозадач. Jest поддерживает асинхронные тесты по возвращению Обещания из it обратных вызовов, так что вы могли бы написать:

jest.mock('../../lib/API_V2') 
it.only(`should mock a login`,() => new Promise(resolve => { 
    const myMock = jest.fn() 
    const authComp = mount(<AuthComponent afterAuth={myMock}/>) 

    authComp.find('.userName').simulate('change', {target: {value: 'userName'}}) 
    authComp.find('.password').simulate('change', {target: {value: 'password'}}) 
    expect(authComp.state().userName).toEqual('userName') 
    expect(authComp.state().password).toEqual('password') 
    authComp.find('[type="submit"]').get(0).click() 
    setTimeout(() => { 
    expect(myMock.mock.calls.length).toBe(1) 
    resolve() // Tell jest this test is done running 
    }, 0); 
})) 

Существует хорошее объяснение того, как задачи и microtasks работы здесь: https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

Смежные вопросы