简体   繁体   English

在反应测试库中使用 DOM 元素?

[英]Working with DOM elements in react testing-library?

I have what I think is a general question about working with DOM elements in React Testing library.我有一个关于在 React 测试库中使用 DOM 元素的一般性问题。

Essentially, I have a couple of nested components, one of which creates a React ref that is forwarded down to some child components (code below).本质上,我有几个嵌套组件,其中一个创建了一个 React ref,它被转发到一些子组件(下面的代码)。

When it does this, it then renders the child components and checks the nested Ref to call .getBoundingClientRect() a magical native Javascript function that gives me the x and y positioning, the width & height, and top, bottom, left & right bounds.当它执行此操作时,它会渲染子组件并检查嵌套的 Ref 以调用.getBoundingClientRect()一个神奇的原生 Javascript 函数,该函数为我提供 x 和 y 定位、宽度和高度以及顶部、底部、左侧和右侧边界. I really need this information because I want to do some other things with it, without directly modifying the DOM (I am making all my DOM modifications using setState and letting React re-render the DOM)我真的需要这些信息,因为我想用它做一些其他事情,而不直接修改 DOM(我正在使用 setState 进行所有 DOM 修改并让 React 重新渲染 DOM)

In development (Chrome), when I do console.log(this.thing_one_ref.current.getBoundingClientRect()) I get this result:在开发(Chrome)中,当我执行console.log(this.thing_one_ref.current.getBoundingClientRect())我得到这个结果: 在此处输入图像描述

(you'll note that thing_one_ref here is correctly populated once my app renders-- not before-- and looks like:) (您会注意到,一旦我的应用程序呈现 - 而不是之前 - 并且看起来像这样,这里的 thing_one_ref 就会正确填充:)

在此处输入图像描述

I have a simple spec for this code, which happens to pass, but even though it passes, the console logged output when in the test environment looks like this:我对此代码有一个简单的规范,它恰好通过了,但即使它通过了,在测试环境中控制台记录的输出看起来像这样:

在此处输入图像描述

Notice that all of the values are 0 instead of what I am expecting, which is the element to be rendered as-if it were on a real DOM请注意,所有值都是 0 而不是我所期望的,这是要呈现的元素,就好像它在真实的 DOM 上一样

// src/App.test.js // src/App.test.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());
});

// src/App.js // src/App.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;

// src/container.js // src/container.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

// src/thing_one.js // src/thing_one.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

How do I get the test environment to behave as-if it is mounted in a real DOM, complete with a cartesian plane that I can use for trigonometry and animation ?如何让测试环境表现得就像它安装在真实的 DOM 中一样,并配有可用于三角函数动画笛卡尔平面 I have some working code that depends on the result of getBoundingClientRect() looking something like this result (as said above, work in browser)我有一些工作代码取决于getBoundingClientRect()的结果,看起来像这个结果(如上所述,在浏览器中工作)

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

complete source code can be referenced here:完整的源代码可以参考这里:

https://github.com/jasonfb/jest-playground-3 https://github.com/jasonfb/jest-playground-3

I am not sure if this goes beyond your current requirements, but you may consider running your test suites on an actual browser (real DOM environment), rather than jsdom , which is used by Jest to simulate a browser-like environment on Node.JS.我不确定这是否超出了您当前的要求,但您可以考虑在实际浏览器(真实 DOM 环境)上运行测试套件,而不是jsdom ,Jest 使用 jsdom 在 Node.JS 上模拟类似浏览器的环境.

You may consider using test frameworks like Selenium and Cypress to carry out tests on supported browsers such as Chrome.您可以考虑使用SeleniumCypress等测试框架在 Chrome 等受支持的浏览器上进行测试。 This will allow you to carry out Integration testing (what you are trying to achieve), and in the future, End to End testing on the browser.这将允许您执行集成测试(您想要实现的目标),以及将来在浏览器上进行端到端测试。 This will eliminate the need to mock/stub/simulate DOM elements on Node.JS.这将消除在 Node.JS 上模拟/存根/模拟 DOM 元素的需要。

Late to the party but perhaps this can help, In your tests you can override the default HTMLElement method for getBoundingClientRect and return mocked results just like this:迟到了,但也许这会有所帮助,在您的测试中,您可以覆盖 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)()
    }
}

You can then call mockBoundingClientRect() inside your test or before step.然后,您可以在测试中或在步骤之前调用 mockBoundingClientRect()。

You will probably also want to mock window.innerHeight/innerWidth and/or window.scrollX/scrollY, for that simply set them to desired values in your test.您可能还想模拟 window.innerHeight/innerWidth 和/或 window.scrollX/scrollY,因为只需在测试中将它们设置为所需的值。

hope this can help.希望这能有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 React Testing-Library 在事件触发时测试 DOM 更改 - React Testing-Library testing DOM changes on event fire @testing-library/React:在组件外部单击不起作用 - @testing-library/React : Clicking outside of component not working @testing-library/jest-dom 未加载 - @testing-library/jest-dom not loading 使用测试库测试弹出组件以进行反应 - Testing popover components with testing-library for react Jest + @testing-library/react 在 [dom-accessibility-api] 库中的 a.mjs 文件上抛出错误 - Jest + @testing-library/react throws error on a .mjs file from [dom-accessibility-api] library 在将 @testing-library/jest-dom 版本从 4.0.0 更新到 4.2.0 时反应测试用例失败 - On updating @testing-library/jest-dom version from 4.0.0 to 4.2.0 react test case is failing React + Jest + testing-library:“请至少升级到 react-dom@16.9.0 以删除此警告。” …但是 react-dom 已经是 16.9.0 - React + Jest + testing-library: “Please upgrade to at least react-dom@16.9.0 to remove this warning.” …but react-dom is 16.9.0 already @testing-library/react 测试表单 onSubmit - @testing-library/react test form onSubmit 找不到模块'@testing-library/react' - Cannot find module '@testing-library/react' 使用 @testing-library/react 测试 antd 下拉列表 - Test antd dropdown with @testing-library/react
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM