如何使用玩笑在 redux saga 中测试嵌套的 firestore 批处理函数?

How to test nested firestore batch functions in redux saga using jest?

在一个反应​​项目中,我有一个 redux-saga 文件,我在 firebase 后端 (firestore) 上创建并保存新项目。

在那个 saga 函数中,我首先获取一个新的写入批处理对象,然后更新 firestore 文档,最后提交批处理。

佐贺工人

import { call, put } from 'redux-saga/effects'
import { db } from './firebase' // db: firebase.firestore()

export function* mySaga(item) {
    try {
        // init firestore batch.
        const batch = yield call(db, db.batch)

        // Set firestore document and save new item.
        const itemRef = yield call ([db, db.doc], `/items/${item.id}`)
        yield call([batch, batch.set], itemRef , item)

        // Commit the batch.
        yield call([batch, batch.commit])


        yield put({type: 'success'})
    } catch (err) {
        yield put({type: 'error', payload: err})
    }
}

佐贺工人的考验

import * as sagas from './mySaga'

describe('mySaga', () => {
    const spyOnDoc = jest.spyOn(db, 'doc')

    it('handles item creation', async () => {

        const dispatched = []
        await runSaga(
            { dispatch: action => dispatched.push(action) },
            sagas.mySaga,
        ).toPromise()

        expect(spyOnDoc).toHaveBeenCalledTimes(1)

        // !!! Here I need to check for nested set and commit functions of the batch object created in saga.

    })
})

我如何测试批处理函数的嵌套 "set" 和 "commit" 函数以检查它们是否被调用 x 次并使用正确的输入调用?

如有任何帮助,我们将不胜感激。

After several attemps I figured out a way to accomplishing this kind of tests. In case if someone needs this solution, here it is.

db.batch() 方法创建一个 firebase.firestore.WriteBatch 对象。而这个对象有commitsetupdatedelete方法。可以找到更多详细信息 here.

最终 Saga 工人测试

import * as sagas from './mySaga'
import { db } from './firebase' // db: firebase.firestore()

describe('mySaga', () => {
    const spyOnDoc = jest.spyOn(db, 'doc')

    // We are mocking the methods of this predefined object.
    firestore.WriteBatch.set = jest.fn()
    firestore.WriteBatch.commit = jest.fn()

    // Then we implement those created mocks into the batch's mock implementation.
    const spyOnBatch = jest.spyOn(db, 'batch').mockImplementation(() => ({
        set: firestore.WriteBatch.set,
        commit: firestore.WriteBatch.commit,
    }))

    it('handles item creation', async () => {

        const dispatched = []
        await runSaga(
            { dispatch: action => dispatched.push(action) },
            sagas.mySaga,
            {id: 123} // Item
        ).toPromise()

        expect(spyOnDoc).toHaveBeenCalledTimes(1)

        // Finally, we can test those nested object functions as below.
        expect(firestore.WriteBatch.commit).toHaveBeenCalledTimes(1)
        expect(firestore.WriteBatch.set).toHaveBeenCalledTimes(1)
        expect(firestore.WriteBatch.set).toHaveBeenCalledWith(db.doc('/items/123'), {id: 123})

    })
})