如何对这个 Redux thunk 进行单元测试?

2024-04-20

所以我有这个 Redux 动作创建器正在使用redux thunk中间件:

accountDetailsActions.js:

export function updateProduct(product) {
  return (dispatch, getState) => {
    const { accountDetails } = getState();

    dispatch({
      type: types.UPDATE_PRODUCT,
      stateOfResidence: accountDetails.stateOfResidence,
      product,
    });
  };
}

我该如何测试它?我正在使用chai用于测试的包。我在网上找到了一些资源,但不确定如何继续。这是我到目前为止的测试:

accountDetailsReducer.test.js:

describe('types.UPDATE_PRODUCT', () => {
    it('should update product when passed a product object', () => {
        //arrange
        const initialState = {
            product: {}
        };
        const product = {
            id: 1,
            accountTypeId: 1,
            officeRangeId: 1,
            additionalInfo: "",
            enabled: true
        };
        const action = actions.updateProduct(product);
        const store = mockStore({courses: []}, action);
        store.dispatch(action);
        //this is as far as I've gotten - how can I populate my newState variable in order to test the `product` field after running the thunk?
        //act
        const newState = accountDetailsReducer(initialState, action);
        //assert
        expect(newState.product).to.be.an('object');
        expect(newState.product).to.equal(product);
    });
});

我的 thunk 不执行任何异步操作。有什么建议吗?


如何对 Redux Thunk 进行单元测试

thunk 动作创建者的全部目的是在将来分派异步动作。使用 redux-thunk 时,一个好的方法是对开始和结束的异步流程进行建模,通过三个操作导致成功或错误。

尽管此示例使用 Mocha 和 Chai 进行测试,但您可以轻松地使用任何断言库或测试框架。

使用由我们的主要 thunk 动作创建者管理的多个动作对异步流程进行建模

在本示例中,我们假设您想要执行更新产品的异步操作,并且想要了解三个关键事项。

  • 当异步操作开始时
  • 当异步操作完成时
  • 异步操作是否成功或失败

好的,现在是时候根据操作生命周期的这些阶段来建模我们的 redux 操作了。请记住,这同样适用于所有异步操作,因此这通常适用于从 api 获取数据的 http 请求。

我们可以这样写我们的动作。

accountDetailsActions.js:

export function updateProductStarted (product) {
  return {
    type: 'UPDATE_PRODUCT_STARTED',
    product,
    stateOfResidence
  }
}

export function updateProductSuccessful (product, stateOfResidence, timeTaken) {
  return {
    type: 'PRODUCT_UPDATE_SUCCESSFUL',
    product,
    stateOfResidence
    timeTaken
  }
}

export function updateProductFailure (product, err) {
  return {
    product,
    stateOfResidence,
    err
  }
}

// our thunk action creator which dispatches the actions above asynchronously
export function updateProduct(product) {
  return dispatch => {
    const { accountDetails } = getState()
    const stateOfResidence = accountDetails.stateOfResidence

    // dispatch action as the async process has begun
    dispatch(updateProductStarted(product, stateOfResidence))

    return updateUser()
        .then(timeTaken => {
           dispatch(updateProductSuccessful(product, stateOfResidence, timeTaken)) 
        // Yay! dispatch action because it worked
      }
    })
    .catch(error => {
       // if our updateUser function ever rejected - currently never does -
       // oh no! dispatch action because of error
       dispatch(updateProductFailure(product, error))

    })
  }
}

请注意底部看起来忙碌的动作。这就是我们的 thunk 动作创建者。由于它返回一个函数,因此它是一个被 redux-thunk 中间件拦截的特殊操作。那个 thunk 动作创建者可以在未来的某个时刻派遣其他动作创建者。相当聪明。

现在我们已经编写了对异步过程(即用户更新)进行建模的操作。假设这个过程是一个返回承诺的函数调用,这将是当今处理异步过程的最常见方法。

定义我们使用 redux 操作建模的实际异步操作的逻辑

对于这个例子,我们将只创建一个返回承诺的通用函数。将其替换为更新用户或执行异步逻辑的实际函数。确保该函数返回一个承诺。

我们将使用下面定义的函数来创建一个工作的独立示例。要获得一个有效的示例,只需将此函数放入您的操作文件中,这样它就位于您的 thunk 操作创建者的范围内。

 // This is only an example to create asynchronism and record time taken
 function updateUser(){
      return new Promise( // Returns a promise will be fulfilled after a random interval
          function(resolve, reject) {
              window.setTimeout(
                  function() {
                      // We fulfill the promise with the time taken to fulfill
                      resolve(thisPromiseCount);
                  }, Math.random() * 2000 + 1000);
          }
      )
})

我们的测试文件

import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import chai from 'chai' // You can use any testing library
let expect = chai.expect;

import { updateProduct } from './accountDetailsActions.js'

const middlewares = [ thunk ]
const mockStore = configureMockStore(middlewares)

describe('Test thunk action creator', () => {
  it('expected actions should be dispatched on successful request', () => {
    const store = mockStore({})
    const expectedActions = [ 
        'updateProductStarted', 
        'updateProductSuccessful'
    ]

    return store.dispatch(fetchSomething())
      .then(() => {
        const actualActions = store.getActions().map(action => action.type)
        expect(actualActions).to.eql(expectedActions)
     })

  })

  it('expected actions should be dispatched on failed request', () => {
    const store = mockStore({})
    const expectedActions = [ 
        'updateProductStarted', 
        'updateProductFailure'
    ]

    return store.dispatch(fetchSomething())
      .then(() => {
        const actualActions = store.getActions().map(action => action.type)
        expect(actualActions).to.eql(expectedActions)
     })

  })
})
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何对这个 Redux thunk 进行单元测试? 的相关文章

  • D3.js分组条形图

    I am making a bar chart using D3 js like this source statcan gc ca http www statcan gc ca pub 12 593 x 2007001 figures f
  • OpenLayers:放大或缩小后,被破坏的特征会重新出现

    我有一个 OpenLayers Bing 地图应用程序 可以显示危险废物站点 用户可以单击链接来切换地图上站点的子站点 当我通过调用层上的 destroyFeatures 来关闭子站点 它们是向量层上的点 时 它们会按预期消失 但是 如果我
  • 无法实现模块模式

    我正在尝试重现 Douglas Crockford 所著的 Javascript The Good Parts 一书中的一些代码 这个想法是使用闭包进行对象封装并避免Javascript固有的全局变量 var serial maker fu
  • 如何从mapDispatchToProps内部访问状态

    需要根据状态或演示组件道具来调度操作 const mapDispatchToProps dispatch gt return onClick gt if state someValue this props someValue dispat
  • 为什么有人将(Apache mod_expires 参数)ExpiresByType 设置为“访问加 0 秒”?

    在审查答案时这个帖子 https stackoverflow com questions 9933012 how to use mod headers and mod expires to cache 我不明白为什么这里使用 0 秒作为最佳
  • ajax 调用成功后点击链接 href

    我有一个正常的链接 a href http www google com class continue Continue a 我已将点击绑定到一个事件来发布 ajax 请求 如下所示 continue click function ajax
  • 未捕获的安全错误:阻止了具有原点的框架...访问具有原点的框架

    我已经为 SAP 解决方案 无论什么 制作了一个组件 该组件通过 iframe 嵌入到报告中 在 SAP 平台 BO 上部署报告后 我收到此错误 在 Chrome 上 但在 IE 或 FF 上也不起作用 Uncaught SecurityE
  • Antd 选择搜索框未呈现匹配项

    我有产品数据 我正在使用搜索值过滤数据 然后使用过滤后的数据呈现选项 产品数据作为道具来自全局 redux 存储 由于某种原因 下拉列表仅在搜索值为空时显示数据 当我开始输入时 filteredData已更新 组件也重新渲染 但选项不显示任
  • 如何像在浏览器中一样检索准确的 HTML

    我正在使用 Python 脚本来呈现网页并检索其 HTML 它适用于大多数页面 但对于其中一些页面 检索到的 HTML 不完整 我不太明白为什么 这是我用来废弃此页面的脚本 由于某种原因 每个产品的链接不在 HTML 中 Link http
  • JavaScript:嵌套循环?

    我想实现这样的动画 序列 动画以循环开始 想象一下car从 x1 移动到 x2 然后暂停 1 秒 然后再次播放动画 想象一下car从 x2 移动到 x3 等 the car循环是通过向汽车左侧添加 1px 来实现的 值 但我无法弄清楚嵌套循
  • 如何使表格单元格的最小宽度为 3 位数字?

    如何使表格中的每个单元格的最小宽度为 3 位数字且不会更大 现在我正在硬编码min width 但我不喜欢硬编码一个值 因为我将来可能想更改字体 如果需要Javascript也没关系 table border 1 tr td 1 td td
  • JQuery 屏蔽输入插件不起作用

    我已将 JQuery Masked 输入插件添加到我的 Web 项目中 但它根本不起作用 该插件可以在这里找到 http digitalbush com projects masked input plugin http digitalbu
  • Google 折线图添加对象数组

    我有一个通过解析 JSON 字符串创建的对象数组 var measurementData Html Raw JsonConvert SerializeObject this Model Item1 var stringifiedData J
  • 让管道自我刷新角度

    我有来自后端的静态时间戳 我想每 1 秒刷新一次管道以获取现在的日期 这是我的烟斗 import Pipe PipeTransform from angular core import moment from moment Pipe nam
  • 如何缩放到高图中的特定点

    Highmaps highcharts 是一个 javascript jquery 适配器 可在浏览器等中呈现地图 我有一张突出显示单个国家 地区的地图 但是 世界 地图的比例如此之大 因此我想在将地图加载到相关国家 地区后进行放大 看看
  • html 下钻下拉所选值未插入 MYSQL

    我有两个下拉列表 首先从数据库下拉填充 根据第一个下拉列表的选定值从数据库填充第二个下拉列表 document ready function c change function var c1 c selected text if c1 aj
  • 为什么 [].push([]) 返回 1? [复制]

    这个问题在这里已经有答案了 为什么这会返回 1 push outputs 1 push 返回数组的新长度 one push two returns 2 array length is 2 one two push something ret
  • RemoveEventListener 在 Firefox 版本 58 中不起作用

    但它在 Chrome 中有效 这是我的 UI EventBus 代码 原型 addEventListener方法是一样的 只不过remove换成了add UI EventBus removeEventListener function ob
  • ESLint 如何集成到 Create React App 中?

    当我跑步时npx create react app some name 为我创建了一个简单的 React 项目 当我随后窥视package json 似乎有一些 ESLint 存在的证据 因为有 eslintConfig extends r
  • 如果列表在初始化之前为空,则 jQuery 可排序无法与水平列表正常工作

    如果我在初始化后将元素添加到列表中 sortable它无法正常工作 参见示例jsFiddle http jsfiddle net NQMPr 1 示例 HTML div class container div br

随机推荐