diff --git a/.eslintrc.json b/.eslintrc.json index a5d012e448afb..4efa02222c841 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -59,7 +59,7 @@ } }, { - "files": ["**/cypress/integration/**/*"], + "files": ["**/cypress/integration/**/*", "**/cypress/support/**/*"], "globals": { "cy": false, "Cypress": false diff --git a/e2e-tests/production-runtime/cypress/integration/lifecycle-methods.js b/e2e-tests/production-runtime/cypress/integration/lifecycle-methods.js new file mode 100644 index 0000000000000..774e9346b9065 --- /dev/null +++ b/e2e-tests/production-runtime/cypress/integration/lifecycle-methods.js @@ -0,0 +1,41 @@ +describe(`Production build tests`, () => { + it(`should remount when navigating to different template`, () => { + cy.visit(`/`).waitForAPI(`onRouteUpdate`) + + cy.getTestElement(`page2`) + .click() + .waitForAPI(`onRouteUpdate`) + + // we expect 2 `componentDidMount` calls - 1 for initial page and 1 for second page + cy.lifecycleCallCount(`componentDidMount`).should(`equal`, 2) + cy.lifecycleCallCount(`render`).should(`equal`, 2) + }) + + it(`should remount when navigating to different page using same template`, () => { + cy.visit(`/`).waitForAPI(`onRouteUpdate`) + + cy.getTestElement(`duplicated`) + .click() + .waitForAPI(`onRouteUpdate`) + + // we expect 2 `componentDidMount` calls - 1 for initial page and 1 for duplicated page + cy.lifecycleCallCount(`componentDidMount`).should(`equal`, 2) + cy.lifecycleCallCount(`render`).should(`equal`, 2) + }) + + it(`should NOT remount when navigating within client only paths`, () => { + cy.visit(`/client-only-paths`).waitForAPI(`onRouteUpdate`) + + cy.getTestElement(`/profile`) + .click() + .waitForAPI(`onRouteUpdate`) + + cy.getTestElement(`/dashboard`) + .click() + .waitForAPI(`onRouteUpdate`) + + // we expect just 1 `componentDidMount` call, when navigating inside matchPath + cy.lifecycleCallCount(`componentDidMount`).should(`equal`, 1) + cy.lifecycleCallCount(`render`).should(`equal`, 3) + }) +}) diff --git a/e2e-tests/production-runtime/cypress/support/commands.js b/e2e-tests/production-runtime/cypress/support/commands.js new file mode 100644 index 0000000000000..62bedced4b6be --- /dev/null +++ b/e2e-tests/production-runtime/cypress/support/commands.js @@ -0,0 +1,10 @@ +Cypress.Commands.add(`lifecycleCallCount`, action => + cy + .window() + .then( + win => + win.___PageComponentLifecycleCallsLog.filter( + entry => entry.action === action + ).length + ) +) diff --git a/e2e-tests/production-runtime/cypress/support/index.js b/e2e-tests/production-runtime/cypress/support/index.js index 819e86d80e162..e1570cea495ef 100644 --- a/e2e-tests/production-runtime/cypress/support/index.js +++ b/e2e-tests/production-runtime/cypress/support/index.js @@ -16,6 +16,7 @@ // Import commands.js using ES2015 syntax: // TODO: import as "cypress-gatsby" once this is published to NPM import '../../../../packages/cypress-gatsby' +import './commands' // Alternatively you can use CommonJS syntax: // require('./commands') diff --git a/e2e-tests/production-runtime/gatsby-browser.js b/e2e-tests/production-runtime/gatsby-browser.js index b1e5c316b7f94..f81cf6249d3e9 100644 --- a/e2e-tests/production-runtime/gatsby-browser.js +++ b/e2e-tests/production-runtime/gatsby-browser.js @@ -1,7 +1,20 @@ -/** - * Implement Gatsby's Browser APIs in this file. - * - * See: https://www.gatsbyjs.org/docs/browser-apis/ - */ +if (typeof window !== `undefined`) { + window.___PageComponentLifecycleCallsLog = [] +} -// You can delete this file if you're not using it +const addLogEntry = (action, location) => { + const idElement = document.querySelector(`[data-testid="dom-marker"]`) + window.___PageComponentLifecycleCallsLog.push({ + action, + pathname: location.pathname, + domContent: idElement ? idElement.innerText : null, + }) +} + +exports.onPreRouteUpdate = ({ location }) => { + addLogEntry(`onPreRouteUpdate`, location) +} + +exports.onRouteUpdate = ({ location }) => { + addLogEntry(`onRouteUpdate`, location) +} diff --git a/e2e-tests/production-runtime/gatsby-node.js b/e2e-tests/production-runtime/gatsby-node.js index 2f4266513eb66..1b7aa08513b2e 100644 --- a/e2e-tests/production-runtime/gatsby-node.js +++ b/e2e-tests/production-runtime/gatsby-node.js @@ -1,7 +1,17 @@ -/** - * Implement Gatsby's Node APIs in this file. - * - * See: https://www.gatsbyjs.org/docs/node-apis/ - */ - -// You can delete this file if you're not using it +exports.onCreatePage = ({ page, actions }) => { + if (page.path === `/client-only-paths/`) { + // create client-only-paths + page.matchPath = `/client-only-paths/*` + actions.createPage(page) + } else if (page.path === `/`) { + // use index page as template + // (mimics) + actions.createPage({ + ...page, + path: `/duplicated`, + context: { + DOMMarker: `duplicated`, + }, + }) + } +} diff --git a/e2e-tests/production-runtime/src/pages/client-only-paths.js b/e2e-tests/production-runtime/src/pages/client-only-paths.js new file mode 100644 index 0000000000000..1a54ddca88921 --- /dev/null +++ b/e2e-tests/production-runtime/src/pages/client-only-paths.js @@ -0,0 +1,34 @@ +import React from 'react' +import { Router } from '@reach/router' +import { Link } from 'gatsby' + +import Layout from '../components/layout' +import InstrumentPage from '../utils/instrument-page' + +const Page = props => ( +
[client-only-path] {props.page}+) + +const routes = [`/`, `/profile`, `/dashboard`] + +const basePath = `/client-only-paths` + +const ClientOnlyPathPage = props => ( +
Welcome to your new Gatsby site.
-Now go build something great.
- - Go to page 2 - - - To non-existent page - - - To long page - +{pageContext.DOMMarker || `index`}+
Welcome to page 2
+page-2Go back to the homepage