2016-12-24 1 views
2

Ich habe folgende redux Saga, die einen API-Aufruf macht und verarbeitet die Ergebnisse:manuell einen Wert an einen Generator vorbei führt zu unerwarteten Ergebnisse mit Scherz Tests

import { takeLatest } from 'redux-saga' 
import { call, put } from 'redux-saga/effects' 
import { normalize, arrayOf } from 'normalizr' 
import * as actions from './actions' 
import * as schemas from './schemas' 
import * as types from './actionTypes' 
import { api, constants as apiConstants } from '../../services/api' 

export function* fetchWorks() { 
    const { response, error } = yield call(api.getJson, apiConstants.WORKS_ENDPOINT) 
    if (response) { 
    const normalized = normalize(response.items, arrayOf(schemas.works)) 
    yield put(actions.fetchWorksSuccess(normalized)) 
    } else { 
    yield put(actions.fetchWorksFail(error)) 
    } 
} 

Ich teste, ob alles mit diesem Scherz funktioniert Tests:

import { takeLatest } from 'redux-saga' 
import { call, put } from 'redux-saga/effects' 
import * as sagas from './sagas' 
import * as actions from './actions' 
import * as types from './actionTypes' 
import { api, constants as apiConstants } from '../../services/api' 

describe('works saga',() => { 
    describe('fetchWorks',() => { 
    it('should fetch data',() => { 
     const generator = sagas.fetchWorks() 
     const actual = generator.next().value 
     const expected = call(api.getJson, apiConstants.WORKS_ENDPOINT) 
     expect(actual).toEqual(expected) 
    }) 

    // this test requires me to pass a response object to the generator 
    it('should put fetchWorksSuccess on a response',() => { 
     // so I create it here 
     const response = { 
     items: [{ 
      sys: { id: '1' }, 
      fields: { content: 'content' } 
     }] 
     } 
     const generator = sagas.fetchWorks() 
     const expected = put(actions.fetchWorksSuccess()) 
     // but I would expect to pass it here  
     generator.next() 
     // but actually the test only succeeds if I pass it here 
     const actual = generator.next({ response }).value 
     expect(actual).toEqual(expected) 
    }) 

    // same goes for this test 
    it('should put fetchWorksFail on errors',() => { 
     const error = new Error('Something went wrong') 
     const generator = sagas.fetchWorks() 
     const expected = put(actions.fetchWorksFail()) 
     generator.next() 
     const actual = generator.next({ error }).value 
     expect(actual).toEqual(expected) 
    }) 
    }) 
}) 

jedoch für die 'should put fetchWorksSuccess on a response' und 'should put fetchWorksFail on errors' Tests habe ich jeweils eine {response} und {error} Objekt in jedem Generator manuell zu übergeben.

Ich verstehe, dass diese Objekte notwendig sind (wegen der if-Anweisung, die prüft, ob es eine Antwort gibt), aber ich verstehe nicht, warum ich es an die zweite .next() anstelle der ersten weitergeben muss? Weil die Art, wie ich es sehe, die erste yield ergibt das Antwort- oder Fehlerobjekt, nicht die zweite. Versteht jemand warum?

Antwort

1

Dies ist keine React-Sache, es ist eine Generator-Sache.

Der erste Aufruf von generator.next() startet den Generator, nicht Rückkehr aus der Ausbeute Aufruf:

>>> function *example_generator() { 
    console.log('before first yield', Array.slice(arguments)); 
    var first_yield = yield 'first'; 
    console.log('first yield returned', first_yield); 
    var second_yield = yield 'second'; 
    console.log('second yield returned', second_yield); 
    return 'done'; 
} 
>>> generator = example_generator("generator", "creation") 
Generator {} 
>>> generator.next("first next") 
before first yield Array [ "generator", "creation" ] 
Object { value: "first", done: false } 
>>> generator.next("second next") 
first yield returned second next 
Object { value: "second", done: false } 
>>> generator.next("third next") 
second yield returned third next 
Object { value: "done", done: true } 

Ihr erster Anruf zu fetchWorks() das Generator-Objekt erstellt, aber nicht startet tatsächlich den Generator.

Denken Sie darüber nach - der erste Anruf an next() gibt Ihnen den Wert an die erste weitergegeben yield; das Argument gegeben der zweite Aufruf an next() können Sie den Rückgabewert der ersten yield angeben.

+0

Ah ok. Die MDN-Dokumente haben mir nicht wirklich geholfen, das zu verstehen. Ihre Antwort, kombiniert mit diesem Artikel (https://davidwalsh.name/es6-generators) und dem Experimentieren mit Codepen (https://codepen.io/anon/pen/GNbRpe?editors=0010) hat mir geholfen, es zu verstehen. Vielen Dank! –

Verwandte Themen