I am building out tests in my React app that was built with create-react-app and I'm trying to understand what the difference is between screen.getByText() and simply getByText(). For instance, the documentation shows this kind of example:
import React from 'react';
import { render, screen } from '#testing-library/react';
import App from './App';
it('renders a title of "Dashboard"', () => {
render(<App />);
expect(screen.getByText('Dashboard')).toBeInTheDocument();
});
But I see that I can do this:
it('renders a title of "Dashboard"', () => {
const { getByText } = render(<App />);
expect(getByText('Dashboard')).toBeInTheDocument();
});
I haven't found what the difference is between using screen.getByText() vs. simply using getByText() like I've shown above.
What are the differences, and are there advantages in using one over the other in various scenarios?
It's a convenience thing. Using screen you'll find that you no longer need to constantly/explicitly have to destructure the return value of the render method to get to the selector functions (that's basically it).
The PR that introduced the feature has a clear explanation of the rationale behind it:
https://github.com/testing-library/dom-testing-library/pull/412
The only caveat is in the scenario where you provide an explicit container argument to the render method - as the screen based selector would match all elements on the document.body (where as if you destructure the render result, the selector functions will be scoped to elements within the container you provided).
If you're starting out with that library I also suggest that you take a peek into this Kent Dodds article (the same who introduced the feature and a person which is a big reference in this area), which has a bunch of goodies/best practices using testing-library with the rationale behind each recommendation:
https://kentcdodds.com/blog/common-mistakes-with-react-testing-library
Related
Almost all examples (even the official documentation) use mobx-react-light in combination with useContext() hook.
However, React, many articles and blog-posts advice to NOT USE useContext() for middle/high frequent updates. Isn't state something which can update very frequenty?
Should one use the package in combination with the hook or will performance issues occur?
useContext() is only used to get your store value (reference) and this value is not updated frequently, usually you only set your stores once and don't touch it after. When you use actions you only change observable values of your store and not the store itself. So basically Context is only used to pass reference to the store down the tree, after that all the work performed by MobX only.
Example from MobX docs:
import {observer} from 'mobx-react-lite'
import {createContext, useContext} from "react"
const TimerContext = createContext<Timer>()
const TimerView = observer(() => {
// Grab the timer from the context.
const timer = useContext(TimerContext) // See the Timer definition above.
return (
<span>Seconds passed: {timer.secondsPassed}</span>
)
})
ReactDOM.render(
<TimerContext.Provider value={new Timer()}
<TimerView />
</TimerContext.Provider>,
document.body
)
So you pass value of new Timer() to TimerContext.Provider once when you render your app and it will never be changed or updated after that. Even docs says:
Note that we don't recommend ever replacing the value of a Provider with a different one. Using MobX, there should be no need for that, since the observable that is shared can be updated itself.
However, if you don't have SSR or don't test your app, then you don't even need to use Context at all, you can just use global variables/singletons as your stores and it will work perfectly fine.
Example:
// Initialize timer somewhere
export const myTimer = new Timer()
// You can use directly in the same file or import somewhere else
import { myTimer } from './file-with-your-timer'
// No props, `myTimer` is directly consumed from the closure or from another file
const TimerView = observer(() => <span>Seconds passed: {myTimer.secondsPassed}</span>)
ReactDOM.render(<TimerView />, document.body)
Quote from docs:
Using observables directly works very well, but since this typically introduces module state, this pattern might complicate unit testing. Instead, we recommend using React Context instead.
More about best practices with React: https://mobx.js.org/react-integration.html
I'm confused on the point of React.forwardRef. As explained in its documentation, I understand that its main use is for a Parent Component to gain access to DOM elements of the Child Component. But I can already do that without even having to use it.
Here is a code example that you can plug into CodeSandbox and see that it works:
import React, {useRef, useEffect} from "react";
import "./styles.css";
const ChildComponent = (props) => {
useEffect( ()=> {
props.callbackFunction()
})
return(
<div ref={props.fRef}>
{"hello"}
</div>
)
}
export default function App() {
const callbackFunction = () => {
console.log("The parent is now holding the forwarded ref to the child div: ")
console.log(forwardedRef)
}
const forwardedRef = useRef(null)
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<ChildComponent name="gravy" callbackFunction={callbackFunction} fRef={forwardedRef}/>
</div>
);
}
Or here's the embed of this example. Honestly, I'm kind of new to this and I don't know exactly how embeds work and whether someone fiddling with the embed changes my original Sandbox or not, so I was hesitant to put it. But here it is.
Example Forwarding Ref
In the example, the parent App() component successfully passes a ref to the child which the child attaches to its rendered div. After it renders, it calls a callback function to the parent. The parent then does a console log where it proves that its forwarded ref now has a hold of the child's div. And this is all done without React.forwardRef.
So what then is the use for React.forwardRef?
You're absolutely right that you can do what you've described. The downside is that you're forced to expose an API (ie: the fRef prop) for it to work. Not a huge deal if you're a solo developer building an app, but it can be more problematic eg. if you're maintaining an open-source library with a public API.
In that case, consumers of the library won't have access to the internals of a component, meaning you'd have to expose it for them somehow. You could simply do what you're suggesting in your example and add a named prop. In fact, that's what libraries did before React 16.3. Not a huge deal, but you'd have to document it so people know how to use it. Ideally, you'd also want some kind of standard that everyone used so it wasn't confusing (many libraries used the innerRef naming convention), but there'd have to be some consensus around that. So all doable, but perhaps not the ideal solution.
Using forwardRef, passing a ref to a component just works as expected. The ref prop is already standardized in React, so you don't need to go look at docs to figure out how to pass the ref down or how it works. However, the approach you describe is totally fine and if it meets your needs, by all means go with that.
As mentioned in the docs , it's useful for highly reusable components, meaning components that tend to be used like regular HTML DOM elements.
This is useful for component libraries where you have lots of "leaf" components. You've probably used one like Material UI.
Example:
Let's say you're maintaining a component library.
You create a <Button/> and <Input/> component that maybe just adds some default styling.
Notice how these components literally are just like regular HTML DOM elements with extra steps.
If these components were made to be used like regular HTML DOM elements, then I expect all the props to be the same, including ref, no?
Wouldn't it be tedious if to get the button ref from your <Button/> component I'd have to get it through something like fRef or buttonRef ?
Same with your <Input/>, do I have to go to the documentation just to find out what ref to use and it's something like inputRef ? Now I have to memorize?
Getting the ref should be as simple as <Button ref={}/>
Problem
As you might know, ref will not get passed through props because, like key, it is handled differently by React.
Solution
React.forwardRef() solves this so I can use <Button ref={}/> or <Input ref={}/>.
Here's a line from one of my React Testing Library tests:
expect(queryByTestId('tile-sample-service')).toHaveClass('regularTile-0-2-24', 'btn', 'btn-outline-secondary');
While it works, the test is fragile because every time the structure of the component changes, I need to go back and fix the numbers, which have changed.
Is there a way to use toHaveClass with RegEx queries or is there some other way to check if classes are present but avoid having to add things like "0-2-24" ?
Yeah for some CSS in JS generated class names sometimes the number suffix changes.
Something like this should work:
const currentLinkAnchorEl = getByText(container, 'My Currently Active Link').closest('a');
expect(currentLinkAnchorEl.className).toMatch(/mySelectedActiveClassName/)
I think it's not possible with toHaveClass(...classNames: string[]),but you can use Shallow Renderer,try this one
import ShallowRenderer from 'react-test-renderer/shallow';
it('match claas name', () => {
const renderer = new ShallowRenderer();
renderer.render(<Component />);
expect(renderer.getRenderOutput().props.className).toMatch(/button/i);
})
I have noticed that certain libraries such as classnames are readily available in Preact but others like styled-components require preact-compat.
What makes a React library unsupported natively in preact that it requires the use of preact-compat?
Disclaimer: I work on preact.
There are several APIs in react that are not needed for preact. But because existing third-party libraries have been developed for those APIs we published preact-compat which re-implements them on top of preact.
Some examples:
Children-API:
This API is in particular interesting because it isn't needed at all for preact. With preact the children property is always an array.
// React
Children.forEach(props.children, child => ...);
Children.map(props.children, child => ...);
Children.count(props.children);
// Preact
props.children.forEach(child => ...);
props.children.map(child => ...);
props.children.length;
unmountComponentAtNode:
This is another API that is not needed for preact, because we can simply unmount any tree by rendering null:
import { render } from "preact";
import App from "./app";
// Render App into dom
render(<App />, document.getElementById("root"));
// Unmount tree
render(null, document.getElementById("root"));
If you want to drop a subtree instead of the root node you can do that via returning null from a component. Basically null is always treated as an empty value.
findDOMNode:
// React
const element = React.findDOMNode(componentInstance);
// In Preact that's just a property
const element = componentInstance.base;
In our case this even works for function components. Note that in nearly all cases refs are preferred over findDOMNode.
Summary: preact-compat contains mostly shims for third-party libraries expecting full API compatibility with react.
In React JS documentation,
it is mentioned Elements are the smallest building blocks of ReactJS.
But, Components are also built, in order to create Elements.
For example,
const element = <Welcome name="Sara" title="Mara"/>;
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
So, Component (here Welcome function component) was smallest building block that helped create an Element.
So, Does it mean Components are the smallest building blocks? It is confusing. Please clarify.
A react component is made up of simple html elements. But a react component's smallest element is the react component itself.
A react component is actually an object with fields {type:..., state:..., props:...., children:....,} Where children will be componsed of other subtree objects(react elements). This object is used for calculating the difference in dom when a component is rerendered(on change of state or props) and pushing the objects with change and ignoring those which doesnt change.
React is all about components. When you have complex DOM ( DOM is made up of elements ) it's React's way to break that complex DOM into granular smaller components.
The more granular it is, you are doing it the more React way (It's a React best practice).
coming to "Components are the smallest build blocks ?", well we can't say it that way, we can say "React is all about components"
It depends on us that how well we create granular components, which makes it easily reusable and maintainable.
Creating granular components always doesn't mean creating components with just one element.
Granular Component ?
import React from 'react';
const welcome = (props) => (
<div>
<p>props.welcomeMessage</p>
<h3>Disclaimer</h3>
<p>props.disclaimerMessage</p>
</div>
);
export default welcome;
I can call this a granular component but we can also debate on the Disclaimer part of this code, Disclaimer also can be used elsewhere so it's always a good practice to identify such pieces and move them into there own components so that we get the complete benefits of React
We cannot call a component the smallest building block but yes we can break the HTML into proper, well-structured Component Tree to get the smallest ones.
Elements and Components are different things in React, and the documentation you read explains the first of those, the element.
Elements:
Elements are plain JavaScript objects that describe how your UI should be rendered.
If you are using JSX, describing elements looks quite similar to writing HTML.
// The `<div />` is JSX for creating a React *Element*
const element = <div>Foo</div>;
Components:
Components are separate from elements. As mentioned in the Components and Props doc, components are "like JavaScript functions" and "return React elements describing what should appear on the screen."
React Components return React Elements describing what should appear on the screen
// This is a React *Component*: a Function that returns a React *Element*.
function MyComponent() {
return <div>Foo</div>;
}
// You can also implement a React *Component* by extending `React.Component`
// and implementing a `render` method.
class YourComponent extends React.Component {
render() {
return <div>Foo</div>;
}
}