/* eslint max-nested-callbacks: [1, 7] */ /* eslint-disable import/no-named-as-default */ import React from "react"; import ReactDOM from "react-dom"; import ReactServer from "react-dom/server"; import {Helmet} from "../src/Helmet"; import {requestAnimationFrame} from "../src/HelmetUtils.js"; const HELMET_ATTRIBUTE = "data-react-helmet"; describe("Helmet", () => { 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 => { ReactDOM.render( , container ); requestAnimationFrame(() => { expect(document.title).to.equal("Test Title"); done(); }); }); it("updates page title with multiple children", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { expect(document.title).to.equal("Child Two Title"); done(); }); }); it("sets title based on deepest nested component", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { expect(document.title).to.equal("Nested Title"); done(); }); }); it("sets title using deepest nested component with a defined title", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { expect(document.title).to.equal("Main Title"); done(); }); }); it("uses defaultTitle if no title is defined", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { expect(document.title).to.equal("Fallback"); done(); }); }); it("uses a titleTemplate if defined", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { expect(document.title).to.equal( "This is a Test of the titleTemplate feature" ); done(); }); }); it("replaces multiple title strings in titleTemplate", done => { ReactDOM.render( , 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 => { ReactDOM.render(
, 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 => { ReactDOM.render(
, 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 dollarTitle = "te$t te$$t te$$$t te$$$$t"; ReactDOM.render( , 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 chineseTitle = "膣膗 鍆錌雔"; ReactDOM.render(
, container ); requestAnimationFrame(() => { expect(document.title).to.equal(chineseTitle); done(); }); }); it("page title with prop itemprop", done => { ReactDOM.render( , 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(); }); }); }); describe("title attributes", () => { beforeEach(() => { headElement.innerHTML = `Test Title`; }); it("update title attributes", done => { ReactDOM.render( , 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 => { ReactDOM.render(
, container ); requestAnimationFrame(() => { const titleTag = document.getElementsByTagName("title")[0]; expect(titleTag.getAttribute("lang")).to.equal("ja"); expect(titleTag.getAttribute("hidden")).to.equal(""); expect(titleTag.getAttribute(HELMET_ATTRIBUTE)).to.equal( "lang,hidden" ); done(); }); }); it("handles valueless attributes", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const titleTag = document.getElementsByTagName("title")[0]; expect(titleTag.getAttribute("hidden")).to.equal(""); expect(titleTag.getAttribute(HELMET_ATTRIBUTE)).to.equal( "hidden" ); done(); }); }); it("clears title attributes that are handled within helmet", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { ReactDOM.render(, 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 => { ReactDOM.render( , 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 => { ReactDOM.render(
, 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 => { ReactDOM.render( , container ); requestAnimationFrame(() => { const htmlTag = document.getElementsByTagName("html")[0]; expect(htmlTag.getAttribute("amp")).to.equal(""); expect(htmlTag.getAttribute(HELMET_ATTRIBUTE)).to.equal( "amp" ); done(); }); }); it("clears html attributes that are handled within helmet", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { ReactDOM.render(, 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 => { ReactDOM.render( , container ); requestAnimationFrame(() => { ReactDOM.render( , 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 => { ReactDOM.render( , container ); requestAnimationFrame(() => { ReactDOM.render( , 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("attributes are not cleared", done => { ReactDOM.render(, 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("attributes are overwritten if specified in helmet", done => { ReactDOM.render( , 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("attributes are cleared once managed in helmet", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { ReactDOM.render(, 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("onChangeClientState", () => { it("when handling client state change, calls the function with new state, addedTags and removedTags ", done => { const spy = sinon.spy(); ReactDOM.render(
, 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.contain({title: "Main Title"}); expect(newState.baseTag).to.contain({ href: "http://mysite.com/" }); expect(newState.metaTags).to.contain({charset: "utf-8"}); expect(newState.linkTags).to.contain({ href: "http://localhost/helmet", rel: "canonical" }); expect(newState.scriptTags).to.contain({ src: "http://localhost/test.js", type: "text/javascript" }); expect(addedTags).to.have.property("baseTag"); expect(addedTags.baseTag).to.have.deep.property("[0]"); expect(addedTags.baseTag[0].outerHTML).to.equal( `` ); expect(addedTags).to.have.property("metaTags"); expect(addedTags.metaTags).to.have.deep.property("[0]"); expect(addedTags.metaTags[0].outerHTML).to.equal( `` ); expect(addedTags).to.have.property("linkTags"); expect(addedTags.linkTags).to.have.deep.property("[0]"); expect(addedTags.linkTags[0].outerHTML).to.equal( `` ); expect(addedTags).to.have.property("scriptTags"); expect(addedTags.scriptTags).to.have.deep.property("[0]"); expect(addedTags.scriptTags[0].outerHTML).to.equal( `` ); expect(removedTags).to.be.empty; done(); }); }); it("calls the deepest defined callback with the deepest state", done => { const spy = sinon.spy(); ReactDOM.render(
, container ); requestAnimationFrame(() => { expect(spy.callCount).to.equal(1); expect(spy.getCall(0).args[0]).to.contain({ title: "Deeper Title" }); done(); }); }); }); describe("base tag", () => { it("updates base tag", done => { ReactDOM.render( , 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 => { ReactDOM.render( , container ); requestAnimationFrame(() => { ReactDOM.render(, 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 => { ReactDOM.render( , 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 => { ReactDOM.render(
, container ); requestAnimationFrame(() => { const existingTags = headElement.querySelectorAll( `base[${HELMET_ATTRIBUTE}]` ); const firstTag = Array.prototype.slice.call( existingTags )[0]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.be.equal(1); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("href")).to.equal( "http://mysite.com/public" ); expect(firstTag.outerHTML).to.equal( `` ); done(); }); }); it("does not render tag when primary attribute is null", done => { ReactDOM.render(, container); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `base[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); expect(existingTags).to.be.empty; done(); }); }); }); describe("meta tags", () => { it("updates meta tags", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `meta[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); expect(existingTags).to.not.equal(undefined); const filteredTags = [].slice .call(existingTags) .filter(tag => { return ( tag.getAttribute("charset") === "utf-8" || (tag.getAttribute("name") === "description" && tag.getAttribute("content") === "Test description") || (tag.getAttribute("http-equiv") === "content-type" && tag.getAttribute("content") === "text/html") || (tag.getAttribute("itemprop") === "name" && tag.getAttribute("content") === "Test name itemprop") ); }); expect(filteredTags.length).to.be.at.least(4); done(); }); }); it("clears all meta tags if none are specified", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { ReactDOM.render(, container); requestAnimationFrame(() => { const existingTags = headElement.querySelectorAll( `meta[${HELMET_ATTRIBUTE}]` ); expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(0); done(); }); }); }); it("tags without 'name', 'http-equiv', 'property', 'charset', or 'itemprop' are not accepted", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const existingTags = headElement.querySelectorAll( `meta[${HELMET_ATTRIBUTE}]` ); expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(0); done(); }); }); it("sets meta tags based on deepest nested component", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `meta[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; const secondTag = existingTags[1]; const thirdTag = existingTags[2]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.be.equal(3); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("charset")).to.equal("utf-8"); expect(firstTag.outerHTML).to.equal( `` ); expect(existingTags).to.have.deep .property("[1]") .that.is.an.instanceof(Element); expect(secondTag).to.have.property("getAttribute"); expect(secondTag.getAttribute("name")).to.equal( "description" ); expect(secondTag.getAttribute("content")).to.equal( "Inner description" ); expect(secondTag.outerHTML).to.equal( `` ); expect(existingTags).to.have.deep .property("[2]") .that.is.an.instanceof(Element); expect(thirdTag).to.have.property("getAttribute"); expect(thirdTag.getAttribute("name")).to.equal("keywords"); expect(thirdTag.getAttribute("content")).to.equal( "test,meta,tags" ); expect(thirdTag.outerHTML).to.equal( `` ); done(); }); }); it("allows duplicate meta tags if specified in the same component", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `meta[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; const secondTag = existingTags[1]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(2); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("name")).to.equal( "description" ); expect(firstTag.getAttribute("content")).to.equal( "Test description" ); expect(firstTag.outerHTML).to.equal( `` ); expect(existingTags).to.have.deep .property("[1]") .that.is.an.instanceof(Element); expect(secondTag).to.have.property("getAttribute"); expect(secondTag.getAttribute("name")).to.equal( "description" ); expect(secondTag.getAttribute("content")).to.equal( "Duplicate description" ); expect(secondTag.outerHTML).to.equal( `` ); done(); }); }); it("overrides duplicate meta tags with single meta tag in a nested component", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `meta[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(1); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("name")).to.equal( "description" ); expect(firstTag.getAttribute("content")).to.equal( "Inner description" ); expect(firstTag.outerHTML).to.equal( `` ); done(); }); }); it("overrides single meta tag with duplicate meta tags in a nested component", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `meta[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; const secondTag = existingTags[1]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(2); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("name")).to.equal( "description" ); expect(firstTag.getAttribute("content")).to.equal( "Inner description" ); expect(firstTag.outerHTML).to.equal( `` ); expect(existingTags).to.have.deep .property("[1]") .that.is.an.instanceof(Element); expect(secondTag).to.have.property("getAttribute"); expect(secondTag.getAttribute("name")).to.equal( "description" ); expect(secondTag.getAttribute("content")).to.equal( "Inner duplicate description" ); expect(secondTag.outerHTML).to.equal( `` ); done(); }); }); it("does not render tag when primary attribute is null", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `meta[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); expect(existingTags).to.be.empty; done(); }); }); it("fails gracefully when meta is wrong shape", done => { const error = sinon.stub(console, "error"); const warn = sinon.stub(console, "warn"); ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `meta[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); expect(existingTags).to.be.empty; expect(error.called).to.be.true; expect(warn.called).to.be.true; const [warning] = warn.getCall(0).args; expect(warning).to.equal( `Helmet: meta should be of type "Array". Instead found type "object"` ); error.restore(); warn.restore(); done(); }); }); }); describe("link tags", () => { it("updates link tags", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `link[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); expect(existingTags).to.not.equal(undefined); const filteredTags = [].slice .call(existingTags) .filter(tag => { return ( (tag.getAttribute("href") === "http://localhost/style.css" && tag.getAttribute("rel") === "stylesheet" && tag.getAttribute("type") === "text/css") || (tag.getAttribute("href") === "http://localhost/helmet" && tag.getAttribute("rel") === "canonical") ); }); expect(filteredTags.length).to.be.at.least(2); done(); }); }); it("clears all link tags if none are specified", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { ReactDOM.render(, container); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `link[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call( tagNodes ); expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(0); done(); }); }); }); it("tags without 'href' or 'rel' are not accepted, even if they are valid for other tags", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `link[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(0); done(); }); }); it("tags 'rel' and 'href' properly use 'rel' as the primary identification for this tag, regardless of ordering", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `link[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(1); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("rel")).to.equal("canonical"); expect(firstTag.getAttribute("href")).to.equal( "http://localhost/helmet/newest" ); expect(firstTag.outerHTML).to.equal( `` ); done(); }); }); it("tags with rel='stylesheet' uses the href as the primary identification of the tag, regardless of ordering", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `link[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; const secondTag = existingTags[1]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(2); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("href")).to.equal( "http://localhost/style.css" ); expect(firstTag.getAttribute("rel")).to.equal("stylesheet"); expect(firstTag.getAttribute("type")).to.equal("text/css"); expect(firstTag.getAttribute("media")).to.equal("all"); expect(firstTag.outerHTML).to.equal( `` ); expect(existingTags).to.have.deep .property("[1]") .that.is.an.instanceof(Element); expect(secondTag).to.have.property("getAttribute"); expect(secondTag.getAttribute("rel")).to.equal( "stylesheet" ); expect(secondTag.getAttribute("href")).to.equal( "http://localhost/inner.css" ); expect(secondTag.getAttribute("type")).to.equal("text/css"); expect(secondTag.getAttribute("media")).to.equal("all"); expect(secondTag.outerHTML).to.equal( `` ); done(); }); }); it("sets link tags based on deepest nested component", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `link[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; const secondTag = existingTags[1]; const thirdTag = existingTags[2]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.be.at.least(2); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("href")).to.equal( "http://localhost/style.css" ); expect(firstTag.getAttribute("rel")).to.equal("stylesheet"); expect(firstTag.getAttribute("type")).to.equal("text/css"); expect(firstTag.getAttribute("media")).to.equal("all"); expect(firstTag.outerHTML).to.equal( `` ); expect(existingTags).to.have.deep .property("[1]") .that.is.an.instanceof(Element); expect(secondTag).to.have.property("getAttribute"); expect(secondTag.getAttribute("href")).to.equal( "http://localhost/helmet/innercomponent" ); expect(secondTag.getAttribute("rel")).to.equal("canonical"); expect(secondTag.outerHTML).to.equal( `` ); expect(existingTags).to.have.deep .property("[2]") .that.is.an.instanceof(Element); expect(thirdTag).to.have.property("getAttribute"); expect(thirdTag.getAttribute("href")).to.equal( "http://localhost/inner.css" ); expect(thirdTag.getAttribute("rel")).to.equal("stylesheet"); expect(thirdTag.getAttribute("type")).to.equal("text/css"); expect(thirdTag.getAttribute("media")).to.equal("all"); expect(thirdTag.outerHTML).to.equal( `` ); done(); }); }); it("allows duplicate link tags if specified in the same component", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `link[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; const secondTag = existingTags[1]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.be.at.least(2); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("rel")).to.equal("canonical"); expect(firstTag.getAttribute("href")).to.equal( "http://localhost/helmet" ); expect(firstTag.outerHTML).to.equal( `` ); expect(existingTags).to.have.deep .property("[1]") .that.is.an.instanceof(Element); expect(secondTag).to.have.property("getAttribute"); expect(secondTag.getAttribute("rel")).to.equal("canonical"); expect(secondTag.getAttribute("href")).to.equal( "http://localhost/helmet/component" ); expect(secondTag.outerHTML).to.equal( `` ); done(); }); }); it("overrides duplicate link tags with a single link tag in a nested component", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `link[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.be.equal(1); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("rel")).to.equal("canonical"); expect(firstTag.getAttribute("href")).to.equal( "http://localhost/helmet/innercomponent" ); expect(firstTag.outerHTML).to.equal( `` ); done(); }); }); it("overrides single link tag with duplicate link tags in a nested component", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `link[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; const secondTag = existingTags[1]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.be.equal(2); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("rel")).to.equal("canonical"); expect(firstTag.getAttribute("href")).to.equal( "http://localhost/helmet/component" ); expect(firstTag.outerHTML).to.equal( `` ); expect(existingTags).to.have.deep .property("[1]") .that.is.an.instanceof(Element); expect(secondTag).to.have.property("getAttribute"); expect(secondTag.getAttribute("rel")).to.equal("canonical"); expect(secondTag.getAttribute("href")).to.equal( "http://localhost/helmet/innercomponent" ); expect(secondTag.outerHTML).to.equal( `` ); done(); }); }); it("does not render tag when primary attribute is null", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `link[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.be.equal(1); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("rel")).to.equal("canonical"); expect(firstTag.getAttribute("href")).to.equal( "http://localhost/helmet/component" ); expect(firstTag.outerHTML).to.equal( `` ); done(); }); }); }); describe("script tags", () => { it("updates script tags", done => { const scriptInnerHTML = ` { "@context": "http://schema.org", "@type": "NewsArticle", "url": "http://localhost/helmet" } `; ReactDOM.render( , container ); requestAnimationFrame(() => { const existingTags = headElement.getElementsByTagName( "script" ); expect(existingTags).to.not.equal(undefined); const filteredTags = [].slice .call(existingTags) .filter(tag => { return ( (tag.getAttribute("src") === "http://localhost/test.js" && tag.getAttribute("type") === "text/javascript") || (tag.getAttribute("src") === "http://localhost/test2.js" && tag.getAttribute("type") === "text/javascript") || (tag.getAttribute("type") === "application/ld+json" && tag.innerHTML === scriptInnerHTML) ); }); expect(filteredTags.length).to.be.at.least(3); done(); }); }); it("clears all scripts tags if none are specified", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { ReactDOM.render(, container); requestAnimationFrame(() => { const existingTags = headElement.querySelectorAll( `script[${HELMET_ATTRIBUTE}]` ); expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(0); done(); }); }); }); it("tags without 'src' are not accepted", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const existingTags = headElement.querySelectorAll( `script[${HELMET_ATTRIBUTE}]` ); expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(0); done(); }); }); it("sets script tags based on deepest nested component", done => { ReactDOM.render(
, container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `script[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const firstTag = existingTags[0]; const secondTag = existingTags[1]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.be.at.least(2); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("src")).to.equal( "http://localhost/test.js" ); expect(firstTag.getAttribute("type")).to.equal( "text/javascript" ); expect(firstTag.outerHTML).to.equal( `` ); expect(existingTags).to.have.deep .property("[1]") .that.is.an.instanceof(Element); expect(secondTag).to.have.property("getAttribute"); expect(secondTag.getAttribute("src")).to.equal( "http://localhost/test2.js" ); expect(secondTag.getAttribute("type")).to.equal( "text/javascript" ); expect(secondTag.outerHTML).to.equal( `` ); done(); }); }); it("sets undefined attribute values to empty strings", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const existingTag = headElement.querySelector( `script[${HELMET_ATTRIBUTE}]` ); expect(existingTag).to.not.equal(undefined); expect(existingTag.outerHTML).to.be .a("string") .that.equals( `` ); done(); }); }); it("does not render tag when primary attribute (src) is null", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `script[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); expect(existingTags).to.be.empty; done(); }); }); it("does not render tag when primary attribute (innerHTML) is null", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `script[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); expect(existingTags).to.be.empty; done(); }); }); }); describe("noscript tags", () => { it("updates noscript tags", done => { const noscriptInnerHTML = ``; ReactDOM.render( , container ); requestAnimationFrame(() => { const existingTags = headElement.getElementsByTagName( "noscript" ); expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(1); expect( existingTags[0].innerHTML === noscriptInnerHTML && existingTags[0].id === "bar" ); done(); }); }); it("clears all noscripts tags if none are specified", done => { ReactDOM.render(, container); requestAnimationFrame(() => { ReactDOM.render(, container); requestAnimationFrame(() => { const existingTags = headElement.querySelectorAll( `script[${HELMET_ATTRIBUTE}]` ); expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(0); done(); }); }); }); it("tags without 'innerHTML' are not accepted", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const existingTags = headElement.querySelectorAll( `noscript[${HELMET_ATTRIBUTE}]` ); expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(0); done(); }); }); it("does not render tag when primary attribute is null", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `noscript[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); expect(existingTags).to.be.empty; done(); }); }); }); describe("style tags", () => { it("updates style tags", done => { const cssText1 = ` body { background-color: green; } `; const cssText2 = ` p { font-size: 12px; } `; ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `style[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); const [firstTag, secondTag] = existingTags; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.be.equal(2); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(firstTag).to.have.property("getAttribute"); expect(firstTag.getAttribute("type")).to.equal("text/css"); expect(firstTag.innerHTML).to.equal(cssText1); expect(firstTag.outerHTML).to.equal( `` ); expect(existingTags).to.have.deep .property("[1]") .that.is.an.instanceof(Element); expect(secondTag.innerHTML).to.equal(cssText2); expect(secondTag.outerHTML).to.equal( `` ); done(); }); }); it("clears all style tags if none are specified", done => { const cssText = ` body { background-color: green; } `; ReactDOM.render( , container ); requestAnimationFrame(() => { ReactDOM.render(, container); requestAnimationFrame(() => { const existingTags = headElement.querySelectorAll( `style[${HELMET_ATTRIBUTE}]` ); expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(0); done(); }); }); }); it("tags without 'cssText' are not accepted", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const existingTags = headElement.querySelectorAll( `style[${HELMET_ATTRIBUTE}]` ); expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.equal(0); done(); }); }); it("does not render tag when primary attribute is null", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const tagNodes = headElement.querySelectorAll( `style[${HELMET_ATTRIBUTE}]` ); const existingTags = Array.prototype.slice.call(tagNodes); expect(existingTags).to.be.empty; done(); }); }); }); }); describe("deferred tags", () => { beforeEach(() => { window.__spy__ = sinon.spy(); }); afterEach(() => { delete window.__spy__; }); it("executes synchronously when defer={true} and async otherwise", done => { ReactDOM.render(
, container ); expect(window.__spy__.callCount).to.equal(1); requestAnimationFrame(() => { expect(window.__spy__.callCount).to.equal(2); expect(window.__spy__.args).to.deep.equal([[1], [2]]); done(); }); }); }); describe("server", () => { const stringifiedHtmlAttributes = `lang="ga" class="myClassName"`; const stringifiedTitle = `Dangerous <script> include`; const unEncodedStringifiedTitle = `This is text and & and '.`; const stringifiedTitleWithItemprop = `Title with Itemprop`; const stringifiedBaseTag = ``; const stringifiedMetaTags = [ ``, ``, ``, ``, `` ].join(""); const stringifiedLinkTags = [ ``, `` ].join(""); const stringifiedScriptTags = [ ``, `` ].join(""); const stringifiedNoscriptTags = [ ``, `` ].join(""); const stringifiedStyleTags = [ ``, `` ].join(""); before(() => { Helmet.canUseDOM = false; }); it("provides initial values if no state is found", () => { let head = Helmet.rewind(); head = Helmet.rewind(); expect(head.meta).to.exist; expect(head.meta).to.respondTo("toString"); expect(head.meta.toString()).to.equal(""); }); it("encodes special characters in title", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.title).to.exist; expect(head.title).to.respondTo("toString"); expect(head.title.toString()).to.equal(stringifiedTitle); }); it("opts out of string encoding", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.title).to.exist; expect(head.title).to.respondTo("toString"); expect(head.title.toString()).to.equal(unEncodedStringifiedTitle); }); it("renders title as React component", () => { ReactDOM.render( include"} />, container ); const head = Helmet.rewind(); expect(head.title).to.exist; expect(head.title).to.respondTo("toComponent"); const titleComponent = head.title.toComponent(); expect(titleComponent).to.be.an("array").that.has.length.of(1); titleComponent.forEach(title => { expect(title).to.be .an("object") .that.contains.property("type", "title"); }); const markup = ReactServer.renderToStaticMarkup(
{titleComponent}
); expect(markup).to.be .a("string") .that.equals(`
${stringifiedTitle}
`); }); it("renders title with itemprop name as React component", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.title).to.exist; expect(head.title).to.respondTo("toComponent"); const titleComponent = head.title.toComponent(); expect(titleComponent).to.be.an("array").that.has.length.of(1); titleComponent.forEach(title => { expect(title).to.be .an("object") .that.contains.property("type", "title"); }); const markup = ReactServer.renderToStaticMarkup(
{titleComponent}
); expect(markup).to.be .a("string") .that.equals(`
${stringifiedTitleWithItemprop}
`); }); it("renders base tag as React component", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.base).to.exist; expect(head.base).to.respondTo("toComponent"); const baseComponent = head.base.toComponent(); expect(baseComponent).to.be.an("array").that.has.length.of(1); baseComponent.forEach(base => { expect(base).to.be .an("object") .that.contains.property("type", "base"); }); const markup = ReactServer.renderToStaticMarkup(
{baseComponent}
); expect(markup).to.be .a("string") .that.equals(`
${stringifiedBaseTag}
`); }); it("renders meta tags as React components", () => { ReactDOM.render( < `" }, {"http-equiv": "content-type", content: "text/html"}, {property: "og:type", content: "article"}, {itemprop: "name", content: "Test name itemprop"} ]} />, container ); const head = Helmet.rewind(); expect(head.meta).to.exist; expect(head.meta).to.respondTo("toComponent"); const metaComponent = head.meta.toComponent(); expect(metaComponent).to.be.an("array").that.has.length.of(5); metaComponent.forEach(meta => { expect(meta).to.be .an("object") .that.contains.property("type", "meta"); }); const markup = ReactServer.renderToStaticMarkup(
{metaComponent}
); expect(markup).to.be .a("string") .that.equals(`
${stringifiedMetaTags}
`); }); it("renders link tags as React components", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.link).to.exist; expect(head.link).to.respondTo("toComponent"); const linkComponent = head.link.toComponent(); expect(linkComponent).to.be.an("array").that.has.length.of(2); linkComponent.forEach(link => { expect(link).to.be .an("object") .that.contains.property("type", "link"); }); const markup = ReactServer.renderToStaticMarkup(
{linkComponent}
); expect(markup).to.be .a("string") .that.equals(`
${stringifiedLinkTags}
`); }); it("renders script tags as React components", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.script).to.exist; expect(head.script).to.respondTo("toComponent"); const scriptComponent = head.script.toComponent(); expect(scriptComponent).to.be.an("array").that.has.length.of(2); scriptComponent.forEach(script => { expect(script).to.be .an("object") .that.contains.property("type", "script"); }); const markup = ReactServer.renderToStaticMarkup(
{scriptComponent}
); expect(markup).to.be .a("string") .that.equals(`
${stringifiedScriptTags}
`); }); it("renders noscript tags as React components", () => { ReactDOM.render( ' }, { id: "bar", innerHTML: '' } ]} />, container ); const head = Helmet.rewind(); expect(head.noscript).to.exist; expect(head.noscript).to.respondTo("toComponent"); const noscriptComponent = head.noscript.toComponent(); expect(noscriptComponent).to.be.an("array").that.has.length.of(2); noscriptComponent.forEach(noscript => { expect(noscript).to.be .an("object") .that.contains.property("type", "noscript"); }); const markup = ReactServer.renderToStaticMarkup(
{noscriptComponent}
); expect(markup).to.be .a("string") .that.equals(`
${stringifiedNoscriptTags}
`); }); it("renders style tags as React components", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.style).to.exist; expect(head.style).to.respondTo("toComponent"); const styleComponent = head.style.toComponent(); expect(styleComponent).to.be.an("array").that.has.length.of(2); const markup = ReactServer.renderToStaticMarkup(
{styleComponent}
); expect(markup).to.be .a("string") .that.equals(`
${stringifiedStyleTags}
`); }); it("renders title tag as string", () => { ReactDOM.render( include"} />, container ); const head = Helmet.rewind(); expect(head.title).to.exist; expect(head.title).to.respondTo("toString"); expect(head.title.toString()).to.be .a("string") .that.equals(stringifiedTitle); }); it("renders title with itemprop name as string", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.title).to.exist; expect(head.title).to.respondTo("toString"); const titleString = head.title.toString(); expect(titleString).to.be .a("string") .that.equals(stringifiedTitleWithItemprop); }); it("renders base tags as string", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.base).to.exist; expect(head.base).to.respondTo("toString"); expect(head.base.toString()).to.be .a("string") .that.equals(stringifiedBaseTag); }); it("renders meta tags as string", () => { ReactDOM.render( < `" }, {"http-equiv": "content-type", content: "text/html"}, {property: "og:type", content: "article"}, {itemprop: "name", content: "Test name itemprop"} ]} />, container ); const head = Helmet.rewind(); expect(head.meta).to.exist; expect(head.meta).to.respondTo("toString"); expect(head.meta.toString()).to.be .a("string") .that.equals(stringifiedMetaTags); }); it("renders link tags as string", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.link).to.exist; expect(head.link).to.respondTo("toString"); expect(head.link.toString()).to.be .a("string") .that.equals(stringifiedLinkTags); }); it("renders script tags as string", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.script).to.exist; expect(head.script).to.respondTo("toString"); expect(head.script.toString()).to.be .a("string") .that.equals(stringifiedScriptTags); }); it("renders style tags as string", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.style).to.exist; expect(head.style).to.respondTo("toString"); expect(head.style.toString()).to.be .a("string") .that.equals(stringifiedStyleTags); }); it("renders html attributes as component", () => { ReactDOM.render( , container ); const {htmlAttributes} = Helmet.rewind(); const attrs = htmlAttributes.toComponent(); expect(attrs).to.exist; const markup = ReactServer.renderToStaticMarkup( ); expect(markup).to.be .a("string") .that.equals(``); }); it("renders html attributes as string", () => { ReactDOM.render( , container ); const head = Helmet.rewind(); expect(head.htmlAttributes).to.exist; expect(head.htmlAttributes).to.respondTo("toString"); expect(head.htmlAttributes.toString()).to.be .a("string") .that.equals(stringifiedHtmlAttributes); }); it("does not encode all characters with HTML character entity equivalents", () => { const chineseTitle = "膣膗 鍆錌雔"; const stringifiedChineseTitle = `${chineseTitle}`; ReactDOM.render(
, container ); const head = Helmet.rewind(); expect(head.title).to.exist; expect(head.title).to.respondTo("toString"); expect(head.title.toString()).to.be .a("string") .that.equals(stringifiedChineseTitle); }); it("rewind() provides a fallback object for empty Helmet state", () => { ReactDOM.render(
, container); const head = Helmet.rewind(); expect(head.htmlAttributes).to.exist; expect(head.htmlAttributes).to.respondTo("toString"); expect(head.htmlAttributes.toString()).to.equal(""); expect(head.htmlAttributes).to.respondTo("toComponent"); expect(head.htmlAttributes.toComponent()).to.be.an("object").that.is .empty; expect(head.title).to.exist; expect(head.title).to.respondTo("toString"); expect(head.title.toString()).to.equal( `` ); expect(head.title).to.respondTo("toComponent"); const markup = ReactServer.renderToStaticMarkup(
{head.title.toComponent()}
); expect(markup).to.be .a("string") .that.equals( `
` ); expect(head.base).to.exist; expect(head.base).to.respondTo("toString"); expect(head.base.toString()).to.equal(""); expect(head.base).to.respondTo("toComponent"); expect(head.base.toComponent()).to.be.an("array").that.is.empty; expect(head.meta).to.exist; expect(head.meta).to.respondTo("toString"); expect(head.meta.toString()).to.equal(""); expect(head.meta).to.respondTo("toComponent"); expect(head.meta.toComponent()).to.be.an("array").that.is.empty; expect(head.link).to.exist; expect(head.link).to.respondTo("toString"); expect(head.link.toString()).to.equal(""); expect(head.link).to.respondTo("toComponent"); expect(head.link.toComponent()).to.be.an("array").that.is.empty; expect(head.script).to.exist; expect(head.script).to.respondTo("toString"); expect(head.script.toString()).to.equal(""); expect(head.script).to.respondTo("toComponent"); expect(head.script.toComponent()).to.be.an("array").that.is.empty; expect(head.noscript).to.exist; expect(head.noscript).to.respondTo("toString"); expect(head.noscript.toString()).to.equal(""); expect(head.noscript).to.respondTo("toComponent"); expect(head.noscript.toComponent()).to.be.an("array").that.is.empty; expect(head.style).to.exist; expect(head.style).to.respondTo("toString"); expect(head.style.toString()).to.equal(""); expect(head.style).to.respondTo("toComponent"); expect(head.style.toComponent()).to.be.an("array").that.is.empty; }); it("does not render undefined attribute values", () => { ReactDOM.render( , container ); const {script} = Helmet.rewind(); const stringifiedScriptTag = script.toString(); expect(stringifiedScriptTag).to.be .a("string") .that.equals( `` ); }); after(() => { Helmet.canUseDOM = true; }); }); describe("misc", () => { it("throws in rewind() when a DOM is present", () => { ReactDOM.render(, container); expect(Helmet.rewind).to.throw( "You may only call rewind() on the server. Call peek() to read the current state." ); }); it("lets you read current state in peek() whether or not a DOM is present", done => { ReactDOM.render(, container); requestAnimationFrame(() => { expect(Helmet.peek().title).to.be.equal("Fancy title"); Helmet.canUseDOM = false; expect(Helmet.peek().title).to.be.equal("Fancy title"); Helmet.canUseDOM = true; done(); }); }); it("encodes special characters", done => { ReactDOM.render( , container ); requestAnimationFrame(() => { const existingTags = headElement.querySelectorAll( `meta[${HELMET_ATTRIBUTE}]` ); const existingTag = existingTags[0]; expect(existingTags).to.not.equal(undefined); expect(existingTags.length).to.be.equal(1); expect(existingTags).to.have.deep .property("[0]") .that.is.an.instanceof(Element); expect(existingTag).to.have.property("getAttribute"); expect(existingTag.getAttribute("name")).to.equal( "description" ); expect(existingTag.getAttribute("content")).to.equal( 'This is "quoted" text and & and \'.' ); expect(existingTag.outerHTML).to.equal( `` ); done(); }); }); it("does not change the DOM if it recevies identical props", done => { const spy = sinon.spy(); ReactDOM.render( , container ); requestAnimationFrame(() => { // Re-rendering will pass new props to an already mounted Helmet ReactDOM.render( , container ); requestAnimationFrame(() => { expect(spy.callCount).to.equal(1); done(); }); }); }); it("does not write the DOM if the client and server are identical", done => { headElement.innerHTML = `