diff --git a/integration-tests/production-runtime/cypress/integration/production.js b/integration-tests/production-runtime/cypress/integration/production.js index df7e9cd07bf25..72bd77a9e6608 100644 --- a/integration-tests/production-runtime/cypress/integration/production.js +++ b/integration-tests/production-runtime/cypress/integration/production.js @@ -5,9 +5,49 @@ describe(`Production build tests`, () => { cy.visit(`/`).waitForRouteChange() }) - it(`should navigate back after a reload`, () => { - cy.getTestElement(`page2`) + it(`should restore scroll position only when going back in history`, () => { + cy.getTestElement(`long-page`) + .click() + .waitForRouteChange() + + cy.scrollTo(`bottom`) + + // allow ScrollContext to update scroll position store + // it uses requestAnimationFrame so wait a bit to allow + // it to store scroll position + cy.wait(500) + + cy.getTestElement(`below-the-fold`) + .click() + .waitForRouteChange() + + // after going back we expect page will + // be restore previous scroll position + cy.go(`back`).waitForRouteChange() + + cy.window().then(win => { + expect(win.scrollY).not.to.eq(0, 0) + }) + + cy.go(`forward`).waitForRouteChange() + + // after clicking link we expect page will be scrolled to top + cy.getTestElement(`long-page`) + .click() + .waitForRouteChange() + + cy.window().then(win => { + expect(win.scrollY).to.eq(0, 0) + }) + + // reset to index page + cy.getTestElement(`index-link`) .click() + .waitForRouteChange() + }) + + it(`should navigate back after a reload`, () => { + cy.getTestElement(`page2`).click() cy.waitForRouteChange() .location(`pathname`) diff --git a/integration-tests/production-runtime/package.json b/integration-tests/production-runtime/package.json index 713d0898e11a9..3ebfcde1c3af5 100644 --- a/integration-tests/production-runtime/package.json +++ b/integration-tests/production-runtime/package.json @@ -5,10 +5,10 @@ "author": "Kyle Mathews ", "dependencies": { "cypress": "^3.1.0", - "gatsby": "next", - "gatsby-plugin-manifest": "next", - "gatsby-plugin-offline": "next", - "gatsby-plugin-react-helmet": "next", + "gatsby": "latest", + "gatsby-plugin-manifest": "latest", + "gatsby-plugin-offline": "latest", + "gatsby-plugin-react-helmet": "latest", "react": "^16.4.2", "react-dom": "^16.4.2", "react-helmet": "^5.2.0" diff --git a/integration-tests/production-runtime/src/components/header.js b/integration-tests/production-runtime/src/components/header.js index 0cbac259e50ea..6deeaad97e666 100644 --- a/integration-tests/production-runtime/src/components/header.js +++ b/integration-tests/production-runtime/src/components/header.js @@ -18,6 +18,7 @@ const Header = ({ siteTitle }) => ( >

(

Hi people

Welcome to your new Gatsby site.

Now go build something great.

- Go to page 2 - To non-existent page + + Go to page 2 + + + To non-existent page + + + To long page + ) diff --git a/integration-tests/production-runtime/src/pages/long-page.js b/integration-tests/production-runtime/src/pages/long-page.js new file mode 100644 index 0000000000000..ffeab9e8d8482 --- /dev/null +++ b/integration-tests/production-runtime/src/pages/long-page.js @@ -0,0 +1,17 @@ +import React from 'react' +import { Link } from 'gatsby' + +import Layout from '../components/layout' + +const LongPage = () => ( + +

Hi from the long page

+

Welcome to long page

+
+ + Go back to the homepage + + +) + +export default LongPage diff --git a/packages/gatsby/cache-dir/navigation.js b/packages/gatsby/cache-dir/navigation.js index 7de11909a2f0a..01e0ca3c4532e 100644 --- a/packages/gatsby/cache-dir/navigation.js +++ b/packages/gatsby/cache-dir/navigation.js @@ -1,3 +1,5 @@ +import React from "react" +import PropTypes from "prop-types" import loader, { setApiRunnerForLoader } from "./loader" import redirects from "./redirects.json" import { apiRunner } from "./api-runner-browser" @@ -139,4 +141,39 @@ function init() { maybeRedirect(window.location.pathname) } -export { init, shouldUpdateScroll, onRouteUpdate, onPreRouteUpdate } +// Fire on(Pre)RouteUpdate APIs +class RouteUpdates extends React.Component { + constructor(props) { + super(props) + onPreRouteUpdate(props.location) + } + + componentDidMount() { + onRouteUpdate(this.props.location) + } + + componentDidUpdate(prevProps, prevState, shouldFireRouteUpdate) { + if (shouldFireRouteUpdate) { + onRouteUpdate(this.props.location) + } + } + + getSnapshotBeforeUpdate(prevProps) { + if (this.props.location.pathname !== prevProps.location.pathname) { + onPreRouteUpdate(this.props.location) + return true + } + + return false + } + + render() { + return this.props.children + } +} + +RouteUpdates.propTypes = { + location: PropTypes.object.isRequired, +} + +export { init, shouldUpdateScroll, RouteUpdates } diff --git a/packages/gatsby/cache-dir/page-renderer.js b/packages/gatsby/cache-dir/page-renderer.js index 058bd2192f5f3..a8f500f66706c 100644 --- a/packages/gatsby/cache-dir/page-renderer.js +++ b/packages/gatsby/cache-dir/page-renderer.js @@ -2,41 +2,9 @@ import React, { createElement } from "react" import PropTypes from "prop-types" import { publicLoader } from "./loader" import { apiRunner } from "./api-runner-browser" -import { onRouteUpdate, onPreRouteUpdate } from "./navigation" -// Renders page and fire on(Pre)RouteUpdate APIs +// Renders page class PageRenderer extends React.Component { - constructor(props) { - super(props) - if (props.isMain) { - onPreRouteUpdate(props.location) - } - } - - componentDidMount() { - if (this.props.isMain) { - onRouteUpdate(this.props.location) - } - } - - componentDidUpdate(prevProps, prevState, shouldFireRouteUpdate) { - if (this.props.isMain && shouldFireRouteUpdate) { - onRouteUpdate(this.props.location) - } - } - - getSnapshotBeforeUpdate(prevProps, prevState) { - if (this.props.isMain) { - if (this.props.location.pathname !== prevProps.location.pathname) { - onPreRouteUpdate(this.props.location) - return true - } - - return false - } - return null - } - render() { const props = { ...this.props, @@ -73,7 +41,6 @@ PageRenderer.propTypes = { pageResources: PropTypes.object.isRequired, data: PropTypes.object, pageContext: PropTypes.object.isRequired, - isMain: PropTypes.bool, } export default PageRenderer diff --git a/packages/gatsby/cache-dir/production-app.js b/packages/gatsby/cache-dir/production-app.js index 55e31c6ad26d9..81b3ecafed1eb 100644 --- a/packages/gatsby/cache-dir/production-app.js +++ b/packages/gatsby/cache-dir/production-app.js @@ -5,7 +5,11 @@ import { Router, navigate } from "@reach/router" import { match } from "@reach/router/lib/utils" import { ScrollContext } from "gatsby-react-router-scroll" import domReady from "domready" -import { shouldUpdateScroll, init as navigationInit } from "./navigation" +import { + shouldUpdateScroll, + init as navigationInit, + RouteUpdates, +} from "./navigation" import emitter from "./emitter" window.___emitter = emitter import PageRenderer from "./page-renderer" @@ -43,22 +47,23 @@ apiRunnerAsync(`onClientEntry`).then(() => { // if not, add that. return ( - - - {({ pageResources, location }) => ( - + {({ pageResources, location }) => ( + + - )} - - + shouldUpdateScroll={shouldUpdateScroll} + > + + + + )} + ) } } diff --git a/packages/gatsby/cache-dir/root.js b/packages/gatsby/cache-dir/root.js index 6f2651fdeff26..404e93bad1517 100644 --- a/packages/gatsby/cache-dir/root.js +++ b/packages/gatsby/cache-dir/root.js @@ -1,7 +1,11 @@ import React, { createElement } from "react" import { Router } from "@reach/router" import { ScrollContext } from "gatsby-react-router-scroll" -import { shouldUpdateScroll, init as navigationInit } from "./navigation" +import { + shouldUpdateScroll, + init as navigationInit, + RouteUpdates, +} from "./navigation" import { apiRunner } from "./api-runner-browser" import syncRequires from "./sync-requires" import pages from "./pages.json" @@ -46,28 +50,33 @@ navigationInit() class RouteHandler extends React.Component { render() { let { location } = this.props - let child // check if page exists - in dev pages are sync loaded, it's safe to use // loader.getPage let page = loader.getPage(location.pathname) if (page) { - child = ( + return ( {locationAndPageResources => ( - + + + + + )} ) } else { const dev404Page = pages.find(p => /^\/dev-404-page\/$/.test(p.path)) - child = createElement( + return createElement( syncRequires.components[dev404Page.componentChunkName], { pages, @@ -75,16 +84,6 @@ class RouteHandler extends React.Component { } ) } - - return ( - - {child} - - ) } }