EmberJS: Test components html without rendering - javascript

As far as I understand glimmer, embers new rendering engine, has a kind of virtual-dom implementation which is diffing for changes and updates the UI accordingly to those changes. To gain some speed in our tests I thought, it should be possible to use this this virtual dom to test a component without rendering it in the browser/phantomjs. In my normal integration tests I would do something like this:
it('shows a textarea', function(){
this.render(hbs`{{my-component}}`); // don't render here
const $textarea = this.$('textarea');
expect($textarea).to.have.length(1);
});
So my question is if there is a way to access this virtual dom in a unit/integration test.
Thanks

Related

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.

React best-practices -- pure or non-pure components? fetching data in componentWillMount?

I'm messing around with React in Meteor. There seem to be two ways of going about things...
Given the meteor leaderboard example, we have a list of players that render a name and a score.
The pure way of doing things is fetch all the players and pass into the playersList component which then divvies up to playerItem components. Everything is done with props and these templates are pure. Whenever a player changes, we can use Meteor's reactivity to re-render everything with React
Tracker.autorun =>
players = Players.find().fetch()
React.render(React.createElement(PlayersList, {players:players}), document.body)
(the function passed to autorun will rerun whenever a player changes)
This is pretty much exactly what Pete Hunt did in his Meteor-React presentation demo.
Now the other way of doing this which seems much more efficient and fine-grained, but not pure. That is to pass the PlayersList component a list of playerIds. Pass the PlayerItem component a playerId and have the PlayerItem fetch the specific player and render the players name and score from the component's state.
// inside the PlayerItem component
componentWillMount: =>
Tracker.autorun =>
this.setState('player', Players.findOne(this.props.playerId))
Now the PlayerItem is not pure. Whenever a player's score changes, only the PlayerItem representing that player will be re-rendered. If we make sure to pass the PlayersList only a list of playerIds, then the PlayersList component will only be re-rendered whenever a player is added or removed.
Tracker.autorun =>
playerIds = _.pluck('_id',Players.find({}, {fields:{_id:1}}).fetch())
React.render(React.createElement(PlayersList, {playerIds: playerIds}), document.body)
This makes sense because now we have fine-grained control over React's render cycle and we're not bombarding react with the entire state of every player whenever one thing changes. However, this doesnt seem in the spirit of the way React was designed. Now we have internal state everywhere and our components are not pure!
It is my impression that the way React wants me to do things is use global state and pure components, and just rely on the fact that React's reconciliation is super fast and efficient. This just makes me slightly uncomfortable because the non-pure way seems much more efficient.
Anyways, I just started with React, so although I read all the documentation, I'm not confident that I know what I'm talking about. So I'm wondering -- when should I stick with pure components and when is it ok to have non-pure components? Should I ever fetch data within a component or should I treat react strictly as a rendering engine?
There's very little difference between React.render and doing it inside the top level component. Either way it updates the states or props, renders, and diffs the old/new virtual dom.
I would have PlayerList fetch all of the players, and pass those down to PlayerItem components. You should be binding to external apis in componentDidMount, and make sure to unbind in componentWillUnmount. The componentWillMount function has a similar role to constructors: set up any non-state instance properties.
PlayerItem should implement shouldComponentUpdate for performance. You can do this when you have some free time, as it's an optimization that doesn't affect the rest of the code.
As a side note, you can implement a mixin that helps with the meteor bindings.
var MeteorMixin = {
getInitialState: function(){
return this.getUpdatedState();
},
componentDidMount: function(){
this._meteorMixinComputation = Tracker.autorun(function(){
this.setState(this.getUpdatedState());
}.bind(this));
},
componentWillUnmount: function(){
this._meteorMixinComputation.stop();
}
};
And then your component will look like:
mixins: [MeteorMixin],
getUpdatedState: -> {players: Players.find({}).fetch()}
render: ->
...
Disclaimer: I don't use meteor, so this might be way off.

Why does React require jsdom for testing?

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.

Categories

Resources