How to access elements outside of root during react testing? - reactjs

So I have an index.html file like this where there is a span outside of root div.
// index.html
<div id="root" class="root-container">
<div class="splash-holder">
<div class="triangle-holder">
<div class="triangle four"></div>
<div class="triangle five"></div>
<div class="triangle six"></div>
</div>
</div>
</div>
<span class="hidden-tag" id="hidden-span"></span>
and my Index.js file looks like this, where you can see main app is being rendered inside root-container.
// index.js
const MainApp = () => (
<Provider store={store}>
<Foo />
</Provider>
);
ReactDOM.render(<MainApp/>, document.querySelector('.root-container'));
and my Foo component file is like the following.
// Foo.js
const Foo = () => {
const ele = document.getElementById('hidden-span');
ele.innerHTML = 'dsaas';
}
Though this works fine in the actual app but when I try to render component using react testing library. eg.
// Foo.test.js
import { render } from '#testing-library/react';
import Foo from ./components;
render(<Foo />);
I get the error that cannot find innerHTML of null. How can I solve this issue?

Related

How to get the whole components tree in jest and testing-library/react-native?

I have a component that I am testing using jest and react native testing library
that looks something like this :
<FallbackErrorBoundary>
<Wrapper>
<Component1>
<Component2>
</Component2>
</Component1>
</Wrapper>
</FallbackErrorBoundary>
I want to get the whole rendered tree , I tried using
renderedComponent.container.children
But It only gets the direct children (FallbackErrorBoundary)
I tried using expect(renderedComponent).toMatchSnapshot()
but It's not very helpful
You can use prettyDOM or asFragment
E.g.
import React from 'react'
import { render, prettyDOM } from '#testing-library/react'
const HelloWorld = () => <h1>Hello World</h1>
const {container, } = render(<HelloWorld />)
const treeString = prettyDOM(container);
console.log(treeString)
// <div>
// <h1>Hello World</h1>
// </div>
expect(asFragment()).toMatchInlineSnapshot(`
<DocumentFragment>
<h1>
Hello World
</h1>
</DocumentFragment>
`);
If you don't want DocumentFragment element, you can use asFragment().firstChild.

document.getElementById() equivalent in React 2020

I have a component called Button.js that has a button that when clicked i simply would like to know if i am accessing the a div in another component called Timer.js. In vanilla javascript i would simply use document.getElementById() to capture the DOM node. How is this done in React?
I came across callback-refs in the docs but it isn't working. If using a ref isn't the React way of accessing DOM elements please refer me to the best way to do this. thanks in advance.
Button.js
function Button() {
const getHtml = () => {
const node = test.current;
console.log(node);
}
return (
<button onClick={getHtml}>GetHtml</button>
)
}
Timer.js
function Timer() {
const test = useRef(null);
return (
<div ref={test}>... </div>
<Button />
}
I would not use a reference to check if a component is rendered inside of another one.
You could get what you're looking for with createContext and useContext.
(It could work like you tried it. If you'd pass the ref to the button as a prop.)
With the context: You create a TimerContext.Provider in your Timer component and in your button you can check with useContext(TimerContext) if the expected key is in the object. If it's not there then the button is not inside of your Timer.
Please have a look at the snippet below or in the following Codesandbox.
//import React, { useContext, createContext } from "react";
//import "./styles.css";
const { useContext, createContext } = React;
const ContainerContext = createContext({
isInContainer: null
});
const Container = () => {
return (
<ContainerContext.Provider value={{ isInContainer: true }}>
<p>
In container:
<Button />
</p>
</ContainerContext.Provider>
);
};
const Button = () => {
const { isInContainer } = useContext(ContainerContext);
console.log(isInContainer);
const isInside = () => {
alert(isInContainer ? "clicked inside" : "not in container");
};
return <button onClick={isInside}>Click me</button>;
};
function App() {
return (
<div className="App">
<Container />
<Button />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
Update 15.04.2020
The question was not clear to me at first but now I understand the use-case. The idea is to have an Editor component where you're writing markup that can be used to generate a copied snippet view and/or a html markup output.
For this the best is to use a reference to the Editor component and pass it as prop to the preview/output component - it would be also possible with a context but passing it is easier.
Like in the following Sandbox.

React: How to mount all components on page?

I want to be able to mount React components based on the HTML markup of a document rendered by a PHP framework and I can't find a way to achieve this.
Here is the HTML markup of my document:
<html>
<head>
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<div id="app">
<Foo bar="lorem"></Foo>
<Foo bar="ipsum"></Foo>
<Foo bar="dolor"></Foo>
</div>
<script src="js/index.js"></script>
</body>
</html>
Here is the Foo component implementation (foo.js):
const React = require('react');
class Foo extends React.Component {
render() {
return React.createElement('div', {
className: 'foo'
}, `Hello ${this.props.bar}`);
}
}
module.exports = Foo;
And here is my App implementation (app.js):
const React = require('react');
const ReactDOM = require('react-dom');
require('./foo');
ReactDOM.render(
React.createElement('div'),
document.getElementById('app')
);
module.exports = {};
I'm expecting React to recursively mount every components found inside the #app div but for some reason only the #app div is mounted resulting in the following markup:
<div id="app">
<div data-reactroot=""></div>
</div>
I can't put my fingers on what I am doing wrong here.
So, in you app.js when you are rendering react DOM
ReactDOM.render(
React.createElement('div'),
document.getElementById('app')
);
In this case you are creating a div element and rendering it inside root div with id=app
In order to create multiple foo elements all you have to do is this
const Foo = require('./foo');
ReactDOM.render(
<div>
<Foo bar="lorem"></Foo>
<Foo bar="ipsum"></Foo>
<Foo bar="dolor"></Foo>
</div>
document.getElementById('app')
);
Hope this helps

empty component after react render

I'm trying to render a react component inside a html page. what i did so far is implementing react like this
var component = React.createClass({
render: function(){
var testStyle = { fontSize: '18px', marginRight: '20px'};
return (
<div>
<h1>Hello React</h1>
<div><ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul></div>
</div>
)
}
});
ReactDOM.render(< component/>,
document.getElementById('content')
);
and in the HTML page i have this
<div id="content"></div>
when i inspect the HTMl page i find that inside the div i have an empty component like this
<component data-reactroot=""></component>
what am i doing wrong here
A React component must always start with a capital letter, otherwise React interprets it as a simple HTML element.
Capitalized types indicate that the JSX tag is referring to a React component.
That being said, define
const Component = React.createClass...
and then render like
ReactDOM.render(<Component />,
document.getElementById('content')
);

How to get innerHTML of ReactDOM mounted element

HTML markup like this:
<div id="my-component">
<div>Some content goes here</div>
</div>
Having this in app.js file:
ReactDOM.render(<MyComponent/>, document.getElementById('my-component));
I want to get innetHTML of #my-component before that react component is mounted.
Using ReactDOM.findDOMNode in componentWillMount is not working because the element is not still mounted so returns null and in componentDidMount innerHTML has been replaced.
I did the following to achieve this:
const el = document.getElementById('my-component');
ReactDOM.render(
<App>{el.innerHTML}</App>,
el
);
Then in my react component I can render the html like so:
render() {
return (
<div dangerouslySetInnerHTML={{__html: this.props.children}}></div>
);
}

Resources