diff --git a/e2e-tests/development-runtime/cypress/integration/slices/slice-via-create-page.js b/e2e-tests/development-runtime/cypress/integration/slices/slice-via-create-page.js new file mode 100644 index 0000000000000..3e0b4cd6cecb5 --- /dev/null +++ b/e2e-tests/development-runtime/cypress/integration/slices/slice-via-create-page.js @@ -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) + }) + }) +}) diff --git a/e2e-tests/development-runtime/cypress/integration/slices/slices.js b/e2e-tests/development-runtime/cypress/integration/slices/slices.js new file mode 100644 index 0000000000000..5e2ec4156b110 --- /dev/null +++ b/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`) + }) +}) diff --git a/e2e-tests/development-runtime/gatsby-node.js b/e2e-tests/development-runtime/gatsby-node.js index d4fc084389919..591abf013737f 100644 --- a/e2e-tests/development-runtime/gatsby-node.js +++ b/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, @@ -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", @@ -47,7 +49,8 @@ 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, @@ -55,7 +58,8 @@ exports.sourceNodes = ({ actions, createNodeId, createContentDigest }) => { }, { 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", @@ -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(` @@ -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`), diff --git a/e2e-tests/development-runtime/shared-data/slices.js b/e2e-tests/development-runtime/shared-data/slices.js new file mode 100644 index 0000000000000..651111121772e --- /dev/null +++ b/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 } diff --git a/e2e-tests/development-runtime/src/components/footer.js b/e2e-tests/development-runtime/src/components/footer.js new file mode 100644 index 0000000000000..d95fc72ff6266 --- /dev/null +++ b/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 ( + + ) +} + +export default Footer diff --git a/e2e-tests/development-runtime/src/components/layout.js b/e2e-tests/development-runtime/src/components/layout.js index ce4f8f7938738..f834dc8d6b563 100644 --- a/e2e-tests/development-runtime/src/components/layout.js +++ b/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" @@ -29,6 +29,12 @@ const Layout = ({ children }) => ( > {children} + + + {/** The slice below doesn't exist but it shouldn't break build */} + + + {/** Insert this here and expect it to fail */} )} /> diff --git a/e2e-tests/development-runtime/src/components/recipe-author.js b/e2e-tests/development-runtime/src/components/recipe-author.js new file mode 100644 index 0000000000000..7d5f0ec09ba53 --- /dev/null +++ b/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 ( +
+ Written by{" "} + + {name} + +
+ ) +} + +export default RecipeAuthor diff --git a/e2e-tests/development-runtime/src/context-for-slices.js b/e2e-tests/development-runtime/src/context-for-slices.js new file mode 100644 index 0000000000000..ac82422b7635f --- /dev/null +++ b/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 ( + + {children} + + ) +} + +export { ContextForSlices, ContextForSlicesProvider } diff --git a/e2e-tests/development-runtime/src/templates/recipe.js b/e2e-tests/development-runtime/src/templates/recipe.js new file mode 100644 index 0000000000000..5f2f3377e29b4 --- /dev/null +++ b/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 ( + +

{name}

+

{description}

+ +
+ ) +} + +export default Recipe diff --git a/e2e-tests/development-runtime/src/wrap-root-element.js b/e2e-tests/development-runtime/src/wrap-root-element.js index 0eadae8422525..a136c16c29094 100644 --- a/e2e-tests/development-runtime/src/wrap-root-element.js +++ b/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 }) => ( ( siteMetadata: { title }, }, }) => ( - <> + {element}