ReactJS - Use a Custom Dummy Instead of nock When Possible
I just realized today that due to the type of tests I had in my spec, and the fact that our action creators
are passed to our container
via mapDispatchToProps
, that I didn't even need to nock
calls to isolate my tests. This is not always the case, sometimes it makes sense to nock
but in this case I didn't need to.
Below is an integration test on existing legacy code. I call it an isolated integration test because these tests don't make calls to real things (real API calls over the network, hit a real DB, etc.). It's also an integration test because it tests several components as a unit. I'm using enzyme mount()
for integration tests.
Example - Mock Collaborator (action creator) with a Dummy
Here, notice that fetchSearch()
is passed to the connected container via mapDispatchToProps
. Well, this means I can inject my own dummy as a prop from my test:
some.spec.js
import { createStore, expect, mount, nock, Provider, React } from 'test/test.helpers';
import { Search } from 'app/components/containers/Search';
describe('Search', () => {
describe('Successful', () => {
let search;
beforeEach(() => {
const reducers = require('config/reducers').default;
// note: stub could/should be refactored to reduce repetition
const panels = {
member: [{
headline: 'New',
customViews: [
{
name: 'Hockey',
url: 'https://fakehost/items',
},
{
name: 'Football',
url: 'https://fakehost/items',
}],
},
{
headline: 'Old',
customViews: [
{
name: 'Hockey',
url: 'https://fakehost/items',
},
{
name: 'Football',
url: 'https://fakehost/items',
}],
}],
};
search = mount(
<Provider store={createStore(reducers, {})}>
<Search
fetchSearch={() => {}} //send in a dummy
panels={panels}
...whatever else
/>
</Provider>);
});
...
it('contains category tabs with items', () => {
const items = search.find('.ft-search-tab');
expect(items.length).to.equal(2);
});
});
// I don't need to nock (this time)!! - Remove this helper!
const mockGet = (url, uri, responseCode, responseBody) => {
nock(url)
.matchHeader('accept', 'application/json, text/plain, */*')
.get(uri)
.reply(responseCode, responseBody);
};
});
So what I'm referring to is this: fetchSearch={() => {}}
. My container therefore ends up calling this, not the action creator.
react-redux Connected Container
export default class Search extends Component {
...
componentDidMount() {
...
this.props.fetchSearch(); // calls my dummy (ah! I forgot about this!)
...
}
render() {
...
);
}
}
export default connect(null, {
fetchSearch,
...
})(Search)
Keep in mind I could also send in the stub data by just returning it from the dummy as well:
fetchSearch={() => { panels }}
depending how your react component works with it, this may or may not make sense or work. If it does, then great, one less line of code in your test.
Sometimes you get tunnel vision and get so used to using something like nock
that so it's just good every once-in-a-while to verify what your tests are truly doing by stepping through or changing prod code to verify that the tests are indeed good ones.. or doing things in the way you think they are.
Final Note: Remember, you don't need a mocking framework for pretty much almost everything. I don't really use one except for rare occasions where sinon
and nock
might be useful. Otherewise I don't like to invite a lot of magic into my code and usualy I can get away with my own cusotm mocks which end up being super simple and easy in a lot of cases.
I'm using mocha
here with enzyme
, because it works jsut fine, Jest is a scam).