My application had a problem with calling the API 2 times in componentDidMount. I fixed it and now I wanted to make a test with Jest for this scenario.
class ResultsPage extends Component {
componentDidMount() {
// It is possible, after parent component state change to be callet again
this.props.getResults();
}
render() {
return "Some JSX";
}
}
How I can test this request. Do I need to test it in the component or to write some general test for Axios?
Unit test for ResultsPage is unable to test that. It's up to parent if some component is re-created or updated.
So if you really want to test that(I'm not sure if this provides any profit) you
Spy on componentDidMount for ResultsPage
mount() parent component
validate that spy for componentDidMount has been called only once.
const cDMspy = jest.spyOn(ResultsPage.prototype, 'componentDidMount');
mount(<SomeParent />);
expect(cDMspy).toHaveBeenCalledTimes(1);
In general case, things become harder if you expect few legal instances of ResultsPage in the same parent. Then validation for .toHaveBeenCalledTimes is not enough: it matters if we have 2 component instances with cDM called once per component or just single instance with cDM been called twice.
const cDMspy = jest.spyOn(ResultsPage.prototype, 'componentDidMount');
const wrapper = mount(<SomeParent />);
expect(wrapper.find(ResultsPage)).toHaveLength(2);
expect(cDMspy).toHaveBeenCalledTimes(2);
In case of cDM we may just check amount of component instances should be equal to calls count. But for other methods(that are not guaranteed to be called at least once per instance) we may end with creating our own tracking tool:
const callContext = [];
const original = ResultsPage.prototype.someMethod;
const spy = jest.spyOn(ResultsPage.prototype, someMethod);
spy.mockImplementation((...args) => {
callContext.push(this.props.someMeaningfullPropToIdentityComponent);
return original.call(this, ...args);
});
mount(<SomeParent />);
expect(callContext).toEqual(["id1", "id3", "id3"]);
See, it becomes much more complicated. Reasons becomes unclear, code becomes harder to maintain. Also any future refactoring like changing calls order, renaming methods supposed to be private etc breaks our test really bad.
What's alternative? You may mock things that should respond exactly N times(say mockFn.mockReturnValueOnce or any equivalent for axios mocks). Then just run your existing test cases and once something is requesting with unexpected frequency - you will know.
What's else? You may avoid focusing on that. In typical CRUD only creation should lead to dramatic results if called extra time. Everything else(deleting, updating, fetching) is more about performance then functionality. So it'd easier to test that alongside other performance-related things manually and on-demand(once there are issues with that).
Related
I want to check if dispatch by react-redux has been called.
In debug mode, I can see that the respective line of code is executed, so dispatch is actually called but in my jest test the result is always 0 calls.
What would be the proper way to do this?
const mockDispatchFn = jest.fn();
jest.doMock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: () => mockDispatchFn,
}));
...
expect(mockDispatchFn).toHaveBeenCalledWith(...);
doMock and requireActual are not really reliable especially for things that might already be caught by other modules in their constants or through function closures. Better to avoid it instead of searching how to make it working.
Option 1. Better one.
Redux docs are pretty opinionated here:
Prefer writing integration tests with everything working together. For a React app using Redux, render a <Provider> with a real store instance wrapping the components being tested. Interactions with the page being tested should use real Redux logic, with API calls mocked out so app code doesn't have to change, and assert that the UI is updated appropriately.
It means:
Real store reducer
to mock store data we will call dispatch on that story with related action creators mockedStore.dispatch(someDataLoadedAction(someMockedData))
instead of checking whether dispatch has been called we, depending on what should happen, will:
a. either validate new store state through selectors("after clicking this button in Component1 we expect Redux's selector getSomeFlag to return true") b. or validating something else happened(network call has been sent with expected parameters, document title has been changed, navigation has occured etc)
c. or validating our component has been updated according to new store's state
Something like this:
const store = createStore(reducer, applyMiddleware(thunk));
// store preparation
store.dispatch(somethingLoadedSuccess(mock1));
store.dispatch(somethingChanged(someMock2));
// rendering component
const { getByRole, getByText } = render(<Provider store={store}>
<ComopnentUnderTest prop1="a" prop2={something} />
</Provide>);
// simulating some scenario
fireEvent.click(getByRole('button', { name: 'Save' }));
// asserting
expect(someSelector1(store.getState())).toBe(42);
expect(getByText('Saved successfully')).toBeInTheDocument();
expect(mockedNetworkLayer.isDone()).toBe(true);
Option 2. Tricky and not that reliable.
Using redux-mock-store you can easily check which actions has been dispatched, however with this approach:
you cannot change Redux state during the test so will be unable to test some cases
you will need to mock store tree with static data; tests become fragile - if you ever do internal refactoring of store's structure and update correctly all the selectors, you will also need to update all the mocked static data across the tests to make them passing again; tests become unreliable - if you ever do internal refactoring of store's structure and miss to update selectors accordingly, tests will still be passing though app will be broken
// store preparation
const store = configureStore([thunk])(staticDataMockForAStore);
// rendering component
const { getByRole, getByText } = render(<Provider store={store}>
<ComopnentUnderTest prop1="a" prop2={something} />
</Provide>);
// simulating some scenario
fireEvent.click(getByRole('button', { name: 'Save' }));
// asserting
expect(store.getActions()).toContainEqual({
type: 'SOME_ACTION_TYPE',
value1: 1,
value2: 'a'
});
Also for that approach to assert on actions dispatched you may need expect.objectContaining to ignore some properties with random data(UUID etc)
As the title says, I'm using RTL + Jest (with Create-react-app setup).
My question is if I should be using a beforeAll in each test pre-rendering the component within that block, so each test doesn't have to re-render the component from scratch since my test suites always start from the same base component. Is there a performance improvement by doing this?
For example, is there an improvement in doing this
describe("MyComponent", () => {
beforeAll(() => {
render(<MyComponent {...props} />);
});
it("tests something", () => {
expect(something).toDoSomething();
});
it("tests something else", () => {
expect(somethingElse).toDoSomethingElse();
});
});
over this (other than being less verbose and re-writing the component rendering)?
describe("MyComponent", () => {
it("tests something", () => {
render(<MyComponent {...props} />);
expect(something).toDoSomething();
});
it("tests something else", () => {
render(<MyComponent {...props} />);
expect(somethingElse).toDoSomethingElse();
});
});
Should I be approaching my test suites differently by doing something else? Is it just a matter of personal preference?
I've read from Kent C Dodds blog this post where he mainly states it makes code less readable but doesn't talk about performance or if it has any kind of impact on the tests.
It is mostly a matter of personal preference, but also about how your component works. You may need to render your component in different contexts (props, mocked redux store, mocked provider...). Render component in beforeEach may be faster but makes it more difficult to change the test conditions.
In my experience, as a rule of thumb, presentational components are rendered in the test itself, because I want to test different sets of props to cover all cases. As they are dumb components (only props involved, few mocks, simple component logic), thoses tests are usually fast. This is "real unit testing" : testing a pure function I/O (I only write functional components in my current position).
For smart/bigger components, usually I test a group of components together (which is more an integration test), I have to setup mocks (redux, http services...), and tests tends to resemble to scenarios like you would see in Cypress, with user interactions. For those tests I render once in beforeEach, and write fewer but longer tests. I end up with a test execution time much longer, but with a high level of confidence (close to what E2E would give).
This is more or less what https://kentcdodds.com/blog/write-tests says (as I understand it), and so far it seems to be a solid approach.
Obvioulsy this is some general thoughts/personal insight, there is no one size fits all in this matter I think. The only goal is to gain confidence.
By the way, when choosing to rerender the component multiple times, don't forget to use the rerender function to prevent funny things to happen.
While It makes sense (to me) theoretically, at least with recent version of Jest and RTL, by default it won't work to render in beforeAll. You can get around Jest auto cleanup in afterEach, but the performance benefit is probably not much anyway.
Better approach may be to write longer / richer tests rather than falling into the old habit of treating RTL as a pure unit testing tool.
https://github.com/testing-library/react-testing-library/issues/541
I need to test a function inside my stateless component as the source code below:
function App(props) {
const handleItemClick = () => {
if (true) {
props.doanything();
}
}
return (
<div onClick={handleItemClick}>
App
</div>
);
}
As suggested - if you can simply test your functionality by simulating user clicks then do take that approach. BUT, saying that testing internal implementation is 'bad practice' is unhelpful and impractical.
There is still a strong case for testing a function directly. Especially when your component is complex with several nested components making asynchronous calls to servers before the function you want to test can be run.
In this scenario - you're left with two choices, that I'm aware of:
Move the function out of the functional component scope, export that and test it (NB, you'll possibly need to pass in quite a few props so this can look ugly)
Use a class component. This way you can reference the function directly.
I'd love there to be a better one and hopefully someone will suggest something in the comments.
You should not test inner (private) items, it is considered bad practice to test internal implementation, instead, try to mimc user interaction with your component.
In your case simulate a click on the div.
If you are using Enzyme, you can grab the div via wrapper.find and then div.simulate('click').
I have a common sentence that I use a lot, "If it is hard to test you probably trying to test something wrong".
Testing components with HOCs generally seems to be a major problem (enzyme#539, enzyme#1002, recompose#407, ...). Most discussions include the opinion "test only the HOC as a function and then later not the usage", whereby for unit tests the actual component is exported as named export and tested in isolation. Then some workarounds are suggested (like dive until the component is reached and the like).
The technical implementation is accordingly also (relatively) clear to me, but it is now difficult for me how and whether the composition should be tested with the HOCs in the end.
example:
import withState from 'recompose/withState';
export const InnerMyComponent = /* ... */;
const enhance = withState('prop', 'setProp', null);
export const MyComponent = enhance(InnerMyComponent);
It seems very important for the app that withState is called correctly and give prop and setProp to the inner component. Should I always test accordingly that the two props are passed on correctly like
expect(shallow(<MyComponent />).dive().prop('setProp')).toBeDefined()
So, should I write tests like that or what would be a better way to test the composition of an app?
To test or not to test an HOC might depend on which HOC are you using(whether its an HOC that is written by you or an HOC that is being imported from the library). If it is an HOC that is being imported from the library, its the responsibility of the library to write test cases for that HOC since it is the one that is exposing methods and props to you and hence should work correctly. On the other hand if there is an HOC that you have written, you should write test cases to verify whether it functions correctly in different scenarios.
In order to test the component which is wrapped with an HOC, the most easiest way is to test it by providing the props to the component that the HOC will provide when you are shallow mounting it like
const wrapper = shallow(<InnerMyComponent prop={null} setProps={jest.fn()} />);
and then test the behaviour of InnerMyComponent
Now when you have to test a custom HOC, you test it as a function passing some random component to it and checking whether the component receives those props and also testing the inner functions
When unit testing a HOC, there are three main things that should be tested (if some parts of the HOC are very simple, these tests may not all be necessary). The examples below use Jest.
1) Props should be passed correctly to the inner component. This includes ones that the HOC creates or modifies, and ones that are passed straight through. For example:
it("passes A prop to InnerMyComponent", async () => {
// ...
let container = shallow(<MyComponent {...props}/>).dive();
const inner = container.find(InnerMyComponent).at(0);
const { A } = inner.props();
expect(inner.props().A).toEqual(expectedA);
});
2) Lifecycle methods in the HOC work as expected. For example:
it("calls X on mount", async () => {
// ...
spy = jest.spyOn(MyComponent.WrappedComponent.prototype, "X");
const component = mount(
<MyComponent {...props}/>
);
expect(spy).toHaveBeenCalled();
spy.mockReset();
});
3) Non-lifecycle methods in the HOC work as expected.
it("method P works", () => {
// ...
let container = shallow(<MyComponent {...props}/>).dive();
let result = container.instance().P("input");
expect(result).toEqual(expectedResult);
});
Any further functionality will be either related to the inner component, and so should be tested there, or is in the realm of integration testing. As HOCs act as normal components, they should be able to be treated as such in integration tests.
Lately I've been trying to write my React components as "Pure Functions" and I've noticed that sometimes I want to have something which feels a lot like state. I was thinking about passing my state as a second parameter to my component. I can achieve this by calling my component as a normal function with two parameters, props and state.
For example:
// abstracted to it's own module
const useState = (Component, state = {}) => {
return class extends React.Component {
state = createState(this, state); // will traverse and update the state
render() {
const { props, state } = this;
return Component(props, state); // <-- call the Component directly
}
};
};
const Component = (props, { index, increase }) => (
<div onClick={increase} {...props}>
Click me to increase: {index}
</div>
);
const componentState = {
index: 0,
increase: (event, state) => ({ ...state, index: state.index + 1 })
};
const StatefullComponent = useState(Component, componentState);
<StatefullComponent style={{ color: "purple" }} />;
I have a CodeSandbox example:
My questions are:
Will this pattern harm performance?
I'm no longer extending the props with state values, this might be a good thing
I am messing with the way components are rendered by default, this might be a bad thing
Will this Pattern break things like shouldComponentUpdate? (I have a sinking feeling this is modelling the old context api)
How worried should I be that future react updates will break this code?
Is there a more "Reacty" way of using State in a Pure function without resorting to libraries like Redux?
Am I trying to solve something which should not be solved?
Note: I'm using state in this example, but it could also be a theme, authorisation rules or other things you might want passed into your component.
EDIT 19-03-2018: I have noticed that people seem to be confused about what I'm asking. I'm not looking for a new framework or a conversation about "why do you want to separate your concerns?". I am quite sure this pattern will clean up my code and make it more testable and "cleaner" in general. I really want to know if the React framework will in any way hinder this pattern.
At first glanced when I checked your code I had a question:
"Why do you make it so complicated? When you can simply make it with a class declaration".
But later when I have splitted your code I found it really worth to do that.
Question 1: Doesn't really make a difference, it is the way how HOC does the composition.
I'm no longer extending the props with state values, this might be a good thing
Why/When might it be a good thing?
I am messing with the way components are rendered by default, this might be a bad thing
I don't see that you break or mess the rendering by default, I think the HOC pattern promotes the same philosophy, the difference you separate state from props.
Question 2: If a developer decide to use a stateless component then he/she should realize all “lifecycle methods” or references ref will be not available.
Your pattern make stateless component as “statefull” but in stateless declaration - amazing 😋.
Like in JSX you write in JS an "HTML" and inside it JS code with another "HTML":
<ul>
{list.map(text => <li>text</li>)} // I know there should be used key
</ul>
Mr. Baudin pattern (state-full like stateless):
import React from 'react'
import {useState} from './lib'
const state = {
index: 0,
increase: (event, state) => ({index: state.index + 1})
}
const Component = (props, state) => (
<div onClick={state.increase} {...props}>
Click me to increase: {state.index}
</div>
)
export default useState(Component, state)
Question 3: It depends what break changes will be in coming versions.
Question 4: Well... I don't think the offered pattern (implemented library) can be considered as application state management but it can be used within any state management like Redux or Mobx because it deals with internal component state.
Question 5: No, I don't think. Your solution makes code less and clean. Functional components are good for very simple or representational components and now it can be extended with state.
While this question has been open I've done some painful research on the subject and I'd like to share this research with you.
Question 1: Performance; Calling your components as functions or even as constructor functions doesn't really make a difference. You simply get your component instead of a type.
// the component
const MyComponent = () => (<div>This is my page</div>);
console.log(MyComponent());
console.log(new MyComponent());
console.log(<MyComponent />);
console.log(React.createElement(MyComponent));
Pen (Don't forget to inspect the developer tools!)
What I've noticed is that when you call a component directly you lose a little information, for example, when I use JSX the type information is preserved:
React.createElement(MyComponent).type === MyComponent // <- true
MyComponent() // <- Now way to find out what constructed this...
This doesn't seem like a big deal because the MyComponent() is seen as a normal div so it should render correctly; but I can imagine that React might do some lookup on the type of the component and calling your function like this that might interfere with the performance.
Haven't found anything in the documentation nor in the source code to suggest that this is the case, so I see no reason to worry about performance at this point.
Question 2: Does this break shouldComponentUpdate; the answer is "maybe not", but not because I need to write a class as was suggested. The problem is that React does a shallow compare on the props when you use a PureComponent and with pure functions just expects that with the same props you get the same result. In my case, because of the second parameter it might think the component doesn't need to update but actually it should. Because of some magic in my implementation this seems to work for child components of a root component wrapped with the useState function.
This is as I expected the same problem as with the original implementation of the context api. And as such I should be able to solve it using some reactive techniques.
Question 3: Seeing how "just calling a component as a function" seems to be the entire idea behind react and seeing how it results in almost exactly the same component without the original type information I see no reason why this should break in the future.
Question 4/5: No, there is no more "Reacty" way of really solving this problem. There is how ever a more functional way. I could use a state monad and lift the entire thing up; but that would envolve a lot of work and I really can't see the benefit of doing that. Passing state as a second parameter seems, at least for now, as something which might be strange but viable and actually feasable.
Question 5: When I started looking around I didn't find a lot os answers to these questions, but now that I've really dug myself in I can see a few other libraries doing the same thing. For example: recompose which calls itself "lodash for react". They seem to use this pattern of wrapping your component in a function and returning a class a lot. (Their withState implementation).
Extra information: My conclusion is that this pattern (because it's nothing more than a pattern) is valid and does not break any fundamental rules of React. Just to give a little bit of extra information Bernardo Ferreira Bastos Braga wrote that I needed to use a class to do it "the React way". I fail to see how wrapping your function and returning a class with state is anything other than "using a class".
I do however realise that wrapping a function increases complexity, but not by much; function calls are really optimised and because you write for maintainability and optimise later.
One of my biggest fears is that when the software gets more and more complocated and we get more cross-cutting concerns to deal with, it will get harder and harder to handle every concern as a parameter. In this case it might be good to use a destructuring pattern to get the concerns which you need from a "concerns" obejct passed as the second parameter.
One last thing about this pattern. I've done a small test (Just selenium rendering a page a 100 times) and this pattern, on a small scale, is faster than using Redux. The bigger your redux state gets and the more components you connect the faster this pattern becomes. The down side is that you are now doing a bit of manual state management, this comes with a real cost in complexity. Just remember to weigh all options.
A few examples of why this state component
Applications which interact with users, require that you try to keep track of the interactions they have. These interactions can be modeled in different ways but I really like a stateful approach. This means that you 'thread' state through your application. Now in react you have a few ways of creating components. The three I want o mention are:
create a class and extend from Component
create a class and extend from PureComponent
create a stateless function
I really like the last option but, to be honest, it's a pain keeping your code performant. There are a lot of articles our there explaining how lambda expression will create a new function every time your component is called, breaking the shallow compare of the props done by PureComponent.
To counteract this I use a pattern where I wrap my stateless component in a HoC where I pass my component and my state object. This HoC does some magic and passes the state as a second parameter to the stateless function, ensuring that when the props are tested by the compare of the PureComponent it should work.
Now to make the wrapper even better I memoize the lambdas so that only a single reference to that function exists so that even if you were to test the function by reference it should still be OK.
The code I use for this is:
return Object.entries(_state).reduce(
(acc, entry) => {
const [key, value] = entry;
if (value instanceof Function) {
acc[key] = _.memoize(item => (...args) => {
const newState = value.apply(null, [...args, root.state, root.props]);
root.setState(newState);
});
} else {
acc[key] = value;
}
return acc;
},
{}
);
};
As you can see I memoize the function and call it proxying the arguments and passing in the state and the props. This works as long as you can call these functions with a unique object like so:
const MyComponent = useState((props, { items, setTitle }) => {
return (
<div>
{items.map(item => (
<Component key={item.id} item={item} changeItem={setTitle(item)} />
))}
</div>
);
}, state);
1- Will this pattern harm performance?
Performance is usually not a black/white, rather it is better / worse in different scenarios. Since React already has a standard way of doing this, it it plausible that you'll be missing out on internal optimizations.
2-Will this Pattern break things like shouldComponentUpdate? (I have a sinking feeling this is modelling the old context api)
Yes, you should be using the class declaration if you need to write shouldComponentUpdate functions
3- How worried should I be that future react updates will break this code?
I think is fair to say that you should, since there are obvious and documented ways of doing the same using classes.
4 - Is there a more "Reacty" way of using State in a Pure function without resorting to libraries like Redux?
you could have a container component that has state and pass down callback functions to update the state
5- Am I trying to solve something which should not be solved?
yes, since there is already a mainstream and documented way of archieving what you need using the Component class. You should probably resort to functional components only for very simple or presentational components