You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在测试中设置或模拟HTML元素的scrollHeight与clientHeight属性

如何模拟HTML元素的scrollHeight和clientHeight进行JavaScript函数测试?

问题描述

我编写了一个用于检测元素是否溢出的TypeScript函数:

function isOverflow(element: string): boolean { 
  const el = document.getElementById(element); 
  return el.scrollHeight > el.clientHeight 
}

但在编写测试用例时,尝试直接给元素的clientHeight和scrollHeight赋值时,遇到了报错:Cannot assign to 'scrollHeight' because it is a read-only property。我的测试代码如下:

it('test', () => { 
  const el = document.createElement("p") 
  el.setAttribute("id", "overflow") 
  // 这里赋值失败,提示属性只读
  el.clientHeight = 2; 
  el.scrollHeight = 1; 
  expect(component.isOverflow("overflow")).toBe(true); 
})

请问该如何模拟这两个只读属性来完成测试?


解决方案

因为scrollHeight和clientHeight是浏览器提供的只读属性,无法直接赋值,我们可以通过以下几种方式来模拟它们的值:

1. 使用Object.defineProperty重新定义属性

通过Object.defineProperty可以修改属性的特性,将其设置为可写,这样就能在测试中自定义值了:

it('should return true when element overflows', () => { 
  const el = document.createElement("p") 
  el.setAttribute("id", "overflow") 

  // 重新定义clientHeight为可写属性并赋值
  Object.defineProperty(el, 'clientHeight', {
    writable: true,
    configurable: true, // 允许后续修改或删除
    value: 2
  });

  // 重新定义scrollHeight为可写属性并赋值(设为大于clientHeight的值)
  Object.defineProperty(el, 'scrollHeight', {
    writable: true,
    configurable: true,
    value: 3
  });

  // 必须将元素添加到DOM中,否则getElementById无法找到它
  document.body.appendChild(el);

  expect(component.isOverflow("overflow")).toBe(true);

  // 测试完成后清理DOM,避免影响其他测试
  document.body.removeChild(el);
})

这种方式非常灵活,适合单个测试用例的定制化需求。

2. 利用测试框架Mock全局原型(以Jest为例)

如果你的项目使用Jest这类测试框架,可以提前MockHTMLElement的原型,让所有创建的元素都拥有可写的scrollHeight和clientHeight:

// 在测试文件的开头或beforeEach钩子中进行全局Mock
beforeEach(() => {
  // 重置Mock,避免测试用例之间互相影响
  jest.restoreAllMocks();
  
  Object.defineProperty(HTMLElement.prototype, 'scrollHeight', {
    writable: true,
    value: 0
  });
  
  Object.defineProperty(HTMLElement.prototype, 'clientHeight', {
    writable: true,
    value: 0
  });
});

it('should return true when element overflows', () => { 
  const el = document.createElement("p") 
  el.setAttribute("id", "overflow") 
  
  // 直接赋值即可
  el.scrollHeight = 5;
  el.clientHeight = 3;

  document.body.appendChild(el);

  expect(component.isOverflow("overflow")).toBe(true);

  document.body.removeChild(el);
})

这种方式适合多个测试用例都需要模拟这两个属性的场景,减少重复代码。

3. 创建真实的溢出元素(无Mock方案)

如果你想完全模拟真实的DOM场景,不需要Mock属性,可以直接创建一个确实会溢出的元素:

it('should return true when element overflows naturally', () => { 
  const el = document.createElement("p") 
  el.setAttribute("id", "overflow") 
  
  // 设置固定高度和溢出隐藏
  el.style.height = '20px';
  el.style.overflow = 'hidden';
  el.style.display = 'block'; // 确保元素有正确的盒模型
  
  // 填充足够多的内容,让元素产生溢出
  el.textContent = '这是一段足够长的文本,用来触发元素的溢出状态。这是一段足够长的文本,用来触发元素的溢出状态。';

  document.body.appendChild(el);

  expect(component.isOverflow("overflow")).toBe(true);

  document.body.removeChild(el);
})

这种方案最贴近真实用户场景,适合需要验证函数在真实DOM环境下表现的测试。


内容的提问来源于stack exchange,提问作者yalpsid eman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 22:07:32