Test Lightning Web Components
同学们,咱们今天来看LWC开发里一个特别有用的工具——Jest。你把它想象成一位随叫随到的质检员,能帮咱们给组件做一套快速又全面的体检。 这套体检最大的好处就是:根本不用打开浏览器,也不用连到Salesforce服务器,完全在你的电脑本地就能跑。所以速度飞快,几秒钟就能看到结果,特别适合放到持续集成流水线里,每一次代码提交都能自动验证,及时发现毛病。 那咱们能用Jest测些什么呢?简单来说,就是把你写好的组件单独拎出来,跟它周围的东西隔离开,专心测它自己的行为。你可以验证那些带@api装饰器的公开属性和方法,确认事件是不是按预期触发的,模拟用户的点击、输入这些交互,还能检查最终渲染出来的DOM结构是不是你想要的样子。 为了让这套测试能跑起来,Salesforce给我们提供了一个专门的小工具包,名字叫sfdx-lwc-jest。它里面有三个核心装备:第一个是jsdom,它在Node.js环境里模拟出一个浏览器才有的DOM树,这样就不需要真浏览器了;第二个是lightning-stub,它会模拟那些Salesforce平台提供的基础组件,比如lightning-button这些,让你测自己写的组件时,不会因为缺少底层依赖而报错;第三个是专门测试有线服务用的实用工具,方便你模拟apex方法或者LDS数据拉取。 咱们接下来这一整章,就是从零开始,带你走过Jest测试的完整生命周期。先搭好环境,装好依赖,然后一步一步做测试,最后还会学到一些高级的模拟模式,让你能应对各种复杂的测试场景。放心,跟着做,你很快就能写出又稳又准的单元测试了。咱们这就开始吧。
本课程共有 5 个章节
大家可能已经看到这页Slide了,上面写着用命令 `sf force lightning lwc test select` 来安装是最简单的。这里有个小小的笔误,实际Salesforce CLI里正确的命令是 `sf force lightning lwc test setup`,我们照着这个来说。你只要在你的项目文件夹下打开终端,运行这一条命令,它就会自动帮你生成所有需要的配置文件,并且把测试依赖包都装好,非常省心。 如果你更习惯手动控制,也可以自己用 npm 来安装。需要执行 `npm install @salesforce/sfdx-lwc-jest`,然后在 `package.json` 里配置好测试脚本,稍麻烦一点,但自由度更高。 装好之后,我们就有四种测试模式可以用。第一种是标准模式,就是直接跑 `npm run test:unit`,执行全部单元测试,验证代码有没有问题。第二种叫监视模式,你在开发的时候打开它,代码一改动,测试就会自动重跑,让你第一时间发现问题。第三种是调试模式,可以让你一行一行地跟踪代码执行,排查故障。最后一种是覆盖模式,能帮你统计测试覆盖了多少行代码,确保质量。 如果你在用 VS Code 开发,装了 Salesforce 扩展包之后,侧边栏会多出一个 LWC Tests 的视图。在这里你可以直接看到测试结果和运行测试,不用频繁切回命令行,很方便。 最后,对于有深入需求的高级用户,项目里会有一个 `jest.config.js` 文件。你可以在里面定制一些东西,比如给模块名起个别名、设置启动文件、调整测试超时时间等等。如果你的项目很大,跨文件夹的依赖让测试变慢,你还可以在 `moduleNameMapper` 里添加一些配置,让解析更快,从而加速测试运行。 整体上,安装很简单,模式也灵活,用熟了就能帮你把组件的质量牢牢守住。接下来我们看看具体怎么配置。
同学们,今天我们来看一下在Lightning Web Components里调试测试代码的三种方法。每种方法适合的场景不太一样,我会用最简单的话帮你们梳理清楚。 第一种,也是最简单的一种,就是直接在我们已经装好的VS Code扩展包里操作。你打开一个测试文件,在左侧的LWC测试侧边栏里,对着代码的行号点一下就能加上断点,像平时调试那样。然后,注意看这个侧边栏上有一个按钮叫“运行测试”,点它就行。运行起来之后,VS Code会弹出运行视图,里面有监视表达式、调试工具栏,还有一个控制台,你可以实时查看变量、逐步执行代码,非常直观。这是最适合日常开发的方式。 第二种,是使用Chrome的开发者工具来调试。这种方式需要你先在命令行执行一条命令:`npm run test:unit:dev`,它会启动一个带调试模式的测试服务。接着,在Chrome浏览器地址栏输入`chrome://inspect`,进去后就能找到对应的目标,点击连接就能开始调试了。这里有一个非常重要的点要记住:你平时在VS Code里点的行号断点,在这个方式下是不起作用的。你需要自己在代码里写上`debugger;`这个关键字,当程序执行到这一行,它就会自动停住,然后你就能在Chrome DevTools里一步一步检查变量了。 第三种,是一种更高级的配置方式,适合对项目有定制需求的同学。你需要自己创建两个文件,一个叫`launch.json`,是VS Code的启动配置文件;另一个是`jest.unit.js`,用来给Jest测试做一些额外设置。配置好之后,同样需要用`debugger;`来声明断点,因为编译后的代码行号和你的源代码是对不上的,所以行号断点也不可靠。虽然配置起来稍微麻烦一点,但一旦配好,你也能像第一种方法那样逐步执行测试,并在运行时检查所有变量。 总结一下:这三种方法最后都能让你一步一步地执行测试,并且在运行时查看变量。只是方式和应用场景不同。日常开发优先用VS Code侧边栏,最省事;需要单独调试或者协作排查问题时,可以试试Chrome DevTools;有特殊工程化需求的时候,再去配置高级方案。好了,这一页的内容就到这里,大家如果有疑问,可以随时提出来。
同学们,大家好!今天我们讲讲Lightning Web Components的测试,用的是Jest框架。这部分内容看起来复杂,但我会一步一步给你拆解,保证你听完就明白。 首先,咱们要记住,Jest测试遵循一个“八步解剖法”,其实就是一套标准的测试流程。第一步,我们用`createElement`来创建一个组件实例,语法是`createElement(‘c-mycomponent’, { is: MyComponentClass })`,这就像在代码里“造”一个组件出来。第二步,调用`appendChild`把这个元素加到文档里,这一步会触发组件的生命周期钩子,比如`connectedCallback`,组件才算真正活起来。然后,我们要访问组件的内部DOM,测试中得用`element.shadowRoot`,这是测试专用的API,相当于生产环境里的`this.template`,专门用来查看影子DOM里面的元素。 测试完每个用例,一定要在`afterEach`里做清理,比如`while (document.body.firstChild) document.body.removeChild(document.body.firstChild)`。这非常关键!因为Jest用的jsdom环境是跨测试共享的,要是不清理干净,前一个测试残留的DOM可能会干扰后面的测试,导致结果错乱。 接下来是导航测试。LWC里如果你用了`CurrentPageReference`这类导航服务,测试时需要模拟。别担心,`sfdx-lwc-jest`已经提供了默认的模拟实现,但你也可以自己定制,通过Jest配置的`moduleNameMapper`来映射到你的自定义模拟文件。 再来说Apex调用。如果组件里调用了Salesforce服务端的方法,比如导入`import getAccount from '@salesforce/apex/AccountController.getAccount'`,测试里必须模拟它。做法是:在同目录或者`__tests__`下放一个同名Apex模拟文件,里面导出`jest.fn()`。还要在Jest配置里加上模块名重定向,把`@salesforce/apex/`开头的模块统统指向一个通用的模拟实现。这样测试就不会真的去调服务器了。 还有异步DOM更新的问题。如果你设置组件属性是在`appendChild`之后,那会触发异步渲染,测试里需要用`return Promise.resolve()`来等待微任务执行完,才能获取到最新的DOM。但如果你在`appendChild`之前设置属性,那就是同步更新,不需要`Promise`处理。简单说:先设属性,再挂载,就同步;先挂载,再改属性,就异步。 最后,有个安全保障:`.forceignore`文件。要让测试文件不被部署到Salesforce生产环境,你可以在`.forceignore`里加入模式来忽略测试文件夹,比如`,/__tests__/,`,这样部署时就会自动跳过它们,确保测试代码不会进到组织里。 把这些点记住,LWC的测试就能写得得心应手。好,这节课就到这里,下一节我们动手写一个实际例子。
大家注意了,这个Slide是关于Wire Service测试当中数据的模拟方式。我们通常说的“emit模式”,就是指在测试环境里,通过调用adapter.emit(),把假的响应数据塞进组件的@wire适配器里。 具体怎么做呢?首先,测试文件里要导入跟被测组件一模一样的那个有线适配器。然后你要把组件先插入到DOM里,也就是执行appendChild,这样组件才连上DOM,开始监听数据的变化。记住,组件只有挂载到DOM上之后,它才会接收更新,所以我们一定要在appendChild完成之后再调用emit。 调用的时候,就是adapter.emit(你准备好的模拟数据)。这些模拟数据有一个关键点:它的结构必须跟真实的后端UI API响应格式一模一样。不要去手写那些JSON,很容易写错。最好的办法是用REST客户端,比如Workbench或者Postman,去捕获一次真实的响应,把它复制下来。如果你用的是Lightning Data Service(LDS)线适配器,你会发现官方示例里,数据文件夹中已经有一些以适配器命名的JSON文件,比如getRecord.json,这些其实就是从真实API粘过来的响应,直接就能用。 接下来,emit完了别急着做断言,因为组件更新是异步的。我们必须要用Promise.resolve(),然后把后续的断言链在这个微任务后面,这样才能等到组件重新渲染完成,再去检查DOM或属性。 最后提一句,在22年春季版本之前,我们是使用registerLdsTestWireAdapter这种旧的注册模式,现在仍然兼容,但官方已经不推荐了,咱们就用新的emit模式,代码更简洁,也更容易理解。 好了,这一页的核心就这些,大家有没有问题?
同学们,今天我们来聊聊在 Lightning Web Components 测试中特别有用的技巧——模拟模式。掌握了它,你就能轻松应对那些不好直接测的场景。 咱们先从最基本的属性更改测试说起。当你创建一个组件实例,如果在调用了 `appendChild` 把它加到文档里之后,才去设置某个公共属性,那么渲染是异步的。这时候想要验证结果,就必须用 `Promise.resolve()` 等待微任务队列清空,否则断言会失败。反过来,如果你希望在附加前就完成赋值、实现同步渲染,可以先用 `Object.assign` 把属性一股脑儿设好,再 `appendChild`,这样就不用等 Promise 了,测试代码更简洁。 接着看组件间的交互。Salesforce 提供的 lightning 存根,比如 `lightning-button` 的模拟,只保证 API 接口兼容,但不会像真实组件那样自动触发事件。所以,假如你的组件监听了按钮的 `click` 事件,在测试里你得自己手动调度事件。用 `new CustomEvent` 然后 `dispatchEvent`,才能模拟用户点击的效果。 说到事件,必然要提事件处理函数的模拟。通常我们用 `jest.fn()` 创建一个假函数,然后通过 `addEventListener` 把它挂到元素上。手动调度事件之后,就可以用 `expect` 验证这个假函数被调用了几次,以及事件对象的 `detail` 属性是不是我们期望的值。这样不用关心内部实现,只看交互结果,测试更稳定。 还有模块导入的模拟。比如你用 `import` 引入了一个自己写的工具模块,或者 `@salesforce/label` 这种 Salesforce 特定范围导入。想控制它的返回结果怎么办?直接用 Jest 的 `jest.mock()`。给模块路径配一个工厂函数,返回你需要的假数据,这样就能隔离被测组件和外部依赖,让测试完全按你的剧本走。 最后要提醒大家:LWC 内部的 HTML 结构和 CSS 类名其实是不稳定的,官方不希望你把测试锚定在那些细节上。所以我们写单元测试时,尽量通过 `element.shadowRoot` 来访问影子 DOM,做一些高层级的检查就好,不要执着于具体的 CSS 选择器。真正需要验证页面外观和整体交互的时候,还是交给 Selenium 这类工具做端到端测试。记住,Jest 单元测试专注于逻辑和 API,Selenium 才负责端到端的用户体验。 把这些模拟手法用好,你的测试就会既健壮又灵活。赶紧去试试吧!