使用Jest和jsdom测试Lit-HTML元素事件与unsafeCSS遇类未更新问题
Jest测试Lit-HTML元素点击状态切换失败
问题描述
尝试用Jest为Lit-HTML开关元素编写单元测试,验证点击后元素从active状态切换为disabled状态。测试中点击事件已触发,但元素类未按预期变化,断言失败。
组件代码(my-lit-html-toggle.ts)
// my-lit-html-toggle.ts const TAG = 'my-lit-html-toggle'; @customElement(TAG) export class MyLitHtmlToggle extends LitElement { @property({ type: Boolean }) public active = false; @property({ type: Boolean }) public disabled = false; public static styles = unsafeCSS(toggleSwitchStyles); public render(): TemplateResult { const classes = { active: this.active, disabled: this.disabled, }; return html` <div class="toggle ${classMap(classes)}" @click=${this.toggleActive}> <div class="toggle-switch"></div> <div class="toggle-handle"></div> </div> `; } private toggleActive() { const onToggle = new CustomEvent<ToggleSwitchEvent>('onToggle', { detail: { active: (this.active = !this.active), }, }); this.dispatchEvent(onToggle); } }
原测试代码(Jest)
// Test JEST import { html, render } from 'lit'; describe('Given my-lit-html-toggle', () => { it('Should switch from active to disabled', async function () { const switchHandler = jest.fn(); render(html`<my-lit-html-toggle active .click="${switchHandler}" ></my-lit-html-toggle>`, document.body); await Promise.resolve(); document.body.querySelector(TAGNAME)?.click() await waitFor(() => expect(switchHandler).toBeCalledTimes(1)); }); })
报错信息
expect(element).toHaveClass("disbled") Expected the element to have class: disbled Received: toggle-switch active 38 | ); 39 | const cut = document.body.querySelector(TAGNAME)?.shadowRoot; > 40 | expect(cut?.childNodes.item(2)).toHaveClass('disbled'); | ^ 41 | }); 42 |
问题分析与解决方案
1. 核心问题:组件逻辑未处理disabled属性
当前组件的toggleActive方法仅翻转active属性,完全未修改disabled值,这是状态不切换的根本原因。根据需求调整方法逻辑:
private toggleActive() { // 点击后将active设为false,disabled设为true this.active = false; this.disabled = true; const onToggle = new CustomEvent<ToggleSwitchEvent>('onToggle', { detail: { active: this.active, disabled: this.disabled }, }); this.dispatchEvent(onToggle); }
如果需求是切换disabled状态(而非单向设置),可改为:
this.disabled = !this.disabled; this.active = !this.disabled; // 确保active和disabled互斥
2. 测试代码的错误修正
- 拼写错误:断言中的
disbled应为disabled。 - 错误绑定点击事件:直接给自定义元素绑定
.click不会触发内部shadow DOM中div的点击事件,需获取shadow内的.toggle元素触发点击。 - 等待Lit异步更新:Lit属性更新是异步的,需等待组件
updateComplete完成后再断言。
修正后的测试代码:
import { html, render } from 'lit'; import { MyLitHtmlToggle } from './my-lit-html-toggle'; const TAG = 'my-lit-html-toggle'; describe('Given my-lit-html-toggle', () => { // 测试后清理DOM,避免污染 afterEach(() => { document.body.innerHTML = ''; }); it('Should switch from active to disabled', async () => { // 渲染初始active为true的组件 render(html`<${TAG} active></${TAG}>`, document.body); await Promise.resolve(); const toggleElement = document.body.querySelector(TAG) as MyLitHtmlToggle; const toggleDiv = toggleElement.shadowRoot?.querySelector('.toggle'); // 触发内部div的点击事件 toggleDiv?.click(); // 等待Lit完成更新 await toggleElement.updateComplete; // 断言状态变化 expect(toggleDiv).toHaveClass('disabled'); expect(toggleDiv).not.toHaveClass('active'); }); });
3. 额外优化
- 组件类名修正:
My-lit-htmToggle改为符合规范的驼峰命名MyLitHtmlToggle,避免语法问题。 - 测试中使用组件实例而非直接操作DOM,更可靠。
内容的提问来源于stack exchange,提问作者rluisn
相关产品推荐
相关产品推荐

