01-mini-vue
·
环境集成 jest 做单元测试
- 初始化项目 npm init -y
- 创建基础文件夹 src/ reactivity/ tests/ index.spec.ts
- 安装 ts 并集成进来,
- npm i typescript --dev
- npx tsc --init
- jest 方法 it 爆红
- yarn add jest @types/jest --dev
- 在 tsconfig.json 中 types 加上 jest
- 报错解决
- package.json 中配置命令
"scripts": { "test": "jest" }, - 运行 npm run test 发现 jest 可以正常使用, 还可以 npm run test + 文件名字 === 检查具体的文件
- 书写一个 导出函数 发现报错,解决三个问题
- 一个是不能使用 any
"noImplicitAny": false, // 可以在项目中使用any - 一个是不能使用 export
// 通过强制显式区分类型与值的导入/导出,生成更干净、可预测的 JavaScript 代码 "verbatimModuleSyntax": false, - 一个是引入模块出现错误,我们使用的 commonjs 规范,却使用了 es6 模块语法,于是引入 Babel 进行编译
- 进行 babel 配置 https://www.jestjs.cn/docs/getting-started babel 官网直接复制
- npm i --save-dev @babel/preset-typescript babel-jest @babel/core @babel/preset-env
-
module.exports = { presets: [['@babel/preset-env', {targets: {node: 'current'}}],'@babel/preset-typescript'] }
简单封装 effect/reactive 引入测试文件保证不报错
-
effect.ts
// 封装一个类,传入fn函数,进行初次执行 class ReactiveEffect { private _fn: any; constructor(fn) { this._fn = fn } run() { this._fn() } } export function effect(fn) { // fn const _effect = new ReactiveEffect(fn) _effect.run() } -
reactive.ts
// 进行拦截 export function reactive (raw) { return new Proxy(raw, { get(target,key) { const res = Reflect.get(target,key) // 依赖收集 return res }, set(target, key, value) { const res = Reflect.set(target, key, value) return res } }) } -
测试用例 yarn test effect ,可以发现因为 update 的逻辑没有封装而报错
import { reactive } from './reactive'; import { effect } from './effect'; describe('effect',()=>{ it('happy path',()=>{ const user = reactive({ age: 10 }) let nextAge effect(()=>{ nextAge = user.age + 1 }) expect(nextAge).toBe(11) // updae user.age++ expect(nextAge).toBe(12) }) }) -
自己手写到这里,npm run test 报错,jest 到 引入 effect 文件就报错
- 解决方法是下载 npm i ts-jest --save-dev
- npx ts-jest config:init
-
在上面的基础上封装 trigger 和 track 方法,以及改写 effect 方法暴露 实例,方便在 track 时添加依赖
// track trigger let targetMap = new Map() export function track(target,key) { // targetMap { target: depsMap } // depsMap { key: dep } // dep 存放fn 函数 let depsMap = targetMap.get(target) if(!depsMap) { depsMap = new Map() targetMap.set(target, depsMap) } let dep = depsMap.get(key) if(!dep) { dep = new Set() depsMap.set(key, dep) } dep.add(activeEffect) } export function trigger(target, key) { const depsMap = targetMap.get(target) const dep = depsMap.get(key) for(let cur of dep) { cur.run() } }class ReactiveEffect { private _fn: any; constructor(fn) { this._fn = fn } run() { activeEffect = this this._fn() } } let activeEffect export function effect(fn) { // fn const _effect = new ReactiveEffect(fn) _effect.run() } -
注意:写到这里,如果我们用写完的 effect.ts 文件来测试 reactive 功能是会报错的,因为这里没有依赖可以收集,当我们在 trigger 里面触发时没有依赖可以执行,所以报错。
-
进行依赖的收集和触发
// 进行拦截
export function reactive (raw) {
return new Proxy(raw, {
get(target,key) {
track(target,key)
const res = Reflect.get(target,key)
// 依赖收集
return res
},
set(target, key, value) {
trigger(target,key)
const res = Reflect.set(target, key, value)
return res
}
})
}
更多推荐
所有评论(0)