Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import headFunctionExportSharedData from "../../../shared-data/head-function-export.js"

describe(`Html and body attributes`, () => {
it(`Page has body and html attributes on direct visit`, () => {
cy.visit(
headFunctionExportSharedData.page.htmlAndBodyAttributes
).waitForRouteChange()

cy.get(`body`).should(`have.attr`, `data-foo`, `baz`)
cy.get(`body`).should(`have.attr`, `class`, `foo`)
cy.get(`html`).should(`have.attr`, `data-foo`, `bar`)
cy.get(`html`).should(`have.attr`, `lang`, `fr`)
})

it(`Page has body and html attributes on client-side navigation`, () => {
cy.visit(headFunctionExportSharedData.page.basic).waitForRouteChange()

cy.get(`body`).should(`not.have.attr`, `data-foo`, `baz`)
cy.get(`body`).should(`not.have.attr`, `class`, `foo`)
cy.get(`html`).should(`not.have.attr`, `data-foo`, `bar`)
cy.get(`html`).should(`not.have.attr`, `lang`, `fr`)

cy.visit(
headFunctionExportSharedData.page.htmlAndBodyAttributes
).waitForRouteChange()

cy.get(`body`).should(`have.attr`, `data-foo`, `baz`)
cy.get(`body`).should(`have.attr`, `class`, `foo`)
cy.get(`html`).should(`have.attr`, `data-foo`, `bar`)
cy.get(`html`).should(`have.attr`, `lang`, `fr`)
})

it(`Body and html attributes are removed on client-side navigation when new page doesn't set them`, () => {
cy.visit(
headFunctionExportSharedData.page.htmlAndBodyAttributes
).waitForRouteChange()

cy.get(`body`).should(`have.attr`, `data-foo`, `baz`)
cy.get(`body`).should(`have.attr`, `class`, `foo`)
cy.get(`html`).should(`have.attr`, `data-foo`, `bar`)
cy.get(`html`).should(`have.attr`, `lang`, `fr`)

cy.visit(headFunctionExportSharedData.page.basic).waitForRouteChange()

cy.get(`body`).should(`not.have.attr`, `data-foo`, `baz`)
cy.get(`body`).should(`not.have.attr`, `class`, `foo`)
cy.get(`html`).should(`not.have.attr`, `data-foo`, `bar`)
cy.get(`html`).should(`not.have.attr`, `lang`, `fr`)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const page = {
invalidElements: `${path}/invalid-elements/`,
fsRouteApi: `${path}/fs-route-api/`,
deduplication: `${path}/deduplication/`,
htmlAndBodyAttributes: `${path}/html-and-body-attributes/`,
}

const data = {
Expand All @@ -23,7 +24,7 @@ const data = {
style: `rebeccapurple`,
link: `/used-by-head-function-export-basic.css`,
extraMeta: `Extra meta tag that should be removed during navigation`,
jsonLD: `{"@context":"https://schema.org","@type":"Organization","url":"https://www.spookytech.com","name":"Spookytechnologies","contactPoint":{"@type":"ContactPoint","telephone":"+5-601-785-8543","contactType":"CustomerSupport"}}`
jsonLD: `{"@context":"https://schema.org","@type":"Organization","url":"https://www.spookytech.com","name":"Spookytechnologies","contactPoint":{"@type":"ContactPoint","telephone":"+5-601-785-8543","contactType":"CustomerSupport"}}`,
},
queried: {
base: `http://localhost:8000`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from "react"

export default function HeadFunctionHtmlAndBodyAttributes() {
return (
<>
<h1>I have html and body attributes</h1>
</>
)
}

function Indirection({ children }) {
return (
<>
<html lang="fr" />
<body className="foo" />
{children}
</>
)
}

export function Head() {
return (
<Indirection>
<html data-foo="bar" />
<body data-foo="baz" />
</Indirection>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import headFunctionExportSharedData from "../../../shared-data/head-function-export.js"

Cypress.on("uncaught:exception", err => {
if (
(err.message.includes("Minified React error #418") ||
err.message.includes("Minified React error #423") ||
err.message.includes("Minified React error #425")) &&
Cypress.env(`TEST_PLUGIN_OFFLINE`)
) {
return false
}
})

describe(`Html and body attributes`, () => {
it(`Page has body and html attributes on direct visit`, () => {
cy.visit(
headFunctionExportSharedData.page.htmlAndBodyAttributes
).waitForRouteChange()

cy.get(`body`).should(`have.attr`, `data-foo`, `baz`)
cy.get(`body`).should(`have.attr`, `class`, `foo`)
cy.get(`html`).should(`have.attr`, `data-foo`, `bar`)
cy.get(`html`).should(`have.attr`, `lang`, `fr`)
})

it(`Page has body and html attributes on client-side navigation`, () => {
cy.visit(headFunctionExportSharedData.page.basic).waitForRouteChange()

cy.get(`body`).should(`not.have.attr`, `data-foo`, `baz`)
cy.get(`body`).should(`not.have.attr`, `class`, `foo`)
cy.get(`html`).should(`not.have.attr`, `data-foo`, `bar`)
cy.get(`html`).should(`not.have.attr`, `lang`, `fr`)

cy.visit(
headFunctionExportSharedData.page.htmlAndBodyAttributes
).waitForRouteChange()

cy.get(`body`).should(`have.attr`, `data-foo`, `baz`)
cy.get(`body`).should(`have.attr`, `class`, `foo`)
cy.get(`html`).should(`have.attr`, `data-foo`, `bar`)
cy.get(`html`).should(`have.attr`, `lang`, `fr`)
})

it(`Body and html attributes are removed on client-side navigation when new page doesn't set them`, () => {
cy.visit(
headFunctionExportSharedData.page.htmlAndBodyAttributes
).waitForRouteChange()

cy.get(`body`).should(`have.attr`, `data-foo`, `baz`)
cy.get(`body`).should(`have.attr`, `class`, `foo`)
cy.get(`html`).should(`have.attr`, `data-foo`, `bar`)
cy.get(`html`).should(`have.attr`, `lang`, `fr`)

cy.visit(headFunctionExportSharedData.page.basic).waitForRouteChange()

cy.get(`body`).should(`not.have.attr`, `data-foo`, `baz`)
cy.get(`body`).should(`not.have.attr`, `class`, `foo`)
cy.get(`html`).should(`not.have.attr`, `data-foo`, `bar`)
cy.get(`html`).should(`not.have.attr`, `lang`, `fr`)
})
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { page, data } from "../../../shared-data/head-function-export.js"

Cypress.on("uncaught:exception", err => {
if (
(err.message.includes("Minified React error #418") ||
err.message.includes("Minified React error #423") ||
err.message.includes("Minified React error #425")) &&
Cypress.env(`TEST_PLUGIN_OFFLINE`)
) {
return false
}
})

describe(`Head function export html insertion`, () => {
it(`should work with static data`, () => {
cy.visit(page.basic).waitForRouteChange()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const page = {
fsRouteApi: `${path}/fs-route-api/`,
deduplication: `${path}/deduplication/`,
pageWithUseLocation: `${path}/page-with-uselocation/`,
htmlAndBodyAttributes: `${path}/html-and-body-attributes/`,
}

const data = {
Expand All @@ -24,7 +25,7 @@ const data = {
style: `rebeccapurple`,
link: `/used-by-head-function-export-basic.css`,
extraMeta: `Extra meta tag that should be removed during navigation`,
jsonLD: `{"@context":"https://schema.org","@type":"Organization","url":"https://www.spookytech.com","name":"Spookytechnologies","contactPoint":{"@type":"ContactPoint","telephone":"+5-601-785-8543","contactType":"CustomerSupport"}}`
jsonLD: `{"@context":"https://schema.org","@type":"Organization","url":"https://www.spookytech.com","name":"Spookytechnologies","contactPoint":{"@type":"ContactPoint","telephone":"+5-601-785-8543","contactType":"CustomerSupport"}}`,
},
queried: {
base: `http://localhost:9000`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from "react"

export default function HeadFunctionHtmlAndBodyAttributes() {
return (
<>
<h1>I have html and body attributes</h1>
</>
)
}

function Indirection({ children }) {
return (
<>
<html lang="fr" />
<body className="foo" />
{children}
</>
)
}

export function Head() {
return (
<Indirection>
<html data-foo="bar" />
<body data-foo="baz" />
</Indirection>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,24 @@ describe(`Head function export SSR'ed HTML output`, () => {
// alternate links are not using id, so should have multiple instances
expect(dom.querySelectorAll(`link[rel=alternate]`)?.length).toEqual(2)
})

it(`should allow setting html and body attributes`, () => {
const html = readFileSync(
`${publicDir}${page.bodyAndHtmlAttributes}/index.html`
)
const dom = parse(html)
expect(dom.querySelector(`html`).attributes).toMatchInlineSnapshot(`
{
"data-foo": "bar",
"lang": "fr",
}
`)

expect(dom.querySelector(`body`).attributes).toMatchInlineSnapshot(`
{
"class": "foo",
"data-foo": "baz",
}
`)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const page = {
warnings: `${path}/warnings/`,
allProps: `${path}/all-props/`,
deduplication: `${path}/deduplication/`,
bodyAndHtmlAttributes: `${path}/html-and-body-attributes/`,
}

const data = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from "react"

export default function HeadFunctionHtmlAndBodyAttributes() {
return (
<>
<h1>I have html and body attributes</h1>
</>
)
}

function Indirection({ children }) {
return (
<>
<html lang="fr" />
<body className="foo" />
{children}
</>
)
}

export function Head() {
return (
<Indirection>
<html data-foo="bar" />
<body data-foo="baz" />
</Indirection>
)
}
18 changes: 18 additions & 0 deletions integration-tests/ssr/__tests__/ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,24 @@ describe(`SSR`, () => {
const ssrHead = ssrDom.querySelector(`[data-testid=title]`)

expect(devSsrHead.textContent).toEqual(ssrHead.textContent)
expect(devSsrDom.querySelector(`html`).attributes).toEqual(
ssrDom.querySelector(`html`).attributes
)
expect(devSsrDom.querySelector(`html`).attributes).toMatchInlineSnapshot(`
Object {
"data-foo": "bar",
"lang": "fr",
}
`)

expect(devSsrDom.querySelector(`body`).attributes).toEqual(
ssrDom.querySelector(`body`).attributes
)
expect(devSsrDom.querySelector(`body`).attributes).toMatchInlineSnapshot(`
Object {
"data-foo": "baz",
}
`)
})

describe(`it generates an error page correctly`, () => {
Expand Down
8 changes: 7 additions & 1 deletion integration-tests/ssr/src/pages/head-function-export.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@ export default function PageWithHeadFunctionExport() {
}

export function Head() {
return <title data-testid="title">Hello world</title>
return (
<>
<html lang="fr" data-foo="bar" />
<body data-foo="baz" />
<title data-testid="title">Hello world</title>
</>
)
}
2 changes: 2 additions & 0 deletions packages/gatsby/cache-dir/head/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ export const VALID_NODE_NAMES = [
`base`,
`noscript`,
`script`,
`html`,
`body`,
]
Loading