I built a simple MyRouter component based on react-router. Now I'd like to test my routing logic, like this:
it('should show AboutPage for /about`, () => {
let vdom = renderMyRouterForPath('/about');
expect(vdom).toEqual(<AboutPage />);
}
I'm using plain Jasmine in Node, no Jest mocking magic. It would be also nice to avoid rendering the whole thing in DOM (virtual DOM should be enough, I don't mean to test DOM interactions).
I've had some success with setting history={ history.createMemoryHistory(path) } in Router, but this wasn't enough. I tried shallow rendering, but with no luck (it returns the Router build by MyRouter).
How can I implement the renderMyRouterForPath function?
Related
I'm new in TDD for the React. I've decided to use the react-testing-library to start TDD for development. Suppose that, I should check a prop and simple text in component:
import { render, screen } from '#testing-library/react';
import Card from '../Card';
test('render without crash', () => {
render(<Card />);
expect(screen.getByText('Card Component')).toBeInTheDocument();
});
test('title', () => {
render(<Card title="test" />);
expect(screen.getByText('test')).toBeInTheDocument();
});
I used render two times two check different types of rendering for my component. But I was worry about performance... Is it best practice to separately use render in any tests? or I should create something like this common variable:
const Component = render(<Card title={...} prop2={} prop3={} ... />);
then use Component instead using render again?
I don't think this would be a bad practice. I usually use one of these approaches :
render my component once in a beforeEach, and use it in multiple test(), if I always need the same setup for each test (props, contexts, redux store...),
render my component in each test(), so I can adjust props and context and test multiple configurations.
See https://stackoverflow.com/a/61838982/2295549 for a more complete explanation, and some pros/cons.
But using render multiple times is not a bad practice, in fact it is a pattern used in official docs.
//in my component i have
{this.props.auth.isLoadding &&
<p className='text-info positionMessage'>Is registring...</p>
}
//in my test i have
it('should start a new component with set props', () => {
const props = {
auth: {
isAuth: false,
isLoadding: false
}
}
const wrapper = shallow(<ScreensCreateAccount {...props}/>)
wrapper.setProps({isLoadding: true})
//here is code for testing if <p>...</p> appeared. how can i do this?
})
my component starts with this.props.auth.isLoadding = false, and when a change it for true, the html too change, adding <p className='text-info positionMessage'>Is registring...</p>. How can i test it using shallow from enzyme?
Here is a working example that sticks to your code : https://codesandbox.io/s/r7owz8mykm
In your code you just forgot the auth level in your json for the prop isLoading.
{isLoadding: true}, instead of {auth: {isLoadding: true} }
But be aware that shallow rendering and enzyme may not be the right tool for testing your React component. I used it a bit but now I use react-testing-library : https://github.com/kentcdodds/react-testing-library and I am definitively happy with that. My tests are now more high level and interact with my components like a real user will do. I can refactor my component without breaking my tests, with enzyme it is, well, not so easy to write this kind of tests.
I really encourage you to at least read this and make your own opinion.
https://blog.kentcdodds.com/why-i-never-use-shallow-rendering-c08851a68bb7
If you already have some tests with enzyme no problem, you can use both libraries in the same project.
What is alternative way of using package 'react-meteor-data' ? I'm using ES6 for writing react component. What would be best approach for writing meteor subscription in react component so that it will re-render the component if anything change on the server side.
What would be best approach for writing meteor subscription in react
component so that it will re-render the component if anything change
on the server side.
The best approach is using react-meteor-data. What is wrong with this package, that makes you think to not use it?
It even allows you to separate / decouple React Components from Meteor. This is really great because when you reach the point of having written some components that you want to reuse in another non-Meteor project you are free to go without greater hassle.
Of course you could write your own subscription container for react, but with this package you have all important stuff you need plus it is maintained and tested.
If you have trouble setting up a container for subscriptions, you may dig deeper into these tutorials:
https://guide.meteor.com/react.html
https://themeteorchef.com/tutorials/using-create-container
Using react-meteor-data, you first create a HOC container that subscribes to the data and passes it down as props to your component.
Container:
import { createContainer } from 'meteor/react-meteor-data';
export default FooContainer = createContainer(() => {
// Do all your reactive data access in this method.
// Note that this subscription will get cleaned up when your component is unmounted
var handle = Meteor.subscribe("todoList", this.props.id);
return {
currentUser: Meteor.user(),
listLoading: ! handle.ready(),
tasks: Tasks.find({listId: this.props.id}).fetch(),
};
}, Foo);
Component:
import FooContainer from './FooContainer';
class App extends React.Component {
render() {
return (
<div>
{this.props.currentUser.name}
</div>
)
}
}
export default FooContainer(App);
Check out React docs for Higher Order Components to understand how the container works.
Im relatively new to React (i'm using preact.js, to be precise) and i am trying to code split out react components using webpack 2.
Im exporting my component as stated in the documentation and i am then importing it on load.
import('./components/List').then((List) => {
render(<List />, document.getElementById('main'));
});
The script loads but i'm not handling the promise callback correctly and finding it hard to see any documentation that shows a working version.
List returns the following object:
I saw your repo. It looks like that your list component doesn't have a export default.
I would add the default and inside your then, when you handle the promise, I'd do it in this way
.then(module => {
const Component = module.default;
render(<Component />, document.getElementById('main'))
})
I'm learning TDD with React from this site, but don't understand how the author got describe and it, aren't these usually from Jasmine? I don't see this package in the author's node_modules at his github nor does his tests.js import anything that looks like describe or it. Where are these two methods coming from?
import React from 'react';
import { expect } from 'chai';
import { shallow, mount, render } from 'enzyme';
describe('Test suite for User component', () => {
it('UserComponent should exist', () => {
let wrapper = shallow(<User />)
expect(wrapper).to.exist;
});
});
If that is the only it() statement that you are going to be using in your test suite, you do not really need the describe() block.
The describe() construct does indeed exist in Jest, it exists in Mocha as well.
The describe() function is used to group together certain sets of tests that have some common setup and tear down for each of them. This is why I said, based on the code you pasted, if you have nothing further to test, you do not need that describe() function.
So when you run create-react-app one of the libraries that got loaded automatically was the Jest test suite.
I would also rewrite that test, instead of UserComponent should exist, I would do
it('shows a user component', () => {
let wrapper = shallow(<User />);
expect(wrapper.find(User).length).toEqual(1);
});
So this is where I recommend to not just follow tutorials, but look up the documentation of the tools they are having you utilize in these tutorials. In the case of Enzyme, there is a really nice method called find() to find the component and it offers an array so you can add on .length and since its just one component of User you can add at the end .toEqual(1);