Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: e2e tests for Slices API #36746

Merged
merged 18 commits into from Nov 16, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,25 @@
import { allRecipes, allRecipeAuthors } from "../../../shared-data/slices"

/**
* Test behaviour when a slice is created and passed `slices` option to createPage
*/

describe("Slice passed via createPage", () => {
it("Pages created with slices mapping have correct content", () => {
allRecipes.forEach(recipe => {
cy.visit(`recipe/${recipe.id}`).waitForRouteChange()

cy.getTestElement(`recipe-name`)
.invoke(`text`)
.should(`contain`, recipe.name)

cy.getTestElement(`recipe-description`)
.invoke(`text`)
.should(`contain`, recipe.description)

cy.getTestElement(`recipe-author-name`)
.invoke(`text`)
.should(`contain`, allRecipeAuthors.find(author => recipe.authorId === author.id).name)
})
})
})
33 changes: 33 additions & 0 deletions e2e-tests/development-runtime/cypress/integration/slices/slices.js
@@ -0,0 +1,33 @@
/**
* Test basic Slices API behaviour like context, props, ....
*/

describe(`Slices`, () => {
beforeEach(() => {
cy.visit(`/`).waitForRouteChange()
})

it(`Slice content show on screen`, () => {
cy.getTestElement(`footer-static-text`)
.invoke(`text`)
.should(`contain`, `Built with`)
})

it(`Slice recieves context passed via createSlice`, () => {
cy.getTestElement(`footer-slice-context-value`)
.invoke(`text`)
.should(`contain`, `Gatsby`)
})

it(`Slice can take in props`, () => {
cy.getTestElement(`footer-props`)
.invoke(`text`)
.should(`contains`, `Gatsbyjs`)
})

it(`Slice can consume a context wrapped in WrapRootElement`, () => {
cy.getTestElement(`footer-context-derieved-value`)
.invoke(`text`)
.should(`contain`, `2`)
})
})
47 changes: 43 additions & 4 deletions e2e-tests/development-runtime/gatsby-node.js
@@ -1,6 +1,7 @@
const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)
const headFunctionExportSharedData = require("./shared-data/head-function-export")
const slicesData = require("./shared-data/slices")
const {
addRemoteFilePolyfillInterface,
polyfillImageServiceDevRoutes,
Expand Down Expand Up @@ -37,7 +38,8 @@ exports.sourceNodes = ({ actions, createNodeId, createContentDigest }) => {
const items = [
{
name: "photoA.jpg",
url: "https://images.unsplash.com/photo-1517849845537-4d257902454a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2000&q=80",
url:
"https://images.unsplash.com/photo-1517849845537-4d257902454a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2000&q=80",
placeholderUrl:
"https://images.unsplash.com/photo-1517849845537-4d257902454a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=%width%&h=%height%",
mimeType: "image/jpg",
Expand All @@ -47,15 +49,17 @@ exports.sourceNodes = ({ actions, createNodeId, createContentDigest }) => {
},
{
name: "photoB.jpg",
url: "https://images.unsplash.com/photo-1552053831-71594a27632d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&h=2000&q=10",
url:
"https://images.unsplash.com/photo-1552053831-71594a27632d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&h=2000&q=10",
mimeType: "image/jpg",
filename: "photo-1552053831.jpg",
width: 1247,
height: 2000,
},
{
name: "photoC.jpg",
url: "https://images.unsplash.com/photo-1561037404-61cd46aa615b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2000&q=80",
url:
"https://images.unsplash.com/photo-1561037404-61cd46aa615b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2000&q=80",
placeholderUrl:
"https://images.unsplash.com/photo-1561037404-61cd46aa615b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=%width%&h=%height%",
mimeType: "image/jpg",
Expand Down Expand Up @@ -122,7 +126,7 @@ exports.onCreateNode = function onCreateNode({
* @type {import('gatsby').createPages}
*/
exports.createPages = async function createPages({
actions: { createPage, createRedirect },
actions: { createPage, createRedirect, createSlice },
graphql,
}) {
const { data } = await graphql(`
Expand Down Expand Up @@ -172,6 +176,41 @@ exports.createPages = async function createPages({
})
})

//-------------------------Slice API----------------------------
createSlice({
id: `footer`,
component: path.resolve(`./src/components/footer.js`),
context: {
framework: slicesData.framework,
},
})

slicesData.allRecipeAuthors.forEach(({ id, name }) => {
createSlice({
id: `author-${id}`,
component: path.resolve(`./src/components/recipe-author.js`),
context: {
name,
id,
},
})
})

slicesData.allRecipes.forEach(({ authorId, id, name, description }) => {
createPage({
path: `/recipe/${id}`,
component: path.resolve(`./src/templates/recipe.js`),
context: {
description: description,
name,
},
slices: {
author: `author-${authorId}`,
},
})
})
//---------------------------------------------------------------

createPage({
path: `/안녕`,
component: path.resolve(`src/pages/page-2.js`),
Expand Down
25 changes: 25 additions & 0 deletions e2e-tests/development-runtime/shared-data/slices.js
@@ -0,0 +1,25 @@
const allRecipes = [
{
id: "r1",
name: "Jollof Rice",
description:
"It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).",
authorId: "a-1",
},
{
id: "r2",
name: "Ewa Agoyin",
description:
"It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).",
authorId: "a-2",
},
]

const allRecipeAuthors = [
{ id: "a-1", name: "Jude" },
{ id: "a-2", name: "Ty" },
]

const framework = "Gatsby"

module.exports = { allRecipes, allRecipeAuthors, framework }
23 changes: 23 additions & 0 deletions e2e-tests/development-runtime/src/components/footer.js
@@ -0,0 +1,23 @@
import React, { useContext } from "react"
import { ContextForSlices } from "../context-for-slices"

// Use as a Slice
function Footer({ framework, lang, sliceContext: { framework: frameworkViaContext }}) {
const { posts } = useContext(ContextForSlices)

return (
<footer
style={{
marginTop: `10px`,
fontSize: `12px`,
}}
>
<span data-testid="footer-slice-context-value">{frameworkViaContext}</span>
<span data-testid="footer-static-text">Built with {` `}</span>
<span data-testid="footer-props">{`${framework}${lang}`}</span>
{` `}Posts Count: <span data-testid="footer-context-derieved-value">{`${posts.length}`}</span>
</footer>
)
}

export default Footer
8 changes: 7 additions & 1 deletion e2e-tests/development-runtime/src/components/layout.js
@@ -1,6 +1,6 @@
import React from "react"
import PropTypes from "prop-types"
import { StaticQuery, graphql } from "gatsby"
import { StaticQuery, graphql, Slice } from "gatsby"

import Header from "./header"
import "./layout.css"
Expand Down Expand Up @@ -29,6 +29,12 @@ const Layout = ({ children }) => (
>
{children}
</div>
<Slice alias="footer" framework="Gatsby" lang="js"/>

{/** The slice below doesn't exist but it shouldn't break build */}
<Slice alias="this-alias-does-not-exist" allowEmpty/>

{/** Insert this here and expect it to fail <Slice alias="this-alias-does-not-exist-too"/>*/}
</>
)}
/>
Expand Down
15 changes: 15 additions & 0 deletions e2e-tests/development-runtime/src/components/recipe-author.js
@@ -0,0 +1,15 @@
import React from "react"

// Use as a Slice
function RecipeAuthor({ sliceContext: { name } }) {
return (
<div>
Written by{" "}
<span data-testid="recipe-author-name" style={{ fontWeight: "bold" }}>
{name}
</span>
</div>
)
}

export default RecipeAuthor
25 changes: 25 additions & 0 deletions e2e-tests/development-runtime/src/context-for-slices.js
@@ -0,0 +1,25 @@
import React from "react"

const ContextForSlices = React.createContext()

const ContextForSlicesProvider = ({ children }) => {
const contextValue = {
posts: [
{
title: "My first blog post",
content: "This is my first blog post",
},
{
title: "My second blog post",
content: "This is my second blog post",
},
],
}
return (
<ContextForSlices.Provider value={contextValue}>
{children}
</ContextForSlices.Provider>
)
}

export { ContextForSlices, ContextForSlicesProvider }
15 changes: 15 additions & 0 deletions e2e-tests/development-runtime/src/templates/recipe.js
@@ -0,0 +1,15 @@
import React from "react"
import { Slice } from "gatsby"
import Layout from "../components/layout"

const Recipe = ({ pageContext: { description, name } }) => {
return (
<Layout>
<h1 data-testid="recipe-name">{name}</h1>
<p data-testid="recipe-description">{description}</p>
<Slice alias="author" />
</Layout>
)
}

export default Recipe
5 changes: 3 additions & 2 deletions e2e-tests/development-runtime/src/wrap-root-element.js
@@ -1,6 +1,7 @@
import React from "react"
import { StaticQuery, graphql, Script } from "gatsby"
import { scripts } from "../gatsby-script-scripts"
import { ContextForSlicesProvider } from "./context-for-slices"

const WrapRootElement = ({ element }) => (
<StaticQuery
Expand All @@ -18,7 +19,7 @@ const WrapRootElement = ({ element }) => (
siteMetadata: { title },
},
}) => (
<>
<ContextForSlicesProvider>
{element}
<Script src={scripts.jQuery} strategy="post-hydrate" />
<Script src={scripts.popper} strategy="idle" />
Expand All @@ -29,7 +30,7 @@ const WrapRootElement = ({ element }) => (
%TEST_HMR_IN_GATSBY_BROWSER%
</div>
</div>
</>
</ContextForSlicesProvider>
)}
/>
)
Expand Down
@@ -0,0 +1,25 @@
import { allRecipes, allRecipeAuthors } from "../../../shared-data/slices"

/**
* Test behaviour when a slice is created and passed `slices` option to createPage
*/

describe("Slice passed via createPage", () => {
it("Pages created with slices mapping have correct content", () => {
allRecipes.forEach(recipe => {
cy.visit(`recipe/${recipe.id}`).waitForRouteChange()

cy.getTestElement(`recipe-name`)
.invoke(`text`)
.should(`contain`, recipe.name)

cy.getTestElement(`recipe-description`)
.invoke(`text`)
.should(`contain`, recipe.description)

cy.getTestElement(`recipe-author-name`)
.invoke(`text`)
.should(`contain`, allRecipeAuthors.find(author => recipe.authorId === author.id).name)
})
})
})
44 changes: 44 additions & 0 deletions e2e-tests/production-runtime/cypress/integration/slices/slices.js
@@ -0,0 +1,44 @@
/**
* Test basic Slices API behaviour like context, props, ....
*/

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(`Slices`, () => {
beforeEach(() => {
cy.visit(`/`).waitForRouteChange()
})

it(`Slice content show on screen`, () => {
cy.getTestElement(`footer-static-text`)
.invoke(`text`)
.should(`contain`, `Built with`)
})

it(`Slice recieves context passed via createSlice`, () => {
cy.getTestElement(`footer-slice-context-value`)
.invoke(`text`)
.should(`contain`, `Gatsby`)
})

it(`Slice can take in props`, () => {
cy.getTestElement(`footer-props`)
.invoke(`text`)
.should(`contains`, `Gatsbyjs`)
})

it(`Slice can consume a context wrapped in WrapRootElement`, () => {
cy.getTestElement(`footer-context-derieved-value`)
.invoke(`text`)
.should(`contain`, `2`)
})
})