diff --git a/.circleci/config.yml b/.circleci/config.yml index c09ccbd22021e..3fcc7a76ffe50 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -130,16 +130,17 @@ jobs: executor: node <<: *test_template - integration_tests: + integration_tests_long_term_caching: executor: node steps: - - checkout - - run: ./scripts/assert-changed-files.sh "packages/*|integration-tests/*|.circleci/*" - - <<: *restore_cache - - <<: *install_node_modules - - <<: *persist_cache - - <<: *attach_to_bootstrap - - run: yarn test:integration + - e2e-test: + test_path: integration-tests/long-term-caching + + integration_tests_gatsby_pipeline: + executor: node + steps: + - e2e-test: + test_path: integration-tests/gatsby-pipeline e2e_tests_gatsbygram: <<: *e2e-executor @@ -210,7 +211,9 @@ workflows: <<: *ignore_docs requires: - bootstrap - - integration_tests: + - integration_tests_long_term_caching: + <<: *ignore_docs + - integration_tests_gatsby_pipeline: <<: *ignore_docs - e2e_tests_gatsbygram: <<: *e2e-test-workflow diff --git a/integration-tests/gatsby-pipeline/LICENSE b/integration-tests/gatsby-pipeline/LICENSE new file mode 100644 index 0000000000000..5169a5e4135e9 --- /dev/null +++ b/integration-tests/gatsby-pipeline/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 gatsbyjs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/integration-tests/gatsby-pipeline/README.md b/integration-tests/gatsby-pipeline/README.md new file mode 100644 index 0000000000000..f0fb934ccbbac --- /dev/null +++ b/integration-tests/gatsby-pipeline/README.md @@ -0,0 +1,11 @@ +# gatsby-pipeline + +It's a default gatsby starter to test our build & develop pipeline. + +## Install + +You can install all dependencies by running `yarn` or `npm install`. + +## Tests + +To run our test suite you can simply run `yarn test`. If you want to test with the latest sources from the packages directory. You can use the [e2e-test.sh](https://github.com/gatsbyjs/gatsby/blob/master/scripts/e2e-test.sh) helper script that we use for CI. You can run it as `sh scripts/e2e-test.sh integration-tests/gatsby-pipeline` from the root directory. diff --git a/integration-tests/gatsby-pipeline/__tests__/lazy-image-build/develop.js b/integration-tests/gatsby-pipeline/__tests__/lazy-image-build/develop.js new file mode 100644 index 0000000000000..f0f4f8eea47b6 --- /dev/null +++ b/integration-tests/gatsby-pipeline/__tests__/lazy-image-build/develop.js @@ -0,0 +1,61 @@ +const execa = require(`execa`) +const path = require(`path`) +const fs = require(`fs-extra`) +const glob = require(`glob`) +const request = require(`request-promise-native`) +const createDevServer = require(`../../utils/create-devserver`) +const basePath = path.resolve(__dirname, `../../`) + +// 2 min +jest.setTimeout(2000 * 60) + +const cleanDirs = () => + Promise.all([ + fs.emptyDir(`${basePath}/public`), + fs.emptyDir(`${basePath}/.cache`), + ]) + +describe(`Lazy images`, () => { + beforeAll(async () => { + await cleanDirs() + }) + + test(`should process images on demand`, async () => { + const { kill } = await createDevServer() + + const response = await request( + `http://localhost:8000/static/6d91c86c0fde632ba4cd01062fd9ccfa/a2541/gatsby-astronaut.png`, + { + resolveWithFullResponse: true, + } + ) + + await kill() + + expect(response.statusCode).toBe(200) + + const images = glob.sync(`${basePath}/public/**/*.png`) + expect(images.length).toBe(6) + }) + + test(`should process the rest of images on build`, async () => { + await execa(`yarn`, [`build`], { + cwd: basePath, + env: { NODE_ENV: `production` }, + }) + + const images = glob.sync(`${basePath}/public/**/*.png`) + expect(images.length).toBe(6) + }) + + test(`should process all images from a clean build`, async () => { + await cleanDirs() + await execa(`yarn`, [`build`], { + cwd: basePath, + env: { NODE_ENV: `production` }, + }) + + const images = glob.sync(`${basePath}/public/**/*.png`) + expect(images.length).toBe(6) + }) +}) diff --git a/integration-tests/gatsby-pipeline/gatsby-browser.js b/integration-tests/gatsby-pipeline/gatsby-browser.js new file mode 100644 index 0000000000000..b1e5c316b7f94 --- /dev/null +++ b/integration-tests/gatsby-pipeline/gatsby-browser.js @@ -0,0 +1,7 @@ +/** + * Implement Gatsby's Browser APIs in this file. + * + * See: https://www.gatsbyjs.org/docs/browser-apis/ + */ + +// You can delete this file if you're not using it diff --git a/integration-tests/gatsby-pipeline/gatsby-config.js b/integration-tests/gatsby-pipeline/gatsby-config.js new file mode 100644 index 0000000000000..bfda48c3cf314 --- /dev/null +++ b/integration-tests/gatsby-pipeline/gatsby-config.js @@ -0,0 +1,19 @@ +module.exports = { + siteMetadata: { + title: `Gatsby Default Starter`, + description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`, + author: `@gatsbyjs`, + }, + plugins: [ + `gatsby-plugin-react-helmet`, + { + resolve: `gatsby-source-filesystem`, + options: { + name: `images`, + path: `${__dirname}/src/images`, + }, + }, + `gatsby-transformer-sharp`, + `gatsby-plugin-sharp`, + ], +} diff --git a/integration-tests/gatsby-pipeline/package.json b/integration-tests/gatsby-pipeline/package.json new file mode 100644 index 0000000000000..2869aa1590eb5 --- /dev/null +++ b/integration-tests/gatsby-pipeline/package.json @@ -0,0 +1,39 @@ +{ + "name": "gatsby-starter-default", + "description": "Gatsby default starter", + "version": "1.0.0", + "author": "Kyle Mathews ", + "dependencies": { + "gatsby": "latest", + "gatsby-image": "latest", + "gatsby-plugin-react-helmet": "latest", + "gatsby-plugin-sharp": "latest", + "gatsby-source-filesystem": "latest", + "gatsby-transformer-sharp": "latest", + "prop-types": "^15.6.2", + "react": "^16.7.0", + "react-dom": "^16.7.0", + "react-helmet": "^5.2.0" + }, + "keywords": [ + "gatsby" + ], + "license": "MIT", + "scripts": { + "build": "gatsby build --prefix-paths", + "develop": "gatsby develop", + "test": "jest --config=../jest.config.js gatsby-pipeline/" + }, + "devDependencies": { + "execa": "^1.0.0", + "fs-extra": "^7.0.1", + "jest": "^24.0.0", + "jest-cli": "^24.0.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5" + }, + "repository": { + "type": "git", + "url": "https://github.com/gatsbyjs/gatsby-starter-default" + } +} diff --git a/integration-tests/gatsby-pipeline/src/components/header.js b/integration-tests/gatsby-pipeline/src/components/header.js new file mode 100644 index 0000000000000..8990b7e31bb7a --- /dev/null +++ b/integration-tests/gatsby-pipeline/src/components/header.js @@ -0,0 +1,42 @@ +import { Link } from "gatsby" +import PropTypes from "prop-types" +import React from "react" + +const Header = ({ siteTitle }) => ( +
+
+

+ + {siteTitle} + +

+
+
+) + +Header.propTypes = { + siteTitle: PropTypes.string, +} + +Header.defaultProps = { + siteTitle: ``, +} + +export default Header diff --git a/integration-tests/gatsby-pipeline/src/components/image.js b/integration-tests/gatsby-pipeline/src/components/image.js new file mode 100644 index 0000000000000..2d068b89a89c9 --- /dev/null +++ b/integration-tests/gatsby-pipeline/src/components/image.js @@ -0,0 +1,32 @@ +import React from "react" +import { StaticQuery, graphql } from "gatsby" +import Img from "gatsby-image" + +/* + * This component is built using `gatsby-image` to automatically serve optimized + * images with lazy loading and reduced file sizes. The image is loaded using a + * `StaticQuery`, which allows us to load the image from directly within this + * component, rather than having to pass the image data down from pages. + * + * For more information, see the docs: + * - `gatsby-image`: https://gatsby.app/gatsby-image + * - `StaticQuery`: https://gatsby.app/staticquery + */ + +const Image = () => ( + } + /> +) +export default Image diff --git a/integration-tests/gatsby-pipeline/src/components/layout.css b/integration-tests/gatsby-pipeline/src/components/layout.css new file mode 100644 index 0000000000000..101f6244f95fd --- /dev/null +++ b/integration-tests/gatsby-pipeline/src/components/layout.css @@ -0,0 +1,620 @@ +html { + font-family: sans-serif; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +main, +menu, +nav, +section, +summary { + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; +} +audio:not([controls]) { + display: none; + height: 0; +} +progress { + vertical-align: baseline; +} +[hidden], +template { + display: none; +} +a { + background-color: transparent; + -webkit-text-decoration-skip: objects; +} +a:active, +a:hover { + outline-width: 0; +} +abbr[title] { + border-bottom: none; + text-decoration: underline; + text-decoration: underline dotted; +} +b, +strong { + font-weight: inherit; + font-weight: bolder; +} +dfn { + font-style: italic; +} +h1 { + font-size: 2em; + margin: 0.67em 0; +} +mark { + background-color: #ff0; + color: #000; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sub { + bottom: -0.25em; +} +sup { + top: -0.5em; +} +img { + border-style: none; +} +svg:not(:root) { + overflow: hidden; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +figure { + margin: 1em 40px; +} +hr { + box-sizing: content-box; + height: 0; + overflow: visible; +} +button, +input, +optgroup, +select, +textarea { + font: inherit; + margin: 0; +} +optgroup { + font-weight: 700; +} +button, +input { + overflow: visible; +} +button, +select { + text-transform: none; +} +[type="reset"], +[type="submit"], +button, +html [type="button"] { + -webkit-appearance: button; +} +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner, +button::-moz-focus-inner { + border-style: none; + padding: 0; +} +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring, +button:-moz-focusring { + outline: 1px dotted ButtonText; +} +fieldset { + border: 1px solid silver; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} +legend { + box-sizing: border-box; + color: inherit; + display: table; + max-width: 100%; + padding: 0; + white-space: normal; +} +textarea { + overflow: auto; +} +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; + padding: 0; +} +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px; +} +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +::-webkit-input-placeholder { + color: inherit; + opacity: 0.54; +} +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit; +} +html { + font: 112.5%/1.45em georgia, serif; + box-sizing: border-box; + overflow-y: scroll; +} +* { + box-sizing: inherit; +} +*:before { + box-sizing: inherit; +} +*:after { + box-sizing: inherit; +} +body { + color: hsla(0, 0%, 0%, 0.8); + font-family: georgia, serif; + font-weight: normal; + word-wrap: break-word; + font-kerning: normal; + -moz-font-feature-settings: "kern", "liga", "clig", "calt"; + -ms-font-feature-settings: "kern", "liga", "clig", "calt"; + -webkit-font-feature-settings: "kern", "liga", "clig", "calt"; + font-feature-settings: "kern", "liga", "clig", "calt"; +} +img { + max-width: 100%; + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +h1 { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; + color: inherit; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; + font-weight: bold; + text-rendering: optimizeLegibility; + font-size: 2.25rem; + line-height: 1.1; +} +h2 { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; + color: inherit; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; + font-weight: bold; + text-rendering: optimizeLegibility; + font-size: 1.62671rem; + line-height: 1.1; +} +h3 { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; + color: inherit; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; + font-weight: bold; + text-rendering: optimizeLegibility; + font-size: 1.38316rem; + line-height: 1.1; +} +h4 { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; + color: inherit; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; + font-weight: bold; + text-rendering: optimizeLegibility; + font-size: 1rem; + line-height: 1.1; +} +h5 { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; + color: inherit; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; + font-weight: bold; + text-rendering: optimizeLegibility; + font-size: 0.85028rem; + line-height: 1.1; +} +h6 { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; + color: inherit; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; + font-weight: bold; + text-rendering: optimizeLegibility; + font-size: 0.78405rem; + line-height: 1.1; +} +hgroup { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +ul { + margin-left: 1.45rem; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; + list-style-position: outside; + list-style-image: none; +} +ol { + margin-left: 1.45rem; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; + list-style-position: outside; + list-style-image: none; +} +dl { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +dd { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +p { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +figure { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +pre { + margin-left: 0; + margin-right: 0; + margin-top: 0; + margin-bottom: 1.45rem; + font-size: 0.85rem; + line-height: 1.42; + background: hsla(0, 0%, 0%, 0.04); + border-radius: 3px; + overflow: auto; + word-wrap: normal; + padding: 1.45rem; +} +table { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; + font-size: 1rem; + line-height: 1.45rem; + border-collapse: collapse; + width: 100%; +} +fieldset { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +blockquote { + margin-left: 1.45rem; + margin-right: 1.45rem; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +form { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +noscript { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +iframe { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +hr { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: calc(1.45rem - 1px); + background: hsla(0, 0%, 0%, 0.2); + border: none; + height: 1px; +} +address { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + margin-bottom: 1.45rem; +} +b { + font-weight: bold; +} +strong { + font-weight: bold; +} +dt { + font-weight: bold; +} +th { + font-weight: bold; +} +li { + margin-bottom: calc(1.45rem / 2); +} +ol li { + padding-left: 0; +} +ul li { + padding-left: 0; +} +li > ol { + margin-left: 1.45rem; + margin-bottom: calc(1.45rem / 2); + margin-top: calc(1.45rem / 2); +} +li > ul { + margin-left: 1.45rem; + margin-bottom: calc(1.45rem / 2); + margin-top: calc(1.45rem / 2); +} +blockquote *:last-child { + margin-bottom: 0; +} +li *:last-child { + margin-bottom: 0; +} +p *:last-child { + margin-bottom: 0; +} +li > p { + margin-bottom: calc(1.45rem / 2); +} +code { + font-size: 0.85rem; + line-height: 1.45rem; +} +kbd { + font-size: 0.85rem; + line-height: 1.45rem; +} +samp { + font-size: 0.85rem; + line-height: 1.45rem; +} +abbr { + border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); + cursor: help; +} +acronym { + border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); + cursor: help; +} +abbr[title] { + border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); + cursor: help; + text-decoration: none; +} +thead { + text-align: left; +} +td, +th { + text-align: left; + border-bottom: 1px solid hsla(0, 0%, 0%, 0.12); + font-feature-settings: "tnum"; + -moz-font-feature-settings: "tnum"; + -ms-font-feature-settings: "tnum"; + -webkit-font-feature-settings: "tnum"; + padding-left: 0.96667rem; + padding-right: 0.96667rem; + padding-top: 0.725rem; + padding-bottom: calc(0.725rem - 1px); +} +th:first-child, +td:first-child { + padding-left: 0; +} +th:last-child, +td:last-child { + padding-right: 0; +} +tt, +code { + background-color: hsla(0, 0%, 0%, 0.04); + border-radius: 3px; + font-family: "SFMono-Regular", Consolas, "Roboto Mono", "Droid Sans Mono", + "Liberation Mono", Menlo, Courier, monospace; + padding: 0; + padding-top: 0.2em; + padding-bottom: 0.2em; +} +pre code { + background: none; + line-height: 1.42; +} +code:before, +code:after, +tt:before, +tt:after { + letter-spacing: -0.2em; + content: " "; +} +pre code:before, +pre code:after, +pre tt:before, +pre tt:after { + content: ""; +} +@media only screen and (max-width: 480px) { + html { + font-size: 100%; + } +} diff --git a/integration-tests/gatsby-pipeline/src/components/layout.js b/integration-tests/gatsby-pipeline/src/components/layout.js new file mode 100644 index 0000000000000..b18838351684a --- /dev/null +++ b/integration-tests/gatsby-pipeline/src/components/layout.js @@ -0,0 +1,46 @@ +import React from "react" +import PropTypes from "prop-types" +import { StaticQuery, graphql } from "gatsby" + +import Header from "./header" +import "./layout.css" + +const Layout = ({ children }) => ( + ( + <> +
+
+
{children}
+
+ © {new Date().getFullYear()}, Built with + {` `} + Gatsby +
+
+ + )} + /> +) + +Layout.propTypes = { + children: PropTypes.node.isRequired, +} + +export default Layout diff --git a/integration-tests/gatsby-pipeline/src/components/seo.js b/integration-tests/gatsby-pipeline/src/components/seo.js new file mode 100644 index 0000000000000..284672d55824e --- /dev/null +++ b/integration-tests/gatsby-pipeline/src/components/seo.js @@ -0,0 +1,96 @@ +import React from "react" +import PropTypes from "prop-types" +import Helmet from "react-helmet" +import { StaticQuery, graphql } from "gatsby" + +function SEO({ description, lang, meta, keywords, title }) { + return ( + { + const metaDescription = + description || data.site.siteMetadata.description + return ( + 0 + ? { + name: `keywords`, + content: keywords.join(`, `), + } + : [] + ) + .concat(meta)} + /> + ) + }} + /> + ) +} + +SEO.defaultProps = { + lang: `en`, + meta: [], + keywords: [], +} + +SEO.propTypes = { + description: PropTypes.string, + lang: PropTypes.string, + meta: PropTypes.array, + keywords: PropTypes.arrayOf(PropTypes.string), + title: PropTypes.string.isRequired, +} + +export default SEO + +const detailsQuery = graphql` + query DefaultSEOQuery { + site { + siteMetadata { + title + description + author + } + } + } +` diff --git a/integration-tests/gatsby-pipeline/src/images/gatsby-astronaut.png b/integration-tests/gatsby-pipeline/src/images/gatsby-astronaut.png new file mode 100644 index 0000000000000..da58ece0a8c5b Binary files /dev/null and b/integration-tests/gatsby-pipeline/src/images/gatsby-astronaut.png differ diff --git a/integration-tests/gatsby-pipeline/src/images/gatsby-icon.png b/integration-tests/gatsby-pipeline/src/images/gatsby-icon.png new file mode 100644 index 0000000000000..908bc78a7f559 Binary files /dev/null and b/integration-tests/gatsby-pipeline/src/images/gatsby-icon.png differ diff --git a/integration-tests/gatsby-pipeline/src/pages/404.js b/integration-tests/gatsby-pipeline/src/pages/404.js new file mode 100644 index 0000000000000..bc4c31d79353c --- /dev/null +++ b/integration-tests/gatsby-pipeline/src/pages/404.js @@ -0,0 +1,14 @@ +import React from "react" + +import Layout from "../components/layout" +import SEO from "../components/seo" + +const NotFoundPage = () => ( + + +

NOT FOUND

+

You just hit a route that doesn't exist... the sadness.

+
+) + +export default NotFoundPage diff --git a/integration-tests/gatsby-pipeline/src/pages/index.js b/integration-tests/gatsby-pipeline/src/pages/index.js new file mode 100644 index 0000000000000..2079a127bc4bb --- /dev/null +++ b/integration-tests/gatsby-pipeline/src/pages/index.js @@ -0,0 +1,21 @@ +import React from "react" +import { Link } from "gatsby" + +import Layout from "../components/layout" +import Image from "../components/image" +import SEO from "../components/seo" + +const IndexPage = () => ( + + +

Hi people

+

Welcome to your new Gatsby site.

+

Now go build something great.

+
+ +
+ Go to page 2 +
+) + +export default IndexPage diff --git a/integration-tests/gatsby-pipeline/src/pages/page-2.js b/integration-tests/gatsby-pipeline/src/pages/page-2.js new file mode 100644 index 0000000000000..666c23ef30f9d --- /dev/null +++ b/integration-tests/gatsby-pipeline/src/pages/page-2.js @@ -0,0 +1,16 @@ +import React from "react" +import { Link } from "gatsby" + +import Layout from "../components/layout" +import SEO from "../components/seo" + +const SecondPage = () => ( + + +

Hi from the second page

+

Welcome to page 2

+ Go back to the homepage +
+) + +export default SecondPage diff --git a/integration-tests/gatsby-pipeline/utils/create-devserver.js b/integration-tests/gatsby-pipeline/utils/create-devserver.js new file mode 100644 index 0000000000000..81ae0168b8fe2 --- /dev/null +++ b/integration-tests/gatsby-pipeline/utils/create-devserver.js @@ -0,0 +1,33 @@ +const execa = require(`execa`) +const path = require(`path`) +const basePath = path.resolve(__dirname, `../`) + +const killProcess = devProcess => + new Promise(resolve => { + devProcess.on(`exit`, () => { + // give it some time to exit + setTimeout(() => { + resolve() + }, 0) + }) + + // If pid is less than -1, then sig is sent to every process in the process group whose ID is -pid. + // @see https://stackoverflow.com/a/33367711 + process.kill(-devProcess.pid) + }) + +module.exports = () => + new Promise(resolve => { + const devProcess = execa(`yarn`, [`develop`], { + cwd: basePath, + env: { NODE_ENV: `development` }, + detached: true, + }) + + devProcess.stdout.on(`data`, chunk => { + if (chunk.toString().includes(`You can now view`)) { + // We only need to expose a kill function, the rest is not needed + resolve({ kill: () => killProcess(devProcess) }) + } + }) + }) diff --git a/integration-tests/jest.config.js b/integration-tests/jest.config.js index ab24e1c5491e6..419dd58ea1cd7 100644 --- a/integration-tests/jest.config.js +++ b/integration-tests/jest.config.js @@ -1,12 +1,19 @@ +const glob = require(`glob`) + +const pkgs = glob + .sync(`${__dirname}/*/`) + .map(p => p.replace(__dirname, `/integration-tests`)) + module.exports = { rootDir: `../`, - roots: [`/integration-tests`], + roots: pkgs, testPathIgnorePatterns: [ `/examples/`, `/www/`, `/dist/`, `/node_modules/`, `__tests__/fixtures`, + `.cache`, ], transform: { "^.+\\.js$": `/jest-transformer.js` }, } diff --git a/integration-tests/long-term-caching/__tests__/long-term-caching.js b/integration-tests/long-term-caching/__tests__/long-term-caching.js index 75dc035aa4562..8168239b0108e 100644 --- a/integration-tests/long-term-caching/__tests__/long-term-caching.js +++ b/integration-tests/long-term-caching/__tests__/long-term-caching.js @@ -39,7 +39,7 @@ describe(`long term caching`, () => { const createPublic0 = async () => { execFileSync(`yarn`, [`build`], { cwd: basePath }) - move(`${basePath}/public`, `${basePath}/public-0`) + return move(`${basePath}/public`, `${basePath}/public-0`) } const createPublic1 = async () => { @@ -51,7 +51,7 @@ describe(`long term caching`, () => { await writeFile(`${pagesPath}/index.js`, modifiedData) execFileSync(`yarn`, [`build`], { cwd: basePath }) - await move(`${basePath}/public`, `${basePath}/public-1`) + return move(`${basePath}/public`, `${basePath}/public-1`) } const createPublic2 = async () => { @@ -64,7 +64,7 @@ describe(`long term caching`, () => { await writeFile(`${pagesPath}/index.js`, modifiedData) execFileSync(`yarn`, [`build`], { cwd: basePath }) - await move(`${basePath}/public`, `${basePath}/public-2`) + return move(`${basePath}/public`, `${basePath}/public-2`) } const createPublic3 = async () => { @@ -77,7 +77,7 @@ describe(`long term caching`, () => { await writeFile(`${pagesPath}/index.js`, modifiedData) execFileSync(`yarn`, [`build`], { cwd: basePath }) - await move(`${basePath}/public`, `${basePath}/public-3`) + return move(`${basePath}/public`, `${basePath}/public-3`) } const createPublic4 = async () => { @@ -91,7 +91,7 @@ describe(`long term caching`, () => { await writeFile(`${pagesPath}/index.js`, modifiedData) execFileSync(`yarn`, [`build`], { cwd: basePath }) - await move(`${basePath}/public`, `${basePath}/public-4`) + return move(`${basePath}/public`, `${basePath}/public-4`) } const createPublic5 = async () => { @@ -103,7 +103,7 @@ describe(`long term caching`, () => { await writeFile(`${srcPath}/async-2.js`, modifiedData) execFileSync(`yarn`, [`build`], { cwd: basePath }) - await move(`${basePath}/public`, `${basePath}/public-5`) + return move(`${basePath}/public`, `${basePath}/public-5`) } beforeAll(async () => { @@ -120,8 +120,6 @@ describe(`long term caching`, () => { srcPath = resolve(`${basePath}/src`) pagesPath = resolve(`${srcPath}/pages`) - execFileSync(`yarn`, [], { cwd: basePath }) - await createPublic0() await createPublic1() await createPublic2() diff --git a/integration-tests/long-term-caching/package.json b/integration-tests/long-term-caching/package.json index 889d0487e10a9..70af26aaa0470 100644 --- a/integration-tests/long-term-caching/package.json +++ b/integration-tests/long-term-caching/package.json @@ -5,6 +5,7 @@ "scripts": { "develop": "gatsby develop", "build": "gatsby build", + "test": "jest --config=../jest.config.js long-term-caching/", "serve": "gatsby serve" }, "dependencies": { @@ -14,6 +15,8 @@ "react-dom": "^16.2.0" }, "devDependencies": { - "babel-plugin-dynamic-import-node-sync": "^2.0.1" + "babel-plugin-dynamic-import-node-sync": "^2.0.1", + "jest": "^24.0.0", + "jest-cli": "^24.0.0" } } diff --git a/scripts/e2e-test.sh b/scripts/e2e-test.sh index dc8d403dceb0d..e9451c9c73284 100755 --- a/scripts/e2e-test.sh +++ b/scripts/e2e-test.sh @@ -3,7 +3,8 @@ SRC_PATH=$1 CUSTOM_COMMAND="${2:-yarn test}" GATSBY_PATH="${CIRCLE_WORKING_DIRECTORY:-../../}" -npm install -g gatsby-dev-cli && +# cypress docker does not support sudo and do not need it but the default node executor does +command -v sudo && sudo npm install -g gatsby-dev-cli || npm install -g gatsby-dev-cli && # setting up child integration test link to gatsby packages cd $SRC_PATH &&