UNPKG

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
/* 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(() => {