如何从0构建一款类jest工具

 Jest工作原理

  Jest 是一个流行的 JavaScript 测试框架,特别适用于 React 项目,但它也可以用来测试任何 JavaScript 代码。Jest 能够执行用 JavaScript 编写的测试文件的原因在于其设计和内部工作原理。下面是 Jest 的工作原理及其内部机制的详细解释,大致分为6部分
初始化
Jest 在启动时会读取配置文件(如 jest.config.js)以及命令行参数来初始化自身的配置。
它会设置全局环境,包括全局变量、钩子函数(如 beforeEach、afterEach)等。
发现测试文件
Jest 会遍历指定的目录,使用配置文件中定义的模式(如 **/__tests__/**/*.js?(x) 或 **/?(*.)+(spec|test).js?(x))来发现测试文件。
这些文件通常是以 .test.js 或 .spec.js 结尾,或者位于 __tests__ 目录下。
编译和转换
对于使用现代 JavaScript 语法(如 ES6、ES7、JSX)的测试文件,Jest 会使用 Babel 或其他编译工具将其转换为兼容的 JavaScript 代码。Jest 内部集成了 Babel,能够自动识别并转换这些语法。
隔离环境执行
Jest 为每个测试文件创建一个独立的沙盒环境。这个环境隔离了全局变量和模块缓存,确保测试之间不会相互干扰。通过 jest-runtime 模块,Jest 能够在这个隔离环境中加载并执行测试文件。
执行测试
Jest 通过导入测试文件并执行其中的测试函数(如 test 或 it 函数)来运行测试。
Jest 会跟踪每个测试的结果,包括成功、失败、跳过等信息。
报告和反馈
测试执行完毕后,Jest 生成详细的测试报告,包括每个测试的结果、执行时间、失败的断言信息等。Jest 还支持代码覆盖率报告,帮助开发者了解测试覆盖的代码范围。

  这些模块中,隔离测试环境执行测试文件是很核心的模块,那么jest如何实现隔离环境以及执行测试的呢?实现这些的是jest-runtime模块,jest-runtime 通过 vm 模块(Node.js的虚拟机模块)在沙盒环境中执行测试文件。创建一个独立的执行上下文,并在其中运行测试代码,确保测试文件与主进程隔离。另外,jest-runtime 还提供了一组全局变量(如 test、expect、beforeEach、afterEach 等)供测试文件使用。这里使用到了vm模块,那什么是node.js的vm模块呢?

Node.js的vm模块

  Node.js 的 vm 模块允许在 V8 虚拟机的上下文中编译和运行代码。它提供了几种 API来创建独立的执行环境(沙盒),用于隔离代码执行。这在以下场景中非常有用:

执行不信任的代码:通过沙盒环境执行用户输入的代码,以防止代码影响到主应用程序。
插件系统:动态加载和执行插件代码。
测试:在隔离的环境中运行测试代码,防止全局状态污染。
动态代码生成:根据运行时数据动态生成并执行代码。

  利用vm编译和执行代码非常简单,具体代码如下图所示,当需要执行某段代码的时候,将code的字符串传入runInSandbox即可。

import { Script, createContext } from 'vm';
import assert from 'assert';
export const runInSandbox = (code, context = {}) => {
    const sandbox = createContext({
        ...context,
        assert,
        console,
        setTimeout,
        setInterval,
        clearTimeout,
        clearInterval,
        Buffer,
        process,
    });

    const script = new Script(code);
    script.runInContext(sandbox);
};

  上面的的代码中,主要是用了vm模块提供Script对象和createContext方法。Script 对象是 vm 模块中的一个核心组件,它允许你编译并运行一段 JavaScript 代码。script.runInContext(context) 方法,可以在指定的上下文中运行编译后的代码。上下文是通过 vm.createContext 创建的。createContext中主要定义两种变量,全局变量和用户自定义变量。全局变量主要包括如下对象:
console: 提供日志记录功能,使沙盒内的代码能够输出日志信息。
setTimeout, setInterval, clearTimeout, clearInterval: 这些计时器函数允许沙盒内的代码使用异步操作。
Buffer: 使沙盒内的代码能够处理二进制数据。
process: 提供关于当前 Node.js 进程的信息,但通常会对其做一些限制,以防止恶意代码影响主进程。
用户自定义变量和方法主要包括:
测试框架相关的函数:例如 test 和 expect,用于定义和执行测试。
自定义的 require 函数:用于加载模块,确保沙盒内的代码只能访问允许的模块。

如何从0构建一款类jest的工具

初始化项目

mkdir custom-jest-runtime
cd custom-jest-runtime
npm init -y
npm install @babel/core @babel/preset-env
npm install expect

实现文件发现和收集逻辑

下面的代码中遍历目录中所有以.test.js结尾的文件,并将所有文件path进行收集存储。

import { readdirSync, statSync } from 'fs';
import { join } from 'path';

export const findTestFiles = (dir, testFiles = []) => {
    const files = readdirSync(dir);
    files.forEach((file) => {
        const filePath = join(dir, file);
        if (statSync(filePath).isDirectory()) {
            findTestFiles(filePath, testFiles);
        } else if (file.endsWith('.test.js')) {
            testFiles.push(filePath);
        }
    });
    return testFiles;
};

创建沙盒运行环境

这里使用node.js中的vm模块实现在沙盒环境中完成测试的编译的执行

import { Script, createContext } from 'vm';
import assert from 'assert';
export const runInSandbox = (code, context = {}) => {
    const sandbox = createContext({
        ...context,
        assert,
        console,
        setTimeout,
        setInterval,
        clearTimeout,
        clearInterval,
        Buffer,
        process,
    });

    const script = new Script(code);
    script.runInContext(sandbox);
};

模块解析和加载

使用 Babel 转换现代 JavaScript 代码,保证不同版本Js代码兼容性。

import * as babel from '@babel/core';
import { readFileSync } from 'fs';

export const loadModule = (filePath) => {
    const code = readFileSync(filePath, 'utf8');
    const { code: transformedCode } = babel.transformSync(code, {
        presets: ['@babel/preset-env'],
    });
    return transformedCode;
};

执行测试文件逻辑

在runTestFile中,首先调用前面封装的loadModule来对测试文件内容进行转换,以兼容不同版本的js代码,接着在context上下文中自定义了test对象,这样当code中包含test的时候,就能进行识别。最后调用runInSandbox执行。

import { runInSandbox } from './sandbox.js';
import { loadModule } from './moduleLoader.js';

export const runTestFile = (testFile) => {
    const code = loadModule(testFile);
    const context = {
        test: (name, fn) => {
            try {
                fn();
                console.log(`Test passed: ${name}`);
            } catch (error) {
                console.log(`Test failed: ${name}`);
                console.error(error);
            }
        },
    };
    runInSandbox(code, context);
};
//index.js入口文件
import { findTestFiles } from './fileFinder.js';
import { runTestFile } from './testRuntime.js';

const testFiles = findTestFiles(new URL('./tests', import.meta.url).pathname);
testFiles.forEach(runTestFile);

在tests目录下编写一个测试脚本,如下所示:

const sum = (a, b) => a + b;

test('adds 1 + 2 to equal 3', () => {
    assert.strictEqual(sum(1, 2), 3);
});

运行index.js脚本(node index.js),得到如下结果,说明执行成功。

  以上就是实现一款类似jest框架的过程。jest框架本身会比这个复杂很大,它自身又集成了其他一些工具,例如expect包等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/745755.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言的学习发展路线(都是干货)

哈喽,大家好呀~我又回来了,前期比较忙,没有时间来更文,现在给大家推荐了一个C语言的学习路线,供大家一起学习啦! 1. 环境搭建与工具篇 选择编译器:常用的编译器有gcc、Clang、Visual Studio等。…

第一个Java程序--HalloWorld(记事本版)

一、开发步骤 1.编写 将 Java 代码编写到扩展名为 .java 的源文件中 class HelloChina{public static void main(String[] args){System.out.println("HelloWorld!");} } 2.编译 winr进入DOS操作系统,进入当前目录。(操作命令见《JAVA概述…

红酒哲学:品味流转时光,探寻生活之深邃奥秘

在繁华的都市中,我们时常被各种声音和色彩所包围,追求着速度与激情。然而,在这喧嚣之中,总有那么一刻,我们渴望静下心来,品味一份不同的宁静与深度。这时,一杯雷盛红酒便成了我们与内心对话的桥…

Ubuntu磁盘分区和挂载 虚拟机扩容 逻辑卷的创建和扩容保姆及教程

目录 1、VMware虚拟机Ubuntu20.04系统磁盘扩容 2、Linux的磁盘分区和挂载 3、创建逻辑卷和逻辑卷的扩容 1、VMware虚拟机Ubuntu20.04系统磁盘扩容 通过下图可以看出我们的根磁盘一共有20G的大小,现在我们把它扩容为30G 注:如果你的虚拟机有快照是无…

鸿萌数据迁移业务案例:为医药客户成功迁移重要科研数据

天津鸿萌科贸发展有限公司对 Windows 及 Linux 系统下的各类型备份及数据迁移业务积累了丰富的业务经验,可提供针对性的解决方案。 医药科研数据迁移成功案例 2024年6月初,天津某医药厂家埃尔法 workstation2020 服务器硬盘老化,为保证服务…

小白上手AIGC-基于PAI-DSW部署Stable Diffusion文生图Lora模型

小白上手AIGC-基于PAI-DSW部署Stable Diffusion文生图Lora模型 前言资源准备开启体验服务创建工作空间 部署服务创建DSW实例安装Diffusers启动WebUI 写在最后 前言 在上一篇博文小白上手AIGC-基于FC部署stable-diffusion 中,说到基于函数计算应用模板部署AIGC文生图…

这么精彩的排序算法,你确定不来看一下?

目录 1.交换函数: 2.三数取中: 一.插入排序: 二.希尔排序: 三.选择排序: 四.快速排序: 1.霍尔法(递归版): 2.挖坑法(递归版): 3.双指针…

智领全栈,模力全开|2024中国智算中心全栈技术大会,锐捷网络引爆智算网络新风潮

6月25日至27日,2024中国智算中心全栈技术大会暨展览会、第5届中国数据中心绿色能源大会暨第10届中国(上海)国际数据中心产业展览会在上海新国际博览中心隆重开幕。此次大会由CDCC和益企研究院主办,以“AI赋能,重构未来”为主题,吸…

重温react-06

开始 函数组件必然成为未来发展的趋势(个人见解),总之努力的去学习,才能赚更多的钱.加油呀! 函数组件的格式 import React from reactexport default function LearnFunction01() {return (<div>LearnFunction01</div>) }以上是函数式组件的组基本的方式 快捷生…

如何提高工业交换机的电源功耗?

工业交换机的电源功耗是指在工作状态下所消耗的能量。随着工业自动化技术的发展&#xff0c;工业交换机在生产和制造领域中扮演着至关重要的角色。它们通过连接各种设备和系统&#xff0c;实现信息的传输和处理&#xff0c;提高生产效率和质量。然而&#xff0c;工业交换机的大…

springAI孵化(二)

目录 一、spring AI 目的 二、spring AI 来源 三、sprig AI 是什么&#xff1f; 四、spring AI中的 概念 4.1、模型&#xff08;Models&#xff09; 4.2、提示&#xff08;Prompts&#xff09; 4.3、提示模板&#xff08;Prompt Templates&#xff09; 4.4、令 牌&…

你的企业“赚钱能力”,银行怎么看?聊聊税贷与票贷背后的门道

大家都听过“税贷”和“票贷”吧&#xff1f;特别是这两年&#xff0c;国家扶持中小微企业&#xff0c;这些名词更是火得不行。但你知道吗&#xff0c;税贷和票贷并不是只看税和票那么简单。今天&#xff0c;咱就来聊聊这背后的门道&#xff08;最后附上&#xff1a;企业信用贷…

ChatGPT的Mac客户端正式发布了!Mac用户有福了

ChatGPT的Mac客户端正式发布了&#xff01;Mac用户有福了 &#x1f389; 大家好&#xff0c;我是猫头虎&#xff0c;科技自媒体博主。今天我带来了一个超级重磅的消息 &#x1f4e2;&#xff0c;就是 ChatGPT 的客户端终于来了&#xff01;这对我们所有 Mac 用户&#xff0c;尤…

可穿戴式手持气象仪

TH-SQ17在快节奏的现代生活中&#xff0c;我们越来越依赖各种智能设备来辅助我们的决策和行动。其中&#xff0c;气象信息的重要性不言而喻&#xff0c;它不仅关系到我们的出行安全&#xff0c;更影响着我们的日常生活安排。如今&#xff0c;一款革命性的产品——可穿戴式手持气…

GPT-4o背后的秘密:深入了解它的运作方式

GPT-4o是OpenAI最新推出的多模态大模型&#xff0c;它在语言处理、图像识别和音频处理方面都实现了重大突破。GPT-4o的"o"代表"omni"&#xff0c;意为全能&#xff0c;能够处理文本、音频、图像和视频输入&#xff0c;是一种高度集成的神经网络。这篇文章将…

精打细算用好 LLMs :LLM 落地应用成本及响应延迟优化

前言 高成本和延迟是将大语言模型应用于生产环境中的主要障碍之一&#xff0c;二者均与提示词信息的体量&#xff08;prompt size&#xff09;紧密相连。 鉴于大语言模型&#xff08;LLM&#xff09;展现出极强的广泛适用性&#xff0c;不少人视其为解决各类问题的灵丹妙药。…

计算机网络 交换机的基本配置

一、理论知识 1.三种模式&#xff1a; ①用户模式&#xff1a;当登录路由器后&#xff0c;系统自动进入用户EXEC命令模式。 例如&#xff1a; Router> 在用户模式状态下&#xff0c;用户只能查看路由器的连接状态和基本信息&#xff0c;访问其他网络和主机&#xff0c…

模拟面试之外卖点单系统(高频面试题目mark)

今天跟大家分享一个大家简历中常见的项目-《外卖点单系统》&#xff0c;这是一个很经典的项目&#xff0c;有很多可以考察的知识点和技能点&#xff0c;但大多数同学都是学期项目&#xff0c;没有实际落地&#xff0c;对面试问题准备不充分&#xff0c;回答时抓不到重点&#x…

ChatGPT只是开胃菜,AIGC风口真的来了!

去年OpenAI发布的ChatGPT在全球疯狂刷屏成为一款现象级产品&#xff0c;并成功出圈受到IT、新闻媒体、学术研究、教育等领域的广泛好评和应用。甚至有一位美国学生用ChatGPT 写论文拿下全班最高分&#xff0c;受到了全球媒体的热议。 比尔盖茨曾在今年“Reddit AMA大会”表示&…

计算机毕业设计Thinkphp/Laravel智能道路交通管理系统4ir8r

Laravel非常的简洁并且是开源的&#xff0c;Laravel 是一个具有表现力、优雅语法的 Web 应用程序框架. Laravel 是构建现代全栈 Web 应用程序的最佳选择. 它的语法更富有表现力&#xff0c;拥有高质量的文档和丰富的扩展包&#xff0c;技术上它有Bundle扩展包、Eloquent ORM、反…