React 测试笔记 03 - 测试 Redux 中 Reducer 状态变化
React 测试笔记 03 - 测试 Redux 中 Reducer 状态变化
这段时间都在重构代码,把本来奇奇怪怪(singleton)的实现改成用 redux 的实现,然后就突然想到……即然 redux 的改变不涉及到 UI 的改变,那么是不是说可以单独写 redux 的测试……?
找了一下资料,发现比想象中的简单很多,所以就稍微记一下
要求简述
这里的案例主要就是通过用户权限,然后 map 对应的页面的读写(全套为增删改查)权限,基本逻辑是这样的:
-
权限分为 read_only、full、A、B、C(A/B/C 为抽象的权限,基本上说对应一下用户可以获得不同分类的权限)
-
每个权限对应着每个页面的读写操作
如 full 代表着用户对所有页面都有读写操作,read_only 相反
A/B/C 给予用户 页面 A/页面 B/页面 C 的读写权限
-
用户可以有不同的权限
-
更高的权限将会复写较低的权限
理论上来说这是不可能发生的事情,不过假设用户同时有 read_only 和 full,那么 full 将会复写 read_only 的权限
比较通常发生的是用户可能会有 A/B/C 这样的权限,但是其中对某些页面会有覆盖操作,如权限 B 给予 B 页面读写操作,权限 C 可能对 B 页面有改的权限,但是没有增删
-
当前 redux 状态只负责授予权限,具体权限的处理则是在 路由/component 处进行处理
实现简述
具体的实现就是 dispatch event 实现,权限的 map 则是通过 {page: permission}
的方式进行存储,至于要求说是取最高权限,因此 permission 的实现方式采用数字,在 redux 中使用 Math.max()
的方式取最大值
需要注意的是,这里在实现的时候可能会出现 type casting 的异常,如 0 | 1 | 2 | 3 is not compatible with number
之类的,我的实现方式是用 Math.max() as (typeof T)[keyof typeof T]
的方式进行一个转型
当然,cv 太多的话还是建议抽一个函数取实现
这样的话通过 roles.filter(role => role in SOME_CONST)
中可以获取需要 map 的权限,再遍历数组更新权限即可
测试实现
首先我先 mock 了一下整个 app component:
jest.mock('../../App', () => ({}));
这一步是假设 app component 已经渲染完毕了,因为其他的 redux 对一些 util——有可能是异步的操作——有一些依赖的关系,然后目前 jest 没有找到这些 util,因此就会抛出找不到 util 的异常,所以这里先 mock 一下虚构的 app,让 jest 知道内部的 util 实现不重要,最终结果就是所有的组件已经正常渲染完毕
其主要原因也是我们的项目有一些 context wrapper 了:
// redux
<Provider store={store}>{/* async code,从 API 处获得权限,再传到 redux 中 */}{/* 如果不 mock,从这里就会报错 */}<AccessContext><OtherContext><App /></OtherContext></AccessContext>
</Provider>
之后的操作非常的简单,jest 已经默认 app 可以正确渲染,因此这里只需要出发 RTK 的状态变化,并且检查状态变化即可,如:
import {ISliceType,sliceReducer,exportedAction,
} from '../../store/slices/state/keycloak';jest.mock('../../App', () => ({}));// 这里可以实现一些状态用来方便 test,而不用手写一堆代码
const initialState: ISliceType = {}; // AKA readOnly
const fullAccess: ISliceType = {};
const aAccess: Partial<ISliceType> = {};
const bAccess: Partial<ISliceType> = {};const validationHelper = (grantedPerm: ISliceType,checkAccess: Partial<ISliceType>
): boolean => {// do some check// 也许可以遍历 checkAccess 的 key,保证 grantedPerm[key] >= checkAccess[key] 这种return true;
};describe('test user has readOnly access', () => {test('initial state is set to readOnly', () => {expect(sliceReducer(undefined, { type: undefined })).toEqual(initialState);});test('user only has readOnly access', () => {const payload = { role: ['readonly'] };expect(sliceReducer(initialState, exportedAction(payload))).toEqual(initialState);});test('user has multiple role', () => {const payload = { role: ['readonly', 'aAccess'] };const grantedPerm = sliceReducer(initialState,exportedAction(payload)).permission;expect(validationHelper(grantedPerm, initialState)).toBeTruthy();expect(validationHelper(grantedPerm, aAccess)).toBeTruthy();expect(validationHelper(grantedPerm, bAccess)).toBeFalsy();});
});
这里检查了三种状态:
-
undefined
相当于触发 Reducer 的初始化,因此返回初始状态因为初始状态直接声明了,所以可以直接用
toEqual
去测试 -
测试只读状态
这里假设返回的状态依旧比较简单,因此仍旧可以使用
toEqual
去和整个状态测试 -
测试更复杂的状态
这个就是用的第三个方法,主要是用
toBeTruthy()
和toBeFalsy()
测试假设说页面有十几二十个,然后有四五组权限,全都手写的话会引入更多的 human error,这个时候就可以考虑将一些常量抽出来
比如说 a 权限对应的
{page: access}
可以单独抽出来做一个变量——这个部分是可以实现、测试公用的,然后再写一个 helper function——这里可以用于测试给予的权限是否大于等于变量中的权限,而没有赋值的权限是否小于等于当前权限,这个根据具体需求具体实现我这里的 helper 直接返回了 boolean,使用上面列举的两个方式去测试,不过实际上还可以搭配其他的 Modifiers 和 Matchers 去测试,不仅仅是用 truthy/falsy
这个不是必须的,因为测试有些情况下就是会 cv 一些代码,而且一些复杂的情况下,仅返回 boolean 的 helper 也许不是这么的好用,那么最差情况下就是得一遍遍手写,然后通过
npm test
去运行测试结果
reference
-
Writing Tests
这里只用了单元测试 reducer 的部分
-
Expect
下面的 reference 列举了 Modifiers 和 Matchers
相关文章:
React 测试笔记 03 - 测试 Redux 中 Reducer 状态变化
React 测试笔记 03 - 测试 Redux 中 Reducer 状态变化 这段时间都在重构代码,把本来奇奇怪怪(singleton)的实现改成用 redux 的实现,然后就突然想到……即然 redux 的改变不涉及到 UI 的改变,那么是不是说可以单独写 redux 的测试……&#…...

xilinx primitives(原语)
Xilinx的原语分为10类,包括:计算组件,IO端口组件,寄存器/锁存器,时钟组件,处理器组件,移位寄存器,配置和检测组件,RAM/ROM组件,Slice/CLB组件,G-t…...

机器学习 - DBSCAN聚类算法:技术与实战全解析
目录 一、简介DBSCAN算法的定义和背景聚类的重要性和应用领域DBSCAN与其他聚类算法的比较 二、理论基础密度的概念核心点、边界点和噪声点DBSCAN算法流程邻域的查询聚类的形成过程 参数选择的影响 三、算法参数eps(邻域半径)举例说明:如何选择…...

kafka微服务学习
消息中间件对比: 1、吞吐、可靠性、性能 Kafka安装 Kafka对于zookeeper是强依赖,保存kafka相关的节点数据,所以安装Kafka之前必须先安装zookeeper Docker安装zookeeper 下载镜像: docker pull zookeeper:3.4.14创建容器 do…...

5G网络切片,到底是什么?
网络切片,是5G引入的一个全新概念。 一看到切片,首先想到的,必然是把一个完整的东西切成薄片。于是,切面包或者切西瓜这样的画面,映入脑海。 添加图片注释,不超过 140 字(可选) 然而…...
linux安装nodejs
写在前面 因为工作需要,需要使用到nodejs,所以这里简单记录下学习过程。 1:安装 wget https://nodejs.org/dist/v14.17.4/node-v14.17.4-linux-x64.tar.xz tar xf node-v14.17.4-linux-x64.tar.xz mkdir /usr/local/lib/node // 这一步骤根…...

第1天:Python基础语法(一)
** 1、Python简介 ** Python是一种高级、通用的编程语言,由Guido van Rossum于1989年创造。它被设计为易于阅读和理解,具有简洁而清晰的语法,使得初学者和专业开发人员都能够轻松上手。 Python拥有丰富的标准库,提供了广泛的功…...

ppt聚光灯效果
1.放入三张图片内容或其他 2.全选复制成图片 3.设置黑色矩形,透明度30% 4.粘贴复制后的图片,制定图层 5.插入椭圆,先选中矩形,再选中椭圆,点击绘图工具,选择相交即可(关键)...

图文解析 Nacos 配置中心的实现
目录 一、什么是 Nacos 二、配置中心的架构 三、Nacos 使用示例 (一)官方代码示例 (二)Properties 解读 (三)配置项的层级设计 (四)获取配置 (五)注册…...
P1918 保龄球
Portal. 记录每一个瓶子数对应的位置即可。 注意到值域很大( a i ≤ 1 0 9 a_i\leq 10^9 ai≤109),要用 map 存储。 #include <bits/stdc.h> using namespace std;map<int,int> p;int main() {int n;cin>>n;for(int i…...

SAP-PP-报错:工作中心 7333_JQ 工厂 7331 对任务清单类型 N 不存在
创建工艺路线时报错:工作中心 7333_JQ 工厂 7331 对任务清单类型 N 不存在, 这是因为在创建工作中心时未维护控制键值导致的...

MySQL -- 用户管理
MySQL – 用户管理 文章目录 MySQL -- 用户管理一、用户1.用户信息2.创建用户3.删除用户4.远端登录MySQL5.修改用户密码6.数据库的权限 一、用户 1.用户信息 MySQL中的用户,都存储在系统数据库mysql的user表中: host: 表示这个用户可以从…...
IOS浏览器不支持对element ui table的宽度设置百分比
IOS浏览器不支持对element ui table的宽度设置百分比 IOS浏览器会把百分号识别成px,所以我们可以根据屏幕宽度将百分比转换成px getColumnWidth(data) {const screenWidth window.innerWidth;const desiredPercentage data;const widthInPixels (screenWidth *…...

Vue+OpenLayers 创建地图并显示鼠标所在经纬度
1、效果 2、创建地图 本文用的是高德地图 页面 <div class"map" id"map"></div><div id"mouse-position" class"position_coordinate"></div>初始化地图 var gaodeLayer new TileLayer({title: "高德地…...
01-编码-H264编码原理
1.整体概念 编码的含义就是压缩,将摄像头采集的YUV或RGB数据压缩成H264。 压缩的过程就是去除信息冗余的过程,一般视频有如下的冗余信息。 (1)空间冗余:在同一个画面中,相邻的像素点之间的变化很小,因而可以用一个特定大小的矩阵来描述相邻的这些像素。 (2)时间冗余:…...

RxJava/RxAndroid的操作符使用(二)
文章目录 一、创建操作1、基本创建2、快速创建2.1 empty2.2 never2.3 error2.4 from2.5 just 3、定时与延时创建操作3.1 defer3.2 timer3.3 interval3.4 intervalRange3.5 range3.6 repeat 二、过滤操作1、skip/skipLast2、debounce3、distinct——去重4、elementAt——获取指定…...

【C语法学习】20 - 文件访问顺序
文章目录 0 前言1 文件位置指示符2 rewind()函数2.1 函数原型2.2 参数2.3 返回值2.4 使用说明 3 ftell()函数3.1 函数原型3.2 参数3.3 返回值 4 fseek()函数4.1 函数原型4.2 参数4.3 返回值 5 示例5.1 示例15.2 示例2 0 前言 C语言文件访问分为顺序文件访问和随机文件访问。 …...

Etcd 常用命令与备份恢复
1. etcd简介 官方网站:etcd.io 官方文档:etcd.io/docs/v3.5/op-guide/maintenance 官方硬件推荐:etcd.io/docs/v3.5/op-guide/hardware github地址:github.com/etcd-io/etcd etcd是CoreOS团队于2013年6月发起的开源项目…...
获取任意时间段内周、季度、半年的二级联动
#需求是获取两个时间内 年周 、年季度、年半年的二级联动# 找了半天也找不到什么有用的信息 就自己简单写了一个 思路是先获取年的列表再去嵌套查询 根据前端VUE提供的格式嵌套 public function getDate(){$leixing Request::param(leixing);$larr array(1,2,3,4);if(empty(…...

前端面试系列之工程化篇
如果对前端八股文感兴趣,可以留意公重号:码农补给站,总有你要的干货。 前端工程化 Webpack 概念 本质上,webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个…...

Python60日基础学习打卡Day45
之前的神经网络训练中,为了帮助理解借用了很多的组件,比如训练进度条、可视化的loss下降曲线、权重分布图,运行结束后还可以查看单张图的推理效果。 如果现在有一个交互工具可以很简单的通过按钮完成这些辅助功能那就好了,他就是…...
东芝Toshiba DP-4528AG打印机信息
东芝 Toshiba DP 4528AG 是一款黑白激光数码复合机: 类型:激光数码复合机,涵盖复印、打印、扫描、传真功能,能满足办公室多样化的文档处理需求。速度类型:中速,黑白复印和打印速度可达 45 页 / 分钟&#…...

新华三H3CNE网络工程师认证—Easy IP
Easy IP 就是“用路由器自己的公网IP,给全家所有设备当共享门牌号”的技术!(省掉额外公网IP,省钱又省配置!) 生活场景对比,想象你住在一个小区:普通动态NAT:物业申请了 …...

Excel 模拟分析之单变量求解简单应用
正向求解 利用公式根据贷款总额、还款期限、贷款利率,求每月还款金额 反向求解 根据每月还款能力,求最大能承受贷款金额 参数: 目标单元格:求的值所在的单元格 目标值:想要达到的预期值 可变单元格:变…...

基于SFC的windows系统损坏修复程序
前言 在平时使用Windows操作系统时会遇到很多因为系统文件损坏而出现的错误 例如:系统应用无法打开 系统窗口(例如开始菜单)无法使用 电脑蓝屏或者卡死 是如果想要修复很多人只能想到重装系统。但其实Windows有一个内置的系统文件检查器可以修复此类错误。 原理 SFC命令…...
An improved YOLACT algorithm for instance segmentation of stacking parts
【一种用于堆叠零件实例分割的改进 YOLACT 算法】 摘要 实例分割在众多应用场景中均是一项至关重要的任务。对于计算机视觉而言,堆叠物体的实例分割是一项挑战。为应对这一挑战,我们提出了一种改进的 YOLACT(You Only Look At CoefficienTs)算法。为提高密集堆叠场景下特…...

单片机0-10V电压输出电路分享
一、原理图 二、芯片介绍 GP8101是一个PWM信号转模拟信号转换器,相当于一个PWM信号输入,模拟信号输出的DAC。此 芯片可以将占空比为0%到100%的PWM信号线性转换成0-5V或者0-10V的模拟电压,并且输出电压 精度小于1%。GP8101M可以处理高频调制的…...

Redis底层数据结构之深入理解跳表(2)
上一篇文章中我们详细讲述了跳表的增添、查找和修改的操作,这篇文章我们来讲解一下跳表在多线程并发时的安全问题。在Redis中,除了网络IO部分和大文件的后台复制涉及到多线程外,其余任务执行时全部都是单线程,这也就意味着在Redis…...
字符串加密(华为OD)
题目描述 给你一串未加密的字符串str,通过对字符串的每一个字母进行改变来实现加密,加密方式是在每一个字母str[i]偏移特定数组元素a[i]的量,数组a前三位已经赋值:a[0]=1,a[1]=2,a[2]=4。当i>=3时,数组元素a[i]=a[i-1]+a[i-2]+a[i-3]。例如:原文 abcde 加密后 bdgkr,…...
基于springboot的校园社团信息系统的设计与实现
其他源码获取可以看首页:代码老y 个人简介:专注于毕业设计项目定制开发:springbootvue系统,Java微信小程序,javaSSM系统等技术开发,并提供远程调试部署、代码讲解、文档指导、ppt制作等技术指导。源码获取&…...