react-safety-helmet
Version:
A fork of react-helmet that support for renderToNodeStream and thread safe with the power of redux
1,352 lines (1,157 loc) • 161 kB
JavaScript
/* eslint max-nested-callbacks: [1, 7] */
/* eslint-disable react/jsx-sort-props */
/* eslint-disable jsx-a11y/html-has-lang */
import React from "react";
import ReactDOM from "react-dom";
import ReactServer from "react-dom/server";
import {Helmet, HelmetProvider, createHelmetStore} from "../src/Helmet";
import {HTML_TAG_MAP} from "../src/HelmetConstants";
import {requestAnimationFrame} from "../src/HelmetUtils.js";
const HELMET_ATTRIBUTE = "data-react-helmet";
describe("Helmet - Declarative API", () => {
let headElement;
const container = document.createElement("div");
beforeEach(() => {
headElement =
headElement || document.head || document.querySelector("head");
// resets DOM after each run
headElement.innerHTML = "";
});
afterEach(() => {
ReactDOM.unmountComponentAtNode(container);
});
describe("api", () => {
describe("title", () => {
it("updates page title", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet defaultTitle={"Fallback"}>
<title>Test Title</title>
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal("Test Title");
done();
});
});
it("updates page title and allows children containing expressions", done => {
const store = createHelmetStore();
const someValue = "Some Great Title";
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<title>Title: {someValue}</title>
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal("Title: Some Great Title");
done();
});
});
it("updates page title with multiple children", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<div>
<Helmet>
<title>Test Title</title>
</Helmet>
<Helmet>
<title>Child One Title</title>
</Helmet>
<Helmet>
<title>Child Two Title</title>
</Helmet>
</div>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal("Child Two Title");
done();
});
});
it("sets title based on deepest nested component", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<div>
<Helmet>
<title>Main Title</title>
</Helmet>
<Helmet>
<title>Nested Title</title>
</Helmet>
</div>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal("Nested Title");
done();
});
});
it("sets title using deepest nested component with a defined title", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<div>
<Helmet>
<title>Main Title</title>
</Helmet>
<Helmet />
</div>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal("Main Title");
done();
});
});
it("uses defaultTitle if no title is defined", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet
defaultTitle={"Fallback"}
titleTemplate={
"This is a %s of the titleTemplate feature"
}
>
<title />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal("Fallback");
done();
});
});
it("uses a titleTemplate if defined", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet
defaultTitle={"Fallback"}
titleTemplate={
"This is a %s of the titleTemplate feature"
}
>
<title>Test</title>
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal(
"This is a Test of the titleTemplate feature"
);
done();
});
});
it("replaces multiple title strings in titleTemplate", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet
titleTemplate={
"This is a %s of the titleTemplate feature. Another %s."
}
>
<title>Test</title>
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal(
"This is a Test of the titleTemplate feature. Another Test."
);
done();
});
});
it("uses a titleTemplate based on deepest nested component", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<div>
<Helmet
titleTemplate={
"This is a %s of the titleTemplate feature"
}
>
<title>Test</title>
</Helmet>
<Helmet
titleTemplate={
"A %s using nested titleTemplate attributes"
}
>
<title>Second Test</title>
</Helmet>
</div>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal(
"A Second Test using nested titleTemplate attributes"
);
done();
});
});
it("merges deepest component title with nearest upstream titleTemplate", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<div>
<Helmet
titleTemplate={
"This is a %s of the titleTemplate feature"
}
>
<title>Test</title>
</Helmet>
<Helmet>
<title>Second Test</title>
</Helmet>
</div>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal(
"This is a Second Test of the titleTemplate feature"
);
done();
});
});
it("renders dollar characters in a title correctly when titleTemplate present", done => {
const store = createHelmetStore();
const dollarTitle = "te$t te$$t te$$$t te$$$$t";
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet titleTemplate={"This is a %s"}>
<title>{dollarTitle}</title>
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal(
"This is a te$t te$$t te$$$t te$$$$t"
);
done();
});
});
it("does not encode all characters with HTML character entity equivalents", done => {
const store = createHelmetStore();
const chineseTitle = "膣膗 鍆錌雔";
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<title>{chineseTitle}</title>
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal(chineseTitle);
done();
});
});
it("page title with prop itemProp", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet defaultTitle={"Fallback"}>
<title itemProp="name">
Test Title with itemProp
</title>
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const titleTag = document.getElementsByTagName("title")[0];
expect(document.title).to.equal("Test Title with itemProp");
expect(titleTag.getAttribute("itemprop")).to.equal("name");
done();
});
});
it("retains existing title tag when no title tag is defined", done => {
const store = createHelmetStore();
headElement.innerHTML = `<title>Existing Title</title>`;
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<meta name="keywords" content="stuff" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal("Existing Title");
done();
});
});
it.skip("clears title tag if empty title is defined", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<title>Existing Title</title>
<meta name="keywords" content="stuff" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal("Existing Title");
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<title />
<meta name="keywords" content="stuff" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(document.title).to.equal("");
done();
});
});
});
});
describe("title attributes", () => {
beforeEach(() => {
headElement.innerHTML = `<title>Test Title</title>`;
});
it("updates title attributes", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<title itemProp="name" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const titleTag = document.getElementsByTagName("title")[0];
expect(titleTag.getAttribute("itemprop")).to.equal("name");
expect(titleTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"itemprop"
);
done();
});
});
it("sets attributes based on the deepest nested component", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<div>
<Helmet>
<title lang="en" hidden />
</Helmet>
<Helmet>
<title lang="ja" />
</Helmet>
</div>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const titleTag = document.getElementsByTagName("title")[0];
expect(titleTag.getAttribute("lang")).to.equal("ja");
expect(titleTag.getAttribute("hidden")).to.equal("true");
expect(titleTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"lang,hidden"
);
done();
});
});
it("handles valueless attributes", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<title hidden />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const titleTag = document.getElementsByTagName("title")[0];
expect(titleTag.getAttribute("hidden")).to.equal("true");
expect(titleTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"hidden"
);
done();
});
});
it("clears title attributes that are handled within helmet", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<title lang="en" hidden />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet />
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const titleTag = document.getElementsByTagName(
"title"
)[0];
expect(titleTag.getAttribute("lang")).to.be.null;
expect(titleTag.getAttribute("hidden")).to.be.null;
expect(
titleTag.getAttribute(HELMET_ATTRIBUTE)
).to.equal(null);
done();
});
});
});
});
describe("html attributes", () => {
it("updates html attributes", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<html className="myClassName" lang="en" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const htmlTag = document.getElementsByTagName("html")[0];
expect(htmlTag.getAttribute("class")).to.equal(
"myClassName"
);
expect(htmlTag.getAttribute("lang")).to.equal("en");
expect(htmlTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"class,lang"
);
done();
});
});
it("sets attributes based on the deepest nested component", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<div>
<Helmet>
<html lang="en" />
</Helmet>
<Helmet>
<html lang="ja" />
</Helmet>
</div>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const htmlTag = document.getElementsByTagName("html")[0];
expect(htmlTag.getAttribute("lang")).to.equal("ja");
expect(htmlTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"lang"
);
done();
});
});
it("handles valueless attributes", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<html amp />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const htmlTag = document.getElementsByTagName("html")[0];
expect(htmlTag.getAttribute("amp")).to.equal("true");
expect(htmlTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"amp"
);
done();
});
});
it("clears html attributes that are handled within helmet", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<html lang="en" amp />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet />
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const htmlTag = document.getElementsByTagName(
"html"
)[0];
expect(htmlTag.getAttribute("lang")).to.be.null;
expect(htmlTag.getAttribute("amp")).to.be.null;
expect(htmlTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
null
);
done();
});
});
});
it("updates with multiple additions and removals - overwrite and new", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<html lang="en" amp />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<html
lang="ja"
id="html-tag"
title="html tag"
/>
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const htmlTag = document.getElementsByTagName(
"html"
)[0];
expect(htmlTag.getAttribute("amp")).to.equal(null);
expect(htmlTag.getAttribute("lang")).to.equal("ja");
expect(htmlTag.getAttribute("id")).to.equal("html-tag");
expect(htmlTag.getAttribute("title")).to.equal(
"html tag"
);
expect(htmlTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"lang,id,title"
);
done();
});
});
});
it("updates with multiple additions and removals - all new", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<html lang="en" amp />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<html id="html-tag" title="html tag" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const htmlTag = document.getElementsByTagName(
"html"
)[0];
expect(htmlTag.getAttribute("amp")).to.equal(null);
expect(htmlTag.getAttribute("lang")).to.equal(null);
expect(htmlTag.getAttribute("id")).to.equal("html-tag");
expect(htmlTag.getAttribute("title")).to.equal(
"html tag"
);
expect(htmlTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"id,title"
);
done();
});
});
});
context("initialized outside of helmet", () => {
before(() => {
const htmlTag = document.getElementsByTagName("html")[0];
htmlTag.setAttribute("test", "test");
});
it("are not cleared", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet />
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const htmlTag = document.getElementsByTagName(
"html"
)[0];
expect(htmlTag.getAttribute("test")).to.equal("test");
expect(htmlTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
null
);
done();
});
});
it("overwritten if specified in helmet", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<html test="helmet-attr" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const htmlTag = document.getElementsByTagName(
"html"
)[0];
expect(htmlTag.getAttribute("test")).to.equal(
"helmet-attr"
);
expect(htmlTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"test"
);
done();
});
});
it("cleared once it is managed in helmet", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<html test="helmet-attr" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet />
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const htmlTag = document.getElementsByTagName(
"html"
)[0];
expect(htmlTag.getAttribute("test")).to.equal(null);
expect(
htmlTag.getAttribute(HELMET_ATTRIBUTE)
).to.equal(null);
done();
});
});
});
});
});
describe("body attributes", () => {
context("valid attributes", () => {
const attributeList = {
accessKey: "c",
className: "test",
contentEditable: "true",
contextMenu: "mymenu",
"data-animal-type": "lion",
dir: "rtl",
draggable: "true",
dropzone: "copy",
hidden: "true",
id: "test",
lang: "fr",
spellcheck: "true",
style: "color:green",
tabIndex: "-1",
title: "test",
translate: "no"
};
Object.keys(attributeList).forEach(attribute => {
it(attribute, done => {
const store = createHelmetStore();
const attrValue = attributeList[attribute];
const attr = {
[attribute]: attrValue
};
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<body {...attr} />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const bodyTag = document.body;
const reactCompatAttr =
HTML_TAG_MAP[attribute] || attribute;
expect(
bodyTag.getAttribute(reactCompatAttr)
).to.equal(attrValue);
expect(
bodyTag.getAttribute(HELMET_ATTRIBUTE)
).to.equal(reactCompatAttr);
done();
});
});
});
});
it("updates multiple body attributes", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<body className="myClassName" tabIndex={-1} />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const bodyTag = document.body;
expect(bodyTag.getAttribute("class")).to.equal(
"myClassName"
);
expect(bodyTag.getAttribute("tabindex")).to.equal("-1");
expect(bodyTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"class,tabindex"
);
done();
});
});
it("sets attributes based on the deepest nested component", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<div>
<Helmet>
<body lang="en" />
</Helmet>
<Helmet>
<body lang="ja" />
</Helmet>
</div>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const bodyTag = document.body;
expect(bodyTag.getAttribute("lang")).to.equal("ja");
expect(bodyTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"lang"
);
done();
});
});
it("handles valueless attributes", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<body hidden />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const bodyTag = document.body;
expect(bodyTag.getAttribute("hidden")).to.equal("true");
expect(bodyTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"hidden"
);
done();
});
});
it("clears body attributes that are handled within helmet", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<body lang="en" hidden />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet />
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const bodyTag = document.body;
expect(bodyTag.getAttribute("lang")).to.be.null;
expect(bodyTag.getAttribute("hidden")).to.be.null;
expect(bodyTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
null
);
done();
});
});
});
it("updates with multiple additions and removals - overwrite and new", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<body lang="en" hidden />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<body
lang="ja"
id="body-tag"
title="body tag"
/>
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const bodyTag = document.body;
expect(bodyTag.getAttribute("hidden")).to.equal(null);
expect(bodyTag.getAttribute("lang")).to.equal("ja");
expect(bodyTag.getAttribute("id")).to.equal("body-tag");
expect(bodyTag.getAttribute("title")).to.equal(
"body tag"
);
expect(bodyTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"lang,id,title"
);
done();
});
});
});
it("updates with multiple additions and removals - all new", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<body lang="en" hidden />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<body id="body-tag" title="body tag" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const bodyTag = document.body;
expect(bodyTag.getAttribute("hidden")).to.equal(null);
expect(bodyTag.getAttribute("lang")).to.equal(null);
expect(bodyTag.getAttribute("id")).to.equal("body-tag");
expect(bodyTag.getAttribute("title")).to.equal(
"body tag"
);
expect(bodyTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"id,title"
);
done();
});
});
});
context("initialized outside of helmet", () => {
before(() => {
const bodyTag = document.body;
bodyTag.setAttribute("test", "test");
});
it("attributes are not cleared", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet />
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const bodyTag = document.body;
expect(bodyTag.getAttribute("test")).to.equal("test");
expect(bodyTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
null
);
done();
});
});
it("attributes are overwritten if specified in helmet", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<body test="helmet-attr" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const bodyTag = document.body;
expect(bodyTag.getAttribute("test")).to.equal(
"helmet-attr"
);
expect(bodyTag.getAttribute(HELMET_ATTRIBUTE)).to.equal(
"test"
);
done();
});
});
it("attributes are cleared once managed in helmet", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<body test="helmet-attr" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet />
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const bodyTag = document.body;
expect(bodyTag.getAttribute("test")).to.equal(null);
expect(
bodyTag.getAttribute(HELMET_ATTRIBUTE)
).to.equal(null);
done();
});
});
});
});
});
describe("onChangeClientState", () => {
it("when handling client state change, calls the function with new state, addedTags and removedTags ", done => {
const store = createHelmetStore();
const spy = sinon.spy();
ReactDOM.render(
<HelmetProvider store={store}>
<div>
<Helmet onChangeClientState={spy}>
<base href="http://mysite.com/" />
<link
href="http://localhost/helmet"
rel="canonical"
/>
<meta charSet="utf-8" />
<script
src="http://localhost/test.js"
type="text/javascript"
/>
<title>Main Title</title>
</Helmet>
</div>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(spy.called).to.equal(true);
const newState = spy.getCall(0).args[0];
const addedTags = spy.getCall(0).args[1];
const removedTags = spy.getCall(0).args[2];
expect(newState).to.deep.contain({title: "Main Title"});
expect(newState.baseTag).to.deep.contain({
href: "http://mysite.com/"
});
expect(newState.metaTags).to.deep.contain({
charset: "utf-8"
});
expect(newState.linkTags).to.deep.contain({
href: "http://localhost/helmet",
rel: "canonical"
});
expect(newState.scriptTags).to.deep.contain({
src: "http://localhost/test.js",
type: "text/javascript"
});
expect(addedTags).to.have.property("baseTag");
expect(addedTags.baseTag).to.have.deep.nested.property(
"[0]"
);
expect(addedTags.baseTag[0].outerHTML).to.equal(
`<base href="http://mysite.com/" data-react-helmet="true">`
);
expect(addedTags).to.have.property("metaTags");
expect(addedTags.metaTags).to.have.deep.nested.property(
"[0]"
);
expect(addedTags.metaTags[0].outerHTML).to.equal(
`<meta charset="utf-8" data-react-helmet="true">`
);
expect(addedTags).to.have.property("linkTags");
expect(addedTags.linkTags).to.have.deep.nested.property(
"[0]"
);
expect(addedTags.linkTags[0].outerHTML).to.equal(
`<link href="http://localhost/helmet" rel="canonical" data-react-helmet="true">`
);
expect(addedTags).to.have.property("scriptTags");
expect(addedTags.scriptTags).to.have.deep.nested.property(
"[0]"
);
expect(addedTags.scriptTags[0].outerHTML).to.equal(
`<script src="http://localhost/test.js" type="text/javascript" data-react-helmet="true"></script>`
);
expect(removedTags).to.be.empty;
done();
});
});
it("calls the deepest defined callback with the deepest state", done => {
const store = createHelmetStore();
const spy = sinon.spy();
ReactDOM.render(
<HelmetProvider store={store}>
<div>
<Helmet onChangeClientState={spy}>
<title>Main Title</title>
</Helmet>
<Helmet>
<title>Deeper Title</title>
</Helmet>
</div>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
expect(spy.callCount).to.equal(1);
expect(spy.getCall(0).args[0]).to.deep.contain({
title: "Deeper Title"
});
done();
});
});
});
describe("base tag", () => {
it("updates base tag", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<base href="http://mysite.com/" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const existingTags = headElement.querySelectorAll(
`base[${HELMET_ATTRIBUTE}]`
);
expect(existingTags).to.not.equal(undefined);
const filteredTags = [].slice
.call(existingTags)
.filter(tag => {
return (
tag.getAttribute("href") ===
"http://mysite.com/"
);
});
expect(filteredTags.length).to.equal(1);
done();
});
});
it("clears the base tag if one is not specified", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet base={{href: "http://mysite.com/"}} />
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet />
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const existingTags = headElement.querySelectorAll(
`base[${HELMET_ATTRIBUTE}]`
);
expect(existingTags).to.not.equal(undefined);
expect(existingTags.length).to.equal(0);
done();
});
});
});
it("tags without 'href' are not accepted", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<Helmet>
<base property="won't work" />
</Helmet>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {
const existingTags = headElement.querySelectorAll(
`base[${HELMET_ATTRIBUTE}]`
);
expect(existingTags).to.not.equal(undefined);
expect(existingTags.length).to.equal(0);
done();
});
});
it("sets base tag based on deepest nested component", done => {
const store = createHelmetStore();
ReactDOM.render(
<HelmetProvider store={store}>
<div>
<Helmet>
<base href="http://mysite.com" />
</Helmet>
<Helmet>
<base href="http://mysite.com/public" />
</Helmet>
</div>
</HelmetProvider>,
container
);
requestAnimationFrame(() => {