Is there a way to unit test an application that uses Helmet? The problem is that Helmet sets things outside the current component...
Thanks very much for your help!
@templth Thanks for your interest in Helmet. Yes, true, Helmet only deals with side effects to the document head. There a couple ways to approach testing. You can certainly set assertions that check for conditions in your document head. You can also utilize onChangeClientState callback to monitor state changes as Helmet processes them.
I hope that helps.
@cwelch5 Thanks very much Chris for your answer!
Here is a fake component using Helmet I want to test:
class FakeComponent {
render() {
return (
<div>
<Helmet
onChangeClientState={ this.logChangeClientState }
title={"Test Title"}
defaultTitle={"Fallback"}
/>
</div>
)
}
logChangeClientState() {
console.log('logChangeClientState');
}
}
and here is the test I implemented (with Mocha and Enzyme):
it('fake test', function() {
let wrapper = shallow(
<div><FakeComponent/></div>
);
expect(document.title).to.equal('Test Title');
});
document.title is empty and logChangeClientState isn't called. I think that I missed something.
Thanks very much for your help!
It seems like Helmet is not getting rendered. What does shallow do? Is it like this - https://facebook.github.io/react/docs/test-utils.html#shallow-rendering? If that's the case, from how I'm reading this, it only renders the first level, and may not be rendering Helmet. Try doing a ReactDOM.render of the Helmet component and see if that helps.
You'll need to use mount, which will recreate a DOM for you so you can query it in your test. You might also need to query the title in the mounted component itself (wrapper.find("title")).
Thanks very much, guys! It works fine ;-)
Does this still work?
Somehow the following fails for me, and it looks basically the same:
// src/nav.spec.js
import React from "react";
import Helmet from "react-helmet";
import { mount } from "enzyme";
import "should";
import "should-enzyme";
it("foo", () => {
const page = mount(
<div>
<Helmet>
<title>foobar</title>
</Helmet>
</div>);
document.title.should.eql("foobar");
});
fails with:
FAIL src/nav.spec.js
โ foo
AssertionError: expected '' to equal 'foobar'
13 | </Helmet>
14 | </div>);
> 15 | document.title.should.eql("foobar");
| ^
16 | });
17 |
18 |
at Assertion.fail (node_modules/should/cjs/should.js:275:17)
at Assertion.value (node_modules/should/cjs/should.js:356:19)
at Object.eql (src/nav.spec.js:15:25)
Found an answer to this in the following SO question: https://stackoverflow.com/questions/44073960/unit-testing-react-helmet-code
const wrapper = mount(<Metadata/>);
// this will return all the markup assigned to helmet
// which will get rendered inside head.
const helmet = Helmet.peek();
expect(helmet.title).to.equal("title");
Most helpful comment
You'll need to use
mount, which will recreate a DOM for you so you can query it in your test. You might also need to query the title in the mounted component itself (wrapper.find("title")).