Why does React require jsdom for testing? - javascript

When writing tests for React components, you have to render them into the DOM in order to make assertions about their correctness. For example, if you want to test that a certain class is added to a node given a certain state, you have to render into a DOM node, then inspect that DOM node via the normal DOM API.
The thing is, considering React maintains a virtual DOM into which it renders, why can't we just assert on the virtual DOM once the component is rendered? That seems to me like a very good reason to have something like the virtual DOM.
Have I missed something?

You haven't really missed anything. We're working on making this better. The virtual parts have always been very much an implementation detail of React, not exposed in any useful or reliable way for testing. We have some methods in our test helpers which wrap up the internal lookups which sometimes avoids looking at the actual DOM but we need more.

Related

In React, is it okay to use getElementById, querySelector, etc versus useRef if you don't perform any DOM manipulation?

Specifically used just to view the heights/widths (getBoundingClientRect) of elements. I recently encountered a need to find all the separate heights of a dynamic amount of child elements to perform a calculation. I added a ref within the child component, and passed a function down from the parent in an attempt to update the parent's list of child dimensions (which was in state). I found this to be overtly complex and confusing and unreliable. So, in the parent, I just did a simple for loop with getElementById after giving each child an id of child-${index}.
I know you are NOT supposed to do any direct DOM manipulation in React; however, if your goal is read some data only, then is it an issue or bad practice?
It might not be a problem right now, but I would consider using getElementById instead of a ref bad practice in general (or at least call it "a workaround").
1
getElementById works "outside" of React, so you are not using React here.
That might work for now, but also might interfere with what might do React at some time.
E.g. you might access or hold a reference to a DOM node, and React might decide to remove that node while you were reading it. I don't see why this might happen in your
example, but when using two separate systems it is hard to keep track of the possible consequences.
2
With the id child-${index} you have introduced a logical dependency (coupling) between the parent and the child.
The id child-${index} acts as a reference here, and has to be kept in sync manually.
This might be easier in a short term, but is actually more complex as a general approach (e.g. less maintainable, reusable, ...).
You could say, Reacts whole purpose is to avoid such complexities.
Your components should be as independent of each other as possible, and should only communicate through the props.
suggestion
I suggest to avoid both getElementById and passing a ref, and have the children know their size (e.g. using a custom hook),
and pass only the sizes up to the parent (not the ref).
If that is not possible, I would prefer to use refs.
Also note that "confusion" is not the same as "complexity": Confusion can be decreased by acquiring more information, but complexity is an
inherent property of a system.

Diff between DebugElement and DOM element

In angular unit testing using jasmine, we can test the view (html content) in two ways.
Getting the elements from DebugElement
fixture.debugElement.queryAll(By.css('.tableData.billStatus.text-center'))
Getting the elements from DOM.
fixture.debugElement.nativeElement.querySelectorAll('.tableData.billStatus.text-center')
My question is not related to queryAll vs querySelectorAll. It is DOM vs DebugElement. Because when I use either of them, they give me the correct result most of the time.
This question has some relation to this issue
They give a work around to look through DOM elements as opposed to DebugElement as a work around. So what makes these two differ from each other?
I have looked through several posts for the difference, before making this question. But I did not find anything appropriate to this.
debug element contains references and methods to a component or element whereas native element is a reference to the DOM element.
The Usage of DebugElement vs NativeElement depends on your scenario:
If you are going to run your tests only on the browser, then NativeElement is enough, since the tests will be run on the browser, the DOM will be available for NativeElement to do its operations.
If you are going to run your tests on server or some pipeline where the browser platform is not available, then you should use DebugElement, as it will wrap the native elements of the runtime platform, so that you can do query on non-browser supported platforms too.

Should I manipulate DOM directly or using React state/props?

This is the situation:
This component renders many data as a list. If I use React state/props to control the DOM style(add classes or modify some attributes), React will always run the render() function when user reacts with the list, like mouseover, click and etc..
Though React has virtual DOM technology, but I think it is still very inefficient to run render() every time. The documents do not recommend to manipulate DOM directly, but I think it is more efficient. What should I do? Thx.
I wouldn't mix writing React with directly manipulating the DOM; do either but not both.
If you are already using React, just use it for what you want. If possible, break the components into as small of pieces as possible; this will help the number renders.
It may be slightly more inefficient to have React re-render too much, but remember that React has been heavily optimized for DOM manipulation.
As far as rerendering in react is concerned, it has been heavily optimised. You may think that the render() function runs on every small manipulation but the thing that is not visibile is that the rerender doesn't occur for the entire DOM rather on only the portion that has changed.
React uses the virtual DOM technology and then it takes out the difference between the current and the virtual dom much like string comparison and then only renders the difference and is thus highly efficient.
So I would recommend you to follow the documentation and not mix DOM manipulation with react.

renderIntoDocument clean up after test

I am looking at the React Test Utilities docs, in particular at the renderIntoDocument function:
Render a component into a detached DOM node in the document.
I am wondering whether I should be doing anything with the component that I've rendered once I'm done testing?
This works:
const component = ReactTestUtils.renderIntoDocument(createElement(MyThing));
// do tests
unmountComponentAtNode(findDOMNode(component).parentElement);
but I'm wondering if this step is necessary, since it isn't mentioned in the docs. Does my current approach actually achieve anything useful, or can I just use renderIntoDocument without worrying about tidying up?

What is "Mounting" in React js?

I am hearing the term "mount" too many times while learning ReactJS. And there seem to be lifecycle methods and errors regarding this term. What exactly does React mean by mounting?
Examples: componentDidMount() and componentWillMount()
The main job of React is to figure out how to modify the DOM to match what the components want to be rendered on the screen.
React does so by "mounting" (adding nodes to the DOM), "unmounting" (removing them from the DOM), and "updating" (making changes to nodes already in the DOM).
How a React node is represented as a DOM node and where and when it appears in the DOM tree is managed by the top-level API. To get a better idea about what's going on, look at the most simple example possible:
// JSX version: let foo = <FooComponent />;
let foo = React.createElement(FooComponent);
So what is foo and what can you do with it? foo, at the moment, is a plain JavaScript object that looks roughly like this (simplified):
{
type: FooComponent,
props: {}
}
It's currently not anywhere on the page, i.e. it is not a DOM element, doesn't exist anywhere in the DOM tree and, aside from being React element node, has no other meaningful representation in the document. It just tells React what needs to be on the screen if this React element gets rendered. It is not "mounted" yet.
You can tell React to "mount" it into a DOM container by calling:
ReactDOM.render(foo, domContainer);
This tells React it's time to show foo on the page. React will create an instance of the FooComponent class and call its render method. Let's say it renders a <div />, in that case React will create a div DOM node for it, and insert it into the DOM container.
This process of creating instances and DOM nodes corresponding to React components, and inserting them into the DOM, is called mounting.
Note that normally you'd only call ReactDOM.render() to mount the root component(s). You don't need to manually "mount" the child components. Every time a parent component calls setState(), and its render method says a particular child should be rendered for the first time, React will automatically "mount" this child into its parent.
React is an isomorphic/universal framework. That means that there is a virtual representation of the UI component tree, and that is separate from the actual rendering that it outputs in the browser. From the documentation:
React is so fast because it never talks to the DOM directly. React maintains a fast in-memory representation of the DOM.
However, that in-memory representation is not tied directly to the DOM in the browser (even though it is called Virtual DOM, which is an unfortunate and confusing name for an universal apps framework), and it is just a DOM-like data-structure that represents all the UI components hierarchy and additional meta-data. Virtual DOM is just an implementation detail.
"We think the true foundations of React are simply ideas of components and elements: being able to describe what you want to render in a declarative way. These are the pieces shared by all of these different packages. The parts of React specific to certain rendering targets aren't usually what we think of when we think of React." - React js Blog
So, the conclusion is that React is Rendering agnostic, which means that it doesn't care about what is the final output. It can be a DOM Tree in the browser, it can be XML, Native components or JSON.
"As we look at packages like react-native, react-art, react-canvas, and react-three, it's become clear that the beauty and essence of React has nothing to do with browsers or the DOM." - React js Blog
Now, that you know how React works, it is easy to answer your question :)
Mounting is the process of outputting the virtual representation of a component into the final UI representation (e.g. DOM or Native Components).
In a browser that would mean outputting a React Element into an actual DOM element (e.g. an HTML div or li element) in the DOM tree. In a native application that would mean outputting a React element into a native component. You can also write your own renderer and output React components into JSON or XML or even XAML if you have the courage.
So, mounting/unmounting handlers are critical to a React application, because you can only be sure a component is output/rendered when it is mounted. However, the componentDidMount handler is invoked only when rendering to an actual UI representation (DOM or Native Components) but not if you are rendering to an HTML string on the server using renderToString, which makes sense, since the component is not actually mounted until it reaches the browser and executes in it.
And, yes, Mounting is also an unfortunate/confusing name, if you ask me. IMHO componentDidRender and componentWillRender would be much better names.
Mounting refers to the component in React (created DOM nodes) being attached to some part of the document. That's it!
Ignoring React you can think of these two native functions as mounting:
replaceChild
appendChild
Which are likely the most common functions React uses to mount internally.
Think of:
componentWillMount === before-mount
And:
componentDidMount === after-mount
https://facebook.github.io/react/docs/tutorial.html
Here, componentDidMount is a method called automatically by React when a component is rendered.
The concept is that you're telling ReactJS, "please take this thing, this comment box or spinning image or whatever it is I want on the browser page, and go ahead and actually put it on the browser page. When that's done, call my function that I've bound to componentDidMount so I can proceed."
componentWillMount is the opposite. It will fire immediately BEFORE your component renders.
See also here
https://facebook.github.io/react/docs/component-specs.html
Finally, the "mount" term seems to be unique to react.js. I don't think it is a general javascript concept, or even a general browser concept.
Mounting refers to the initial page loading when your React component is first rendered. From React documentation for Mounting: componentDidMount:
Invoked once, only on the client (not on the server), immediately after the initial rendering occurs. At this point in the lifecycle, the component has a DOM representation which you can access via React.findDOMNode(this).
You can contrast this with componentDidUpdate function, which is called everytime that React renders (except for the initial mount).
The main goal of React js is to create reusable components. Here, components are the individual parts of a webpage. For example, in a webpage the header is a component, the footer is a component, a toast notification is a component and etc. The term "mount" tells us that these components are loaded or rendered in the DOM. These are many top-level APIs and methods dealing with this.
To make it simple, mounted means the component has been loaded to the DOM and unmounted means the components has been removed from the DOM.

Categories

Resources