reactjs 在react测试库中使用DOM元素?

9nvpjoqh  于 2022-12-18  发布在  React
关注(0)|答案(2)|浏览(166)

我有一个关于在React Testing库中使用DOM元素的一般性问题。
实际上,我有两个嵌套组件,其中一个创建了一个React引用,该引用向下转发到一些子组件(下面的代码)。
当它这样做的时候,它会呈现子组件,并检查嵌套的Ref来调用.getBoundingClientRect(),这是一个神奇的本地Javascript函数,可以给我x和y的位置、宽度和高度以及上、下、左、右边界。我真的需要这些信息,因为我想用它做一些其他的事情。而不直接修改DOM(我使用setState进行所有DOM修改,并让React重新呈现DOM)
在开发中(Chrome),当我执行console.log(this.thing_one_ref.current.getBoundingClientRect())时,我得到了以下结果:

(you我会注意到,一旦我的应用程序呈现(而不是之前),这里的thing_one_ref就会正确填充,看起来像:)

我对这段代码有一个简单的规范,它碰巧通过了,但是即使它通过了,控制台记录的输出 * 当在测试环境中时 * 看起来像这样:

注意,所有的值都是0,而不是我所期望的值,这是要呈现的元素,就好像它在一个真实的的DOM上一样
//源代码/应用程序测试. js

import React from 'react';
import { render, wait } from '@testing-library/react';
import App from './App';
test('renders learn react link', async () => {
  const { getByText, getByTestId } = render(<App />);
  const linkElement = getByTestId("app")
  await wait(() => expect(getByText(/A Test of refs/i, linkElement)).toBeInTheDocument());
});

//源代码/应用程序. js

import React from 'react';
import './App.css';

import styled from 'styled-components'

import ThingOne from './thing_one'
import Container from './container'

const StyledApp = styled.div`
   position: relative;
   height: 100vh;
   width: 100%;
`

function App() {
  return (
    <StyledApp data-testid="app" className="App" style={{position: 'relative'}}>
      <Container />
    </StyledApp>
  );
}

export default App;

//源代码/容器. js

import React from 'react'
import styled from 'styled-components'

import ThingOne from "./thing_one";
const StyledContainer = styled.div`
  display: block;
`

class Container extends React.Component {
  constructor(props) {
    super(props)
    this.thing_one_ref = React.createRef()
    this.state = {
      message: ""
    }
  }

  componentDidMount() {
    setTimeout(() => {
      this.setState({message: "A test of refs"})

      // here's the console.log
      console.log(this.thing_one_ref.current.getBoundingClientRect())
    }, 1000)
  }

  render() {
    const {message} = this.state
    return (
      <StyledContainer>
        {message}
        <ThingOne ref={this.thing_one_ref}/>
      </StyledContainer>
    )
  }
}

export default Container


//源代码/一件事. js

import React from 'react'
import styled from 'styled-components'

const StyledThingOne = styled.div`
  display: block;
  width: 100px;
  height: 100px;
  position: relative;
  top: 20%;
  left: 20%;
  border: solid 1px black;
  margin: 20px;
`
const ThingOne = React.forwardRef((props, ref) => (
      <StyledThingOne ref={ref}></StyledThingOne>
));

export default ThingOne

我如何让测试环境表现得好像它安装在一个真实的的DOM中一样,并带有一个笛卡尔平面,我可以用它来做三角学和动画?我有一些工作代码,它们依赖于getBoundingClientRect()的结果,看起来像这样(如上所述,在浏览器中工作)

DOMRect {x: 225.1875, y: 38, width: 102, height: 102, top: 38, …}

完整的源代码可以在这里引用:
https://github.com/jasonfb/jest-playground-3

sdnqo3pr

sdnqo3pr1#

我不确定这是否超出了您当前的需求,但是您可以考虑在实际的浏览器(真实的的DOM环境)上运行测试套件,而不是在jsdom上运行,Jest使用x1e0 f1 a在Node.JS上模拟类似浏览器的环境。
您可以考虑使用SeleniumCypress等测试框架在Chrome等受支持的浏览器上进行测试,这将允许您进行集成测试(您正在尝试实现的测试),并在将来在浏览器上进行端到端测试,这将消除在Node.JS上模拟/存根/模拟DOM元素的需要。

h43kikqp

h43kikqp2#

晚到派对,但也许这可以帮助,在您的测试中,您可以覆盖getBoundingClientRect的默认HTMLElement方法,并返回模拟结果,如下所示:

function domRect(x, y, width, height) {
    return {x, y, width, height, top: y, bottom: y + height, left: x, right: x + width} as unknown as DOMRect
}

// imagine you want to mock DOMRect for a certain element with data-testid="testid"
const mockRect = domRect(0, 0, 150, 50)

const mockBoundingClientRects = () => {
    const getBoundingClientRect = HTMLElement.prototype.getBoundingClientRect;
    HTMLElement.prototype.getBoundingClientRect = function() {
        const elmt:HTMLElement = this;
        // implement here ways to differentiate elements you want to override getBoundingClientRect for
        // here we're looking for element with data-testid="testid"
        if ((elmt.children?.[0] as HTMLElement)?.dataset?.testid === 'testid') {
            return mockRect
        }
        return getBoundingClientRect.bind(this)()
    }
}

然后,您可以在测试内部或步骤之前调用mockBoundingClientRect()。
您可能还希望模拟window.innerHeight/innerWidth和/或window.scrollX/scrollY,为此只需在测试中将它们设置为所需的值。
希望这能有所帮助。

相关问题