环境集成 jest 做单元测试

  1. 初始化项目 npm init -y
  2. 创建基础文件夹 src/ reactivity/ tests/ index.spec.ts
  3. 安装 ts 并集成进来,
  • npm i typescript --dev
  • npx tsc --init
  1. jest 方法 it 爆红
  • yarn add jest @types/jest --dev
  • 在 tsconfig.json 中 types 加上 jest
  • 报错解决
  1. package.json 中配置命令
    "scripts": {
      "test": "jest"
    },
    
  2. 运行 npm run test 发现 jest 可以正常使用, 还可以 npm run test + 文件名字 === 检查具体的文件
  3. 书写一个 导出函数 发现报错,解决三个问题
  • 一个是不能使用 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 引入测试文件保证不报错

  1. 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()
    }
    
  2. 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
        }
      })
    }
    
  3. 测试用例 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)
      })
    })
    
    
  4. 自己手写到这里,npm run test 报错,jest 到 引入 effect 文件就报错

    • 解决方法是下载 npm i ts-jest --save-dev
    • npx ts-jest config:init
  5. 在上面的基础上封装 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()
    }
    
  6. 注意:写到这里,如果我们用写完的 effect.ts 文件来测试 reactive 功能是会报错的,因为这里没有依赖可以收集,当我们在 trigger 里面触发时没有依赖可以执行,所以报错。

  7. 进行依赖的收集和触发

  // 进行拦截
  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
      }
    })
  }
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐