前端测试 jest 之 测试环境

721 阅读2分钟

本文来源于Jest实践指南,这里只是用作自己复习学习使用。

什么是测试环境?

在很多时候,我们前端的代码往往只在浏览器里运行,经常要用到浏览器的 API,比如某个测试环境中使用了浏览器的API localstorage。我们对 localStorage 进行封装,一共有 set 和 get 两个函数:

// src/utils/storage.ts
const KEY_NAME = "my-app-";

const set = (key: string, value: string) => {
  localStorage.setItem(KEY_NAME + key, value);
};

const get = (key: string) => {
  return localStorage.getItem(KEY_NAME + key);
};

const storage = {
  get,
  set,
};

export default storage;

然后在 tests/utils/storage.test.ts 添加这个文件的测试用例:

// tests/utils/storage.test.ts
import storage from "utils/storage";

describe("storage", () => {
  it("可以缓存值", () => {
    storage.set("newKey", "hello");
    expect(localStorage.getItem("my-app-newKey")).toEqual("hello");
  });

  it("可以设置值", () => {
    localStorage.setItem("my-app-newKey", "hello");
    expect(storage.get("newKey")).toEqual("hello");
  });
});

由于 Node.js 环境并没有 localStorage,所以你会得到这样的报错:

image.png

全局 Mock

既然没有 localStorage,那我们可以给它 Mock 一个!首先添加 tests/jest-setup.ts 文件,然后放置 localStorage 的 Mock 实现:

// tests/jest-setup.ts
Object.defineProperty(global, 'localStorage', {
  value: {
    store: {} as Record<string, string>,
    setItem(key: string, value: string) {
      this.store[key] = value;
    },
    getItem(key: string) {
      return this.store[key];
    },
    removeItem(key: string) {
      delete this.store[key];
    },
    clear() {
      this.store = {}
    }
  },
  configurable: true,
})

然后在 jest.config.js 里添加 setupFilesAfterEnv 配置:

module.exports = {
  setupFilesAfterEnv: ['./tests/jest-setup.ts'],
};

设置了之后,jest-setup.ts 会在每个测试文件执行前先执行一次。  相当于每执行一次测试,都会在全局添加一次 localStorage 的 Mock 实现。 现在再来执行一次 npm run test,会发现执行成功。

jsdom 测试环境

回到主题,像上面 Mock LocalStorage 这样有点傻,因为我们不可能把浏览器里所有的 API 都 Mock 一遍,而且不可能做到 100% 还原所有功能。因此,jest 提供了 testEnvironment 配置:

module.exports = {
  testEnvironment: "jsdom",
}

添加 jsdom 测试环境后,全局会自动拥有完整的浏览器标准 API。原理是使用了 jsdom (opens new window)。 这个库用 JS 实现了一套 Node.js 环境下的 Web 标准 API。  由于 Jest 的测试文件也是 Node.js 环境下执行的,所以 Jest 用这个库充当了浏览器环境的 Mock 实现。

现在清空 jest-setup.ts 里的代码,直接 npm run test 也会发现测试成功。