From 1db361c4142a8c5d9ca62f8017120f0457a2ef10 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Sat, 23 Sep 2023 23:55:08 +0200 Subject: [PATCH] Move client-navigation test to test/development --- .../fixture}/components/hello.jsx | 0 .../fixture}/components/hello1.js | 0 .../fixture}/components/world.jsx | 0 .../fixture}/lib/async-function.js | 0 .../client-navigation/fixture}/lib/cdm.js | 0 .../fixture}/lib/colored-blue.js | 0 .../client-navigation/fixture}/lib/data.json | 0 .../client-navigation/fixture}/next.config.js | 0 .../fixture}/pages/_document.js | 0 .../fixture}/pages/absolute-url.js | 0 .../fixture}/pages/async-props.js | 0 .../fixture}/pages/circular-json-error.js | 0 .../fixture}/pages/custom-encoding.js | 0 .../fixture}/pages/custom-extension.jsx | 0 .../fixture}/pages/default-head.js | 0 .../fixture}/pages/dynamic/[slug]/route.js | 0 .../fixture}/pages/dynamic/ssr.js | 0 .../fixture}/pages/empty-get-initial-props.js | 0 .../error-in-the-browser-global-scope.js | 0 .../pages/error-in-the-global-scope.js | 0 .../pages/error-inside-browser-page.js | 0 .../fixture}/pages/error-inside-page.js | 0 .../fixture}/pages/exports.js | 0 .../fixture}/pages/forwardRef-component.js | 0 .../fixture}/pages/fragment-syntax.js | 0 .../pages/head-duplicate-default-keys.js | 0 .../fixture}/pages/head-dynamic.js | 0 .../fixture}/pages/head-priority.js | 0 .../pages/head-with-json-ld-snippet.js | 0 .../client-navigation/fixture}/pages/head.js | 0 .../client-navigation/fixture}/pages/index.js | 0 .../pages/instance-get-initial-props.js | 0 .../client-navigation/fixture}/pages/json.js | 0 .../fixture}/pages/link-invalid-onclick.js | 0 .../fixture}/pages/link-no-child.js | 0 .../fixture}/pages/link-number-child.js | 0 .../client-navigation/fixture}/pages/link.js | 0 .../fixture}/pages/memo-component.js | 0 .../fixture}/pages/nav/about.js | 0 .../fixture}/pages/nav/as-path-pushstate.js | 0 .../fixture}/pages/nav/as-path-query.js | 0 .../pages/nav/as-path-using-router.js | 0 .../fixture}/pages/nav/as-path.js | 0 .../pages/nav/hash-changes-with-state.js | 0 .../fixture}/pages/nav/hash-changes.js | 0 .../fixture}/pages/nav/head-1.js | 0 .../fixture}/pages/nav/head-2.js | 0 .../fixture}/pages/nav/head-3.js | 0 .../fixture}/pages/nav/index.js | 0 .../pages/nav/long-page-to-snap-scroll.js | 0 .../fixture}/pages/nav/on-click.js | 0 .../fixture}/pages/nav/pass-href-prop.js | 0 .../fixture}/pages/nav/query-only.js | 0 .../fixture}/pages/nav/query-params.js | 0 .../fixture}/pages/nav/querystring.js | 0 .../fixture}/pages/nav/redirect.js | 0 .../fixture}/pages/nav/relative-1.js | 0 .../fixture}/pages/nav/relative-2.js | 0 .../fixture}/pages/nav/relative/index.js | 0 .../fixture}/pages/nav/self-reload.js | 0 .../fixture}/pages/nav/shallow-routing.js | 0 .../fixture}/pages/nav/with-hoc.js | 0 .../fixture}/pages/nested-cdm/index.js | 0 .../pages/nested-index/index/index.js | 0 .../fixture}/pages/no-default-export.js | 0 .../client-navigation/fixture}/pages/query.js | 0 .../fixture}/pages/read-only-object-error.js | 0 .../fixture}/pages/snap-scroll-position.js | 0 .../fixture}/pages/stateless.js | 0 .../fixture}/pages/styled-jsx-external.js | 0 .../fixture}/pages/styled-jsx.js | 0 .../fixture}/pages/throw-undefined.js | 0 .../fixture}/pages/with-cdm.js | 0 .../fixture}/public/test-async.js | 0 .../fixture}/public/test-defer.js | 0 .../pages-dir/client-navigation/index.test.ts | 1810 +++++++++++++++++ .../pages-dir/client-navigation/rendering.ts} | 21 +- .../client-navigation/test/index.test.js | 1799 ---------------- tsconfig.json | 4 +- 79 files changed, 1822 insertions(+), 1812 deletions(-) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/components/hello.jsx (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/components/hello1.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/components/world.jsx (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/lib/async-function.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/lib/cdm.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/lib/colored-blue.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/lib/data.json (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/next.config.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/_document.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/absolute-url.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/async-props.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/circular-json-error.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/custom-encoding.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/custom-extension.jsx (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/default-head.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/dynamic/[slug]/route.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/dynamic/ssr.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/empty-get-initial-props.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/error-in-the-browser-global-scope.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/error-in-the-global-scope.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/error-inside-browser-page.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/error-inside-page.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/exports.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/forwardRef-component.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/fragment-syntax.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/head-duplicate-default-keys.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/head-dynamic.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/head-priority.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/head-with-json-ld-snippet.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/head.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/index.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/instance-get-initial-props.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/json.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/link-invalid-onclick.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/link-no-child.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/link-number-child.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/link.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/memo-component.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/about.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/as-path-pushstate.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/as-path-query.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/as-path-using-router.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/as-path.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/hash-changes-with-state.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/hash-changes.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/head-1.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/head-2.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/head-3.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/index.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/long-page-to-snap-scroll.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/on-click.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/pass-href-prop.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/query-only.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/query-params.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/querystring.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/redirect.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/relative-1.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/relative-2.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/relative/index.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/self-reload.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/shallow-routing.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nav/with-hoc.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nested-cdm/index.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/nested-index/index/index.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/no-default-export.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/query.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/read-only-object-error.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/snap-scroll-position.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/stateless.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/styled-jsx-external.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/styled-jsx.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/throw-undefined.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/pages/with-cdm.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/public/test-async.js (100%) rename test/{integration/client-navigation => development/pages-dir/client-navigation/fixture}/public/test-defer.js (100%) create mode 100644 test/development/pages-dir/client-navigation/index.test.ts rename test/{integration/client-navigation/test/rendering.js => development/pages-dir/client-navigation/rendering.ts} (97%) delete mode 100644 test/integration/client-navigation/test/index.test.js diff --git a/test/integration/client-navigation/components/hello.jsx b/test/development/pages-dir/client-navigation/fixture/components/hello.jsx similarity index 100% rename from test/integration/client-navigation/components/hello.jsx rename to test/development/pages-dir/client-navigation/fixture/components/hello.jsx diff --git a/test/integration/client-navigation/components/hello1.js b/test/development/pages-dir/client-navigation/fixture/components/hello1.js similarity index 100% rename from test/integration/client-navigation/components/hello1.js rename to test/development/pages-dir/client-navigation/fixture/components/hello1.js diff --git a/test/integration/client-navigation/components/world.jsx b/test/development/pages-dir/client-navigation/fixture/components/world.jsx similarity index 100% rename from test/integration/client-navigation/components/world.jsx rename to test/development/pages-dir/client-navigation/fixture/components/world.jsx diff --git a/test/integration/client-navigation/lib/async-function.js b/test/development/pages-dir/client-navigation/fixture/lib/async-function.js similarity index 100% rename from test/integration/client-navigation/lib/async-function.js rename to test/development/pages-dir/client-navigation/fixture/lib/async-function.js diff --git a/test/integration/client-navigation/lib/cdm.js b/test/development/pages-dir/client-navigation/fixture/lib/cdm.js similarity index 100% rename from test/integration/client-navigation/lib/cdm.js rename to test/development/pages-dir/client-navigation/fixture/lib/cdm.js diff --git a/test/integration/client-navigation/lib/colored-blue.js b/test/development/pages-dir/client-navigation/fixture/lib/colored-blue.js similarity index 100% rename from test/integration/client-navigation/lib/colored-blue.js rename to test/development/pages-dir/client-navigation/fixture/lib/colored-blue.js diff --git a/test/integration/client-navigation/lib/data.json b/test/development/pages-dir/client-navigation/fixture/lib/data.json similarity index 100% rename from test/integration/client-navigation/lib/data.json rename to test/development/pages-dir/client-navigation/fixture/lib/data.json diff --git a/test/integration/client-navigation/next.config.js b/test/development/pages-dir/client-navigation/fixture/next.config.js similarity index 100% rename from test/integration/client-navigation/next.config.js rename to test/development/pages-dir/client-navigation/fixture/next.config.js diff --git a/test/integration/client-navigation/pages/_document.js b/test/development/pages-dir/client-navigation/fixture/pages/_document.js similarity index 100% rename from test/integration/client-navigation/pages/_document.js rename to test/development/pages-dir/client-navigation/fixture/pages/_document.js diff --git a/test/integration/client-navigation/pages/absolute-url.js b/test/development/pages-dir/client-navigation/fixture/pages/absolute-url.js similarity index 100% rename from test/integration/client-navigation/pages/absolute-url.js rename to test/development/pages-dir/client-navigation/fixture/pages/absolute-url.js diff --git a/test/integration/client-navigation/pages/async-props.js b/test/development/pages-dir/client-navigation/fixture/pages/async-props.js similarity index 100% rename from test/integration/client-navigation/pages/async-props.js rename to test/development/pages-dir/client-navigation/fixture/pages/async-props.js diff --git a/test/integration/client-navigation/pages/circular-json-error.js b/test/development/pages-dir/client-navigation/fixture/pages/circular-json-error.js similarity index 100% rename from test/integration/client-navigation/pages/circular-json-error.js rename to test/development/pages-dir/client-navigation/fixture/pages/circular-json-error.js diff --git a/test/integration/client-navigation/pages/custom-encoding.js b/test/development/pages-dir/client-navigation/fixture/pages/custom-encoding.js similarity index 100% rename from test/integration/client-navigation/pages/custom-encoding.js rename to test/development/pages-dir/client-navigation/fixture/pages/custom-encoding.js diff --git a/test/integration/client-navigation/pages/custom-extension.jsx b/test/development/pages-dir/client-navigation/fixture/pages/custom-extension.jsx similarity index 100% rename from test/integration/client-navigation/pages/custom-extension.jsx rename to test/development/pages-dir/client-navigation/fixture/pages/custom-extension.jsx diff --git a/test/integration/client-navigation/pages/default-head.js b/test/development/pages-dir/client-navigation/fixture/pages/default-head.js similarity index 100% rename from test/integration/client-navigation/pages/default-head.js rename to test/development/pages-dir/client-navigation/fixture/pages/default-head.js diff --git a/test/integration/client-navigation/pages/dynamic/[slug]/route.js b/test/development/pages-dir/client-navigation/fixture/pages/dynamic/[slug]/route.js similarity index 100% rename from test/integration/client-navigation/pages/dynamic/[slug]/route.js rename to test/development/pages-dir/client-navigation/fixture/pages/dynamic/[slug]/route.js diff --git a/test/integration/client-navigation/pages/dynamic/ssr.js b/test/development/pages-dir/client-navigation/fixture/pages/dynamic/ssr.js similarity index 100% rename from test/integration/client-navigation/pages/dynamic/ssr.js rename to test/development/pages-dir/client-navigation/fixture/pages/dynamic/ssr.js diff --git a/test/integration/client-navigation/pages/empty-get-initial-props.js b/test/development/pages-dir/client-navigation/fixture/pages/empty-get-initial-props.js similarity index 100% rename from test/integration/client-navigation/pages/empty-get-initial-props.js rename to test/development/pages-dir/client-navigation/fixture/pages/empty-get-initial-props.js diff --git a/test/integration/client-navigation/pages/error-in-the-browser-global-scope.js b/test/development/pages-dir/client-navigation/fixture/pages/error-in-the-browser-global-scope.js similarity index 100% rename from test/integration/client-navigation/pages/error-in-the-browser-global-scope.js rename to test/development/pages-dir/client-navigation/fixture/pages/error-in-the-browser-global-scope.js diff --git a/test/integration/client-navigation/pages/error-in-the-global-scope.js b/test/development/pages-dir/client-navigation/fixture/pages/error-in-the-global-scope.js similarity index 100% rename from test/integration/client-navigation/pages/error-in-the-global-scope.js rename to test/development/pages-dir/client-navigation/fixture/pages/error-in-the-global-scope.js diff --git a/test/integration/client-navigation/pages/error-inside-browser-page.js b/test/development/pages-dir/client-navigation/fixture/pages/error-inside-browser-page.js similarity index 100% rename from test/integration/client-navigation/pages/error-inside-browser-page.js rename to test/development/pages-dir/client-navigation/fixture/pages/error-inside-browser-page.js diff --git a/test/integration/client-navigation/pages/error-inside-page.js b/test/development/pages-dir/client-navigation/fixture/pages/error-inside-page.js similarity index 100% rename from test/integration/client-navigation/pages/error-inside-page.js rename to test/development/pages-dir/client-navigation/fixture/pages/error-inside-page.js diff --git a/test/integration/client-navigation/pages/exports.js b/test/development/pages-dir/client-navigation/fixture/pages/exports.js similarity index 100% rename from test/integration/client-navigation/pages/exports.js rename to test/development/pages-dir/client-navigation/fixture/pages/exports.js diff --git a/test/integration/client-navigation/pages/forwardRef-component.js b/test/development/pages-dir/client-navigation/fixture/pages/forwardRef-component.js similarity index 100% rename from test/integration/client-navigation/pages/forwardRef-component.js rename to test/development/pages-dir/client-navigation/fixture/pages/forwardRef-component.js diff --git a/test/integration/client-navigation/pages/fragment-syntax.js b/test/development/pages-dir/client-navigation/fixture/pages/fragment-syntax.js similarity index 100% rename from test/integration/client-navigation/pages/fragment-syntax.js rename to test/development/pages-dir/client-navigation/fixture/pages/fragment-syntax.js diff --git a/test/integration/client-navigation/pages/head-duplicate-default-keys.js b/test/development/pages-dir/client-navigation/fixture/pages/head-duplicate-default-keys.js similarity index 100% rename from test/integration/client-navigation/pages/head-duplicate-default-keys.js rename to test/development/pages-dir/client-navigation/fixture/pages/head-duplicate-default-keys.js diff --git a/test/integration/client-navigation/pages/head-dynamic.js b/test/development/pages-dir/client-navigation/fixture/pages/head-dynamic.js similarity index 100% rename from test/integration/client-navigation/pages/head-dynamic.js rename to test/development/pages-dir/client-navigation/fixture/pages/head-dynamic.js diff --git a/test/integration/client-navigation/pages/head-priority.js b/test/development/pages-dir/client-navigation/fixture/pages/head-priority.js similarity index 100% rename from test/integration/client-navigation/pages/head-priority.js rename to test/development/pages-dir/client-navigation/fixture/pages/head-priority.js diff --git a/test/integration/client-navigation/pages/head-with-json-ld-snippet.js b/test/development/pages-dir/client-navigation/fixture/pages/head-with-json-ld-snippet.js similarity index 100% rename from test/integration/client-navigation/pages/head-with-json-ld-snippet.js rename to test/development/pages-dir/client-navigation/fixture/pages/head-with-json-ld-snippet.js diff --git a/test/integration/client-navigation/pages/head.js b/test/development/pages-dir/client-navigation/fixture/pages/head.js similarity index 100% rename from test/integration/client-navigation/pages/head.js rename to test/development/pages-dir/client-navigation/fixture/pages/head.js diff --git a/test/integration/client-navigation/pages/index.js b/test/development/pages-dir/client-navigation/fixture/pages/index.js similarity index 100% rename from test/integration/client-navigation/pages/index.js rename to test/development/pages-dir/client-navigation/fixture/pages/index.js diff --git a/test/integration/client-navigation/pages/instance-get-initial-props.js b/test/development/pages-dir/client-navigation/fixture/pages/instance-get-initial-props.js similarity index 100% rename from test/integration/client-navigation/pages/instance-get-initial-props.js rename to test/development/pages-dir/client-navigation/fixture/pages/instance-get-initial-props.js diff --git a/test/integration/client-navigation/pages/json.js b/test/development/pages-dir/client-navigation/fixture/pages/json.js similarity index 100% rename from test/integration/client-navigation/pages/json.js rename to test/development/pages-dir/client-navigation/fixture/pages/json.js diff --git a/test/integration/client-navigation/pages/link-invalid-onclick.js b/test/development/pages-dir/client-navigation/fixture/pages/link-invalid-onclick.js similarity index 100% rename from test/integration/client-navigation/pages/link-invalid-onclick.js rename to test/development/pages-dir/client-navigation/fixture/pages/link-invalid-onclick.js diff --git a/test/integration/client-navigation/pages/link-no-child.js b/test/development/pages-dir/client-navigation/fixture/pages/link-no-child.js similarity index 100% rename from test/integration/client-navigation/pages/link-no-child.js rename to test/development/pages-dir/client-navigation/fixture/pages/link-no-child.js diff --git a/test/integration/client-navigation/pages/link-number-child.js b/test/development/pages-dir/client-navigation/fixture/pages/link-number-child.js similarity index 100% rename from test/integration/client-navigation/pages/link-number-child.js rename to test/development/pages-dir/client-navigation/fixture/pages/link-number-child.js diff --git a/test/integration/client-navigation/pages/link.js b/test/development/pages-dir/client-navigation/fixture/pages/link.js similarity index 100% rename from test/integration/client-navigation/pages/link.js rename to test/development/pages-dir/client-navigation/fixture/pages/link.js diff --git a/test/integration/client-navigation/pages/memo-component.js b/test/development/pages-dir/client-navigation/fixture/pages/memo-component.js similarity index 100% rename from test/integration/client-navigation/pages/memo-component.js rename to test/development/pages-dir/client-navigation/fixture/pages/memo-component.js diff --git a/test/integration/client-navigation/pages/nav/about.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/about.js similarity index 100% rename from test/integration/client-navigation/pages/nav/about.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/about.js diff --git a/test/integration/client-navigation/pages/nav/as-path-pushstate.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/as-path-pushstate.js similarity index 100% rename from test/integration/client-navigation/pages/nav/as-path-pushstate.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/as-path-pushstate.js diff --git a/test/integration/client-navigation/pages/nav/as-path-query.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/as-path-query.js similarity index 100% rename from test/integration/client-navigation/pages/nav/as-path-query.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/as-path-query.js diff --git a/test/integration/client-navigation/pages/nav/as-path-using-router.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/as-path-using-router.js similarity index 100% rename from test/integration/client-navigation/pages/nav/as-path-using-router.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/as-path-using-router.js diff --git a/test/integration/client-navigation/pages/nav/as-path.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/as-path.js similarity index 100% rename from test/integration/client-navigation/pages/nav/as-path.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/as-path.js diff --git a/test/integration/client-navigation/pages/nav/hash-changes-with-state.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/hash-changes-with-state.js similarity index 100% rename from test/integration/client-navigation/pages/nav/hash-changes-with-state.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/hash-changes-with-state.js diff --git a/test/integration/client-navigation/pages/nav/hash-changes.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/hash-changes.js similarity index 100% rename from test/integration/client-navigation/pages/nav/hash-changes.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/hash-changes.js diff --git a/test/integration/client-navigation/pages/nav/head-1.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/head-1.js similarity index 100% rename from test/integration/client-navigation/pages/nav/head-1.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/head-1.js diff --git a/test/integration/client-navigation/pages/nav/head-2.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/head-2.js similarity index 100% rename from test/integration/client-navigation/pages/nav/head-2.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/head-2.js diff --git a/test/integration/client-navigation/pages/nav/head-3.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/head-3.js similarity index 100% rename from test/integration/client-navigation/pages/nav/head-3.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/head-3.js diff --git a/test/integration/client-navigation/pages/nav/index.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/index.js similarity index 100% rename from test/integration/client-navigation/pages/nav/index.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/index.js diff --git a/test/integration/client-navigation/pages/nav/long-page-to-snap-scroll.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/long-page-to-snap-scroll.js similarity index 100% rename from test/integration/client-navigation/pages/nav/long-page-to-snap-scroll.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/long-page-to-snap-scroll.js diff --git a/test/integration/client-navigation/pages/nav/on-click.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/on-click.js similarity index 100% rename from test/integration/client-navigation/pages/nav/on-click.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/on-click.js diff --git a/test/integration/client-navigation/pages/nav/pass-href-prop.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/pass-href-prop.js similarity index 100% rename from test/integration/client-navigation/pages/nav/pass-href-prop.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/pass-href-prop.js diff --git a/test/integration/client-navigation/pages/nav/query-only.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/query-only.js similarity index 100% rename from test/integration/client-navigation/pages/nav/query-only.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/query-only.js diff --git a/test/integration/client-navigation/pages/nav/query-params.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/query-params.js similarity index 100% rename from test/integration/client-navigation/pages/nav/query-params.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/query-params.js diff --git a/test/integration/client-navigation/pages/nav/querystring.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/querystring.js similarity index 100% rename from test/integration/client-navigation/pages/nav/querystring.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/querystring.js diff --git a/test/integration/client-navigation/pages/nav/redirect.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/redirect.js similarity index 100% rename from test/integration/client-navigation/pages/nav/redirect.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/redirect.js diff --git a/test/integration/client-navigation/pages/nav/relative-1.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/relative-1.js similarity index 100% rename from test/integration/client-navigation/pages/nav/relative-1.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/relative-1.js diff --git a/test/integration/client-navigation/pages/nav/relative-2.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/relative-2.js similarity index 100% rename from test/integration/client-navigation/pages/nav/relative-2.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/relative-2.js diff --git a/test/integration/client-navigation/pages/nav/relative/index.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/relative/index.js similarity index 100% rename from test/integration/client-navigation/pages/nav/relative/index.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/relative/index.js diff --git a/test/integration/client-navigation/pages/nav/self-reload.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/self-reload.js similarity index 100% rename from test/integration/client-navigation/pages/nav/self-reload.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/self-reload.js diff --git a/test/integration/client-navigation/pages/nav/shallow-routing.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/shallow-routing.js similarity index 100% rename from test/integration/client-navigation/pages/nav/shallow-routing.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/shallow-routing.js diff --git a/test/integration/client-navigation/pages/nav/with-hoc.js b/test/development/pages-dir/client-navigation/fixture/pages/nav/with-hoc.js similarity index 100% rename from test/integration/client-navigation/pages/nav/with-hoc.js rename to test/development/pages-dir/client-navigation/fixture/pages/nav/with-hoc.js diff --git a/test/integration/client-navigation/pages/nested-cdm/index.js b/test/development/pages-dir/client-navigation/fixture/pages/nested-cdm/index.js similarity index 100% rename from test/integration/client-navigation/pages/nested-cdm/index.js rename to test/development/pages-dir/client-navigation/fixture/pages/nested-cdm/index.js diff --git a/test/integration/client-navigation/pages/nested-index/index/index.js b/test/development/pages-dir/client-navigation/fixture/pages/nested-index/index/index.js similarity index 100% rename from test/integration/client-navigation/pages/nested-index/index/index.js rename to test/development/pages-dir/client-navigation/fixture/pages/nested-index/index/index.js diff --git a/test/integration/client-navigation/pages/no-default-export.js b/test/development/pages-dir/client-navigation/fixture/pages/no-default-export.js similarity index 100% rename from test/integration/client-navigation/pages/no-default-export.js rename to test/development/pages-dir/client-navigation/fixture/pages/no-default-export.js diff --git a/test/integration/client-navigation/pages/query.js b/test/development/pages-dir/client-navigation/fixture/pages/query.js similarity index 100% rename from test/integration/client-navigation/pages/query.js rename to test/development/pages-dir/client-navigation/fixture/pages/query.js diff --git a/test/integration/client-navigation/pages/read-only-object-error.js b/test/development/pages-dir/client-navigation/fixture/pages/read-only-object-error.js similarity index 100% rename from test/integration/client-navigation/pages/read-only-object-error.js rename to test/development/pages-dir/client-navigation/fixture/pages/read-only-object-error.js diff --git a/test/integration/client-navigation/pages/snap-scroll-position.js b/test/development/pages-dir/client-navigation/fixture/pages/snap-scroll-position.js similarity index 100% rename from test/integration/client-navigation/pages/snap-scroll-position.js rename to test/development/pages-dir/client-navigation/fixture/pages/snap-scroll-position.js diff --git a/test/integration/client-navigation/pages/stateless.js b/test/development/pages-dir/client-navigation/fixture/pages/stateless.js similarity index 100% rename from test/integration/client-navigation/pages/stateless.js rename to test/development/pages-dir/client-navigation/fixture/pages/stateless.js diff --git a/test/integration/client-navigation/pages/styled-jsx-external.js b/test/development/pages-dir/client-navigation/fixture/pages/styled-jsx-external.js similarity index 100% rename from test/integration/client-navigation/pages/styled-jsx-external.js rename to test/development/pages-dir/client-navigation/fixture/pages/styled-jsx-external.js diff --git a/test/integration/client-navigation/pages/styled-jsx.js b/test/development/pages-dir/client-navigation/fixture/pages/styled-jsx.js similarity index 100% rename from test/integration/client-navigation/pages/styled-jsx.js rename to test/development/pages-dir/client-navigation/fixture/pages/styled-jsx.js diff --git a/test/integration/client-navigation/pages/throw-undefined.js b/test/development/pages-dir/client-navigation/fixture/pages/throw-undefined.js similarity index 100% rename from test/integration/client-navigation/pages/throw-undefined.js rename to test/development/pages-dir/client-navigation/fixture/pages/throw-undefined.js diff --git a/test/integration/client-navigation/pages/with-cdm.js b/test/development/pages-dir/client-navigation/fixture/pages/with-cdm.js similarity index 100% rename from test/integration/client-navigation/pages/with-cdm.js rename to test/development/pages-dir/client-navigation/fixture/pages/with-cdm.js diff --git a/test/integration/client-navigation/public/test-async.js b/test/development/pages-dir/client-navigation/fixture/public/test-async.js similarity index 100% rename from test/integration/client-navigation/public/test-async.js rename to test/development/pages-dir/client-navigation/fixture/public/test-async.js diff --git a/test/integration/client-navigation/public/test-defer.js b/test/development/pages-dir/client-navigation/fixture/public/test-defer.js similarity index 100% rename from test/integration/client-navigation/public/test-defer.js rename to test/development/pages-dir/client-navigation/fixture/public/test-defer.js diff --git a/test/development/pages-dir/client-navigation/index.test.ts b/test/development/pages-dir/client-navigation/index.test.ts new file mode 100644 index 0000000000000..63544dbfc2539 --- /dev/null +++ b/test/development/pages-dir/client-navigation/index.test.ts @@ -0,0 +1,1810 @@ +/* eslint-env jest */ + +import { + fetchViaHTTP, + getRedboxSource, + hasRedbox, + getRedboxHeader, + renderViaHTTP, + waitFor, + check, +} from 'next-test-utils' +import webdriver from 'next-webdriver' +import path from 'path' +import renderingSuite from './rendering' +import { createNextDescribe } from 'e2e-utils' + +createNextDescribe( + 'Client Navigation', + { + files: path.join(__dirname, 'fixture'), + }, + ({ next }) => { + it('should not reload when visiting /_error directly', async () => { + const { status } = await fetchViaHTTP(next.appPort, '/_error') + const browser = await webdriver(next.appPort, '/_error') + + await browser.eval('window.hello = true') + + // wait on-demand-entries timeout since it can trigger + // reloading non-stop + for (let i = 0; i < 15; i++) { + expect(await browser.eval('window.hello')).toBe(true) + await waitFor(1000) + } + const html = await browser.eval('document.documentElement.innerHTML') + + expect(status).toBe(404) + expect(html).toContain('This page could not be found') + expect(html).toContain('404') + }) + + describe('with ', () => { + it('should navigate the page', async () => { + const browser = await webdriver(next.appPort, '/nav') + const text = await browser + .elementByCss('#about-link') + .click() + .waitForElementByCss('.nav-about') + .elementByCss('p') + .text() + + expect(text).toBe('This is the about page.') + await browser.close() + }) + + it('should have proper error when no children are provided', async () => { + const browser = await webdriver(next.appPort, '/link-no-child') + expect(await hasRedbox(browser, true)).toBe(true) + expect(await getRedboxHeader(browser)).toContain( + 'No children were passed to with `href` of `/about` but one child is required' + ) + }) + + it('should not throw error when one number type child is provided', async () => { + const browser = await webdriver(next.appPort, '/link-number-child') + expect(await hasRedbox(browser, false)).toBe(false) + if (browser) await browser.close() + }) + + it('should navigate back after reload', async () => { + const browser = await webdriver(next.appPort, '/nav') + await browser.elementByCss('#about-link').click() + await browser.waitForElementByCss('.nav-about') + await browser.refresh() + await waitFor(3000) + await browser.back() + await waitFor(3000) + const text = await browser.elementByCss('#about-link').text() + if (browser) await browser.close() + expect(text).toMatch(/About/) + }) + + it('should navigate forwards after reload', async () => { + const browser = await webdriver(next.appPort, '/nav') + await browser.elementByCss('#about-link').click() + await browser.waitForElementByCss('.nav-about') + await browser.back() + await browser.refresh() + await waitFor(3000) + await browser.forward() + await waitFor(3000) + const text = await browser.elementByCss('p').text() + if (browser) await browser.close() + expect(text).toMatch(/this is the about page/i) + }) + + it('should error when calling onClick without event', async () => { + const browser = await webdriver(next.appPort, '/link-invalid-onclick') + expect(await browser.elementByCss('#errors').text()).toBe('0') + await browser.elementByCss('#custom-button').click() + expect(await browser.elementByCss('#errors').text()).toBe('1') + }) + + it('should navigate via the client side', async () => { + const browser = await webdriver(next.appPort, '/nav') + + const counterText = await browser + .elementByCss('#increase') + .click() + .elementByCss('#about-link') + .click() + .waitForElementByCss('.nav-about') + .elementByCss('#home-link') + .click() + .waitForElementByCss('.nav-home') + .elementByCss('#counter') + .text() + + expect(counterText).toBe('Counter: 1') + await browser.close() + }) + + it('should navigate an absolute url', async () => { + const browser = await webdriver( + next.appPort, + `/absolute-url?port=${next.appPort}` + ) + await browser.waitForElementByCss('#absolute-link').click() + await check( + () => browser.eval(() => window.location.origin), + 'https://vercel.com' + ) + }) + + it('should call mouse handlers with an absolute url', async () => { + const browser = await webdriver( + next.appPort, + `/absolute-url?port=${next.appPort}` + ) + + await browser.elementByCss('#absolute-link-mouse-events').moveTo() + + expect( + await browser + .waitForElementByCss('#absolute-link-mouse-events') + .getAttribute('data-hover') + ).toBe('true') + }) + + it('should navigate an absolute local url', async () => { + const browser = await webdriver( + next.appPort, + `/absolute-url?port=${next.appPort}` + ) + // @ts-expect-error _didNotNavigate is set intentionally + await browser.eval(() => (window._didNotNavigate = true)) + await browser.waitForElementByCss('#absolute-local-link').click() + const text = await browser + .waitForElementByCss('.nav-about') + .elementByCss('p') + .text() + + expect(text).toBe('This is the about page.') + // @ts-expect-error _didNotNavigate is set intentionally + expect(await browser.eval(() => window._didNotNavigate)).toBe(true) + }) + + it('should navigate an absolute local url with as', async () => { + const browser = await webdriver( + next.appPort, + `/absolute-url?port=${next.appPort}` + ) + // @ts-expect-error _didNotNavigate is set intentionally + await browser.eval(() => (window._didNotNavigate = true)) + await browser + .waitForElementByCss('#absolute-local-dynamic-link') + .click() + expect(await browser.waitForElementByCss('#dynamic-page').text()).toBe( + 'hello' + ) + // @ts-expect-error _didNotNavigate is set intentionally + expect(await browser.eval(() => window._didNotNavigate)).toBe(true) + }) + }) + + describe('with tag inside the ', () => { + it('should navigate the page', async () => { + const browser = await webdriver(next.appPort, '/nav/about') + const text = await browser + .elementByCss('#home-link') + .click() + .waitForElementByCss('.nav-home') + .elementByCss('p') + .text() + + expect(text).toBe('This is the home.') + await browser.close() + }) + + it('should not navigate if the tag has a target', async () => { + const browser = await webdriver(next.appPort, '/nav') + + await browser + .elementByCss('#increase') + .click() + .elementByCss('#target-link') + .click() + + await waitFor(1000) + + const counterText = await browser.elementByCss('#counter').text() + + expect(counterText).toBe('Counter: 1') + await browser.close() + }) + + it('should not navigate if the click-event is modified', async () => { + const browser = await webdriver(next.appPort, '/nav') + + await browser.elementByCss('#increase').click() + + const key = process.platform === 'darwin' ? 'Meta' : 'Control' + + await browser.keydown(key) + + await browser.elementByCss('#in-svg-link').click() + + await browser.keyup(key) + await waitFor(1000) + + const counterText = await browser.elementByCss('#counter').text() + + expect(counterText).toBe('Counter: 1') + await browser.close() + }) + + it('should not reload when link in svg is clicked', async () => { + const browser = await webdriver(next.appPort, '/nav') + await browser.eval('window.hello = true') + await browser + .elementByCss('#in-svg-link') + .click() + .waitForElementByCss('.nav-about') + + expect(await browser.eval('window.hello')).toBe(true) + await browser.close() + }) + }) + + describe('with unexpected nested tag', () => { + it('should not redirect if passHref prop is not defined in Link', async () => { + const browser = await webdriver(next.appPort, '/nav/pass-href-prop') + const text = await browser + .elementByCss('#without-href') + .click() + .waitForElementByCss('.nav-pass-href-prop') + .elementByCss('p') + .text() + + expect(text).toBe('This is the passHref prop page.') + await browser.close() + }) + + it('should redirect if passHref prop is defined in Link', async () => { + const browser = await webdriver(next.appPort, '/nav/pass-href-prop') + const text = await browser + .elementByCss('#with-href') + .click() + .waitForElementByCss('.nav-home') + .elementByCss('p') + .text() + + expect(text).toBe('This is the home.') + await browser.close() + }) + }) + + describe('with empty getInitialProps()', () => { + it('should render an error', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/nav') + await browser.elementByCss('#empty-props').click() + expect(await hasRedbox(browser, true)).toBe(true) + expect(await getRedboxHeader(browser)).toMatch( + /should resolve to an object\. But found "null" instead\./ + ) + } finally { + if (browser) { + await browser.close() + } + } + }) + }) + + describe('with the same page but different querystring', () => { + it('should navigate the page', async () => { + const browser = await webdriver(next.appPort, '/nav/querystring?id=1') + const text = await browser + .elementByCss('#next-id-link') + .click() + .waitForElementByCss('.nav-id-2') + .elementByCss('p') + .text() + + expect(text).toBe('2') + await browser.close() + }) + + it('should remove querystring', async () => { + const browser = await webdriver(next.appPort, '/nav/querystring?id=1') + const text = await browser + .elementByCss('#main-page') + .click() + .waitForElementByCss('.nav-id-0') + .elementByCss('p') + .text() + + expect(text).toBe('0') + await browser.close() + }) + }) + + describe('with the current url', () => { + it('should reload the page', async () => { + const browser = await webdriver(next.appPort, '/nav/self-reload') + const defaultCount = await browser.elementByCss('p').text() + expect(defaultCount).toBe('COUNT: 0') + + const countAfterClicked = await browser + .elementByCss('#self-reload-link') + .click() + .elementByCss('p') + .text() + + expect(countAfterClicked).toBe('COUNT: 1') + await browser.close() + }) + + it('should always replace the state', async () => { + const browser = await webdriver(next.appPort, '/nav') + + const countAfterClicked = await browser + .elementByCss('#self-reload-link') + .click() + .waitForElementByCss('#self-reload-page') + .elementByCss('#self-reload-link') + .click() + .elementByCss('#self-reload-link') + .click() + .elementByCss('p') + .text() + + // counts (page change + two clicks) + expect(countAfterClicked).toBe('COUNT: 3') + + // Since we replace the state, back button would simply go us back to /nav + await browser.back().waitForElementByCss('.nav-home') + + await browser.close() + }) + }) + + describe('with onClick action', () => { + it('should reload the page and perform additional action', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/nav/on-click') + const defaultCountQuery = await browser + .elementByCss('#query-count') + .text() + const defaultCountState = await browser + .elementByCss('#state-count') + .text() + expect(defaultCountQuery).toBe('QUERY COUNT: 0') + expect(defaultCountState).toBe('STATE COUNT: 0') + + await browser.elementByCss('#on-click-link').click() + + const countQueryAfterClicked = await browser + .elementByCss('#query-count') + .text() + const countStateAfterClicked = await browser + .elementByCss('#state-count') + .text() + expect(countQueryAfterClicked).toBe('QUERY COUNT: 1') + expect(countStateAfterClicked).toBe('STATE COUNT: 1') + } finally { + if (browser) { + await browser.close() + } + } + }) + + it('should not reload if default was prevented', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/nav/on-click') + const defaultCountQuery = await browser + .elementByCss('#query-count') + .text() + const defaultCountState = await browser + .elementByCss('#state-count') + .text() + expect(defaultCountQuery).toBe('QUERY COUNT: 0') + expect(defaultCountState).toBe('STATE COUNT: 0') + + await browser.elementByCss('#on-click-link-prevent-default').click() + + const countQueryAfterClicked = await browser + .elementByCss('#query-count') + .text() + const countStateAfterClicked = await browser + .elementByCss('#state-count') + .text() + expect(countQueryAfterClicked).toBe('QUERY COUNT: 0') + expect(countStateAfterClicked).toBe('STATE COUNT: 1') + + await browser.elementByCss('#on-click-link').click() + + const countQueryAfterClickedAgain = await browser + .elementByCss('#query-count') + .text() + const countStateAfterClickedAgain = await browser + .elementByCss('#state-count') + .text() + expect(countQueryAfterClickedAgain).toBe('QUERY COUNT: 1') + expect(countStateAfterClickedAgain).toBe('STATE COUNT: 2') + } finally { + if (browser) { + await browser.close() + } + } + }) + + it('should always replace the state and perform additional action', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/nav') + + await browser + .elementByCss('#on-click-link') + .click() + .waitForElementByCss('#on-click-page') + + const defaultCountQuery = await browser + .elementByCss('#query-count') + .text() + expect(defaultCountQuery).toBe('QUERY COUNT: 1') + + await browser.elementByCss('#on-click-link').click() + const countQueryAfterClicked = await browser + .elementByCss('#query-count') + .text() + const countStateAfterClicked = await browser + .elementByCss('#state-count') + .text() + expect(countQueryAfterClicked).toBe('QUERY COUNT: 2') + expect(countStateAfterClicked).toBe('STATE COUNT: 1') + + // Since we replace the state, back button would simply go us back to /nav + await browser.back().waitForElementByCss('.nav-home') + } finally { + if (browser) { + await browser.close() + } + } + }) + }) + describe('resets scroll at the correct time', () => { + it('should reset scroll before the new page runs its lifecycles ()', async () => { + let browser + try { + browser = await webdriver( + next.appPort, + '/nav/long-page-to-snap-scroll' + ) + + // Scrolls to item 400 on the page + await browser + .waitForElementByCss('#long-page-to-snap-scroll') + .elementByCss('#scroll-to-item-400') + .click() + + const scrollPosition = await browser.eval('window.pageYOffset') + expect(scrollPosition).toBe(7208) + + // Go to snap scroll page + await browser + .elementByCss('#goto-snap-scroll-position') + .click() + .waitForElementByCss('#scroll-pos-y') + + const snappedScrollPosition = await browser.eval( + 'document.getElementById("scroll-pos-y").innerText' + ) + expect(snappedScrollPosition).toBe('0') + } finally { + if (browser) { + await browser.close() + } + } + }) + + it('should reset scroll before the new page runs its lifecycles (Router#push)', async () => { + let browser + try { + browser = await webdriver( + next.appPort, + '/nav/long-page-to-snap-scroll' + ) + + // Scrolls to item 400 on the page + await browser + .waitForElementByCss('#long-page-to-snap-scroll') + .elementByCss('#scroll-to-item-400') + .click() + + const scrollPosition = await browser.eval('window.pageYOffset') + expect(scrollPosition).toBe(7208) + + // Go to snap scroll page + await browser + .elementByCss('#goto-snap-scroll-position-imperative') + .click() + .waitForElementByCss('#scroll-pos-y') + + const snappedScrollPosition = await browser.eval( + 'document.getElementById("scroll-pos-y").innerText' + ) + expect(snappedScrollPosition).toBe('0') + } finally { + if (browser) { + await browser.close() + } + } + }) + + it('should intentionally not reset scroll before the new page runs its lifecycles (Router#push)', async () => { + let browser + try { + browser = await webdriver( + next.appPort, + '/nav/long-page-to-snap-scroll' + ) + + // Scrolls to item 400 on the page + await browser + .waitForElementByCss('#long-page-to-snap-scroll') + .elementByCss('#scroll-to-item-400') + .click() + + const scrollPosition = await browser.eval('window.pageYOffset') + expect(scrollPosition).toBe(7208) + + // Go to snap scroll page + await browser + .elementByCss('#goto-snap-scroll-position-imperative-noscroll') + .click() + .waitForElementByCss('#scroll-pos-y') + + const snappedScrollPosition = await browser.eval( + 'document.getElementById("scroll-pos-y").innerText' + ) + expect(snappedScrollPosition).not.toBe('0') + expect(Number(snappedScrollPosition)).toBeGreaterThanOrEqual(7208) + } finally { + if (browser) { + await browser.close() + } + } + }) + }) + + describe('with hash changes', () => { + describe('check hydration mis-match', () => { + it('should not have hydration mis-match for hash link', async () => { + const browser = await webdriver(next.appPort, '/nav/hash-changes') + const browserLogs = await browser.log('browser') + let found = false + browserLogs.forEach((log) => { + console.log('log.message', log.message) + if (log.message.includes('Warning: Prop')) { + found = true + } + }) + expect(found).toEqual(false) + }) + }) + + describe('when hash change via Link', () => { + it('should not run getInitialProps', async () => { + const browser = await webdriver(next.appPort, '/nav/hash-changes') + + const counter = await browser + .elementByCss('#via-link') + .click() + .elementByCss('p') + .text() + + expect(counter).toBe('COUNT: 0') + + await browser.close() + }) + + it('should scroll to the specified position on the same page', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/nav/hash-changes') + + // Scrolls to item 400 on the page + await browser.elementByCss('#scroll-to-item-400').click() + + const scrollPositionBeforeEmptyHash = await browser.eval( + 'window.pageYOffset' + ) + + expect(scrollPositionBeforeEmptyHash).toBe(7258) + + // Scrolls back to top when scrolling to `#` with no value. + await browser.elementByCss('#via-empty-hash').click() + + const scrollPositionAfterEmptyHash = await browser.eval( + 'window.pageYOffset' + ) + + expect(scrollPositionAfterEmptyHash).toBe(0) + + // Scrolls to item 400 on the page + await browser.elementByCss('#scroll-to-item-400').click() + + const scrollPositionBeforeTopHash = await browser.eval( + 'window.pageYOffset' + ) + + expect(scrollPositionBeforeTopHash).toBe(7258) + + // Scrolls back to top when clicking link with href `#top`. + await browser.elementByCss('#via-top-hash').click() + + const scrollPositionAfterTopHash = await browser.eval( + 'window.pageYOffset' + ) + + expect(scrollPositionAfterTopHash).toBe(0) + + // Scrolls to cjk anchor on the page + await browser.elementByCss('#scroll-to-cjk-anchor').click() + + const scrollPositionCJKHash = await browser.eval( + 'window.pageYOffset' + ) + + expect(scrollPositionCJKHash).toBe(17436) + } finally { + if (browser) { + await browser.close() + } + } + }) + + it('should not scroll to hash when scroll={false} is set', async () => { + const browser = await webdriver(next.appPort, '/nav/hash-changes') + const curScroll = await browser.eval( + 'document.documentElement.scrollTop' + ) + await browser + .elementByCss('#scroll-to-name-item-400-no-scroll') + .click() + expect(curScroll).toBe( + await browser.eval('document.documentElement.scrollTop') + ) + }) + + it('should scroll to the specified position on the same page with a name property', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/nav/hash-changes') + + // Scrolls to item 400 with name="name-item-400" on the page + await browser.elementByCss('#scroll-to-name-item-400').click() + + const scrollPosition = await browser.eval('window.pageYOffset') + + expect(scrollPosition).toBe(16258) + + // Scrolls back to top when scrolling to `#` with no value. + await browser.elementByCss('#via-empty-hash').click() + + const scrollPositionAfterEmptyHash = await browser.eval( + 'window.pageYOffset' + ) + + expect(scrollPositionAfterEmptyHash).toBe(0) + } finally { + if (browser) { + await browser.close() + } + } + }) + + it('should scroll to the specified position to a new page', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/nav') + + // Scrolls to item 400 on the page + await browser + .elementByCss('#scroll-to-hash') + .click() + .waitForElementByCss('#hash-changes-page') + + const scrollPosition = await browser.eval('window.pageYOffset') + expect(scrollPosition).toBe(7258) + } finally { + if (browser) { + await browser.close() + } + } + }) + + it('should scroll to the specified CJK position to a new page', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/nav') + + // Scrolls to CJK anchor on the page + await browser + .elementByCss('#scroll-to-cjk-hash') + .click() + .waitForElementByCss('#hash-changes-page') + + const scrollPosition = await browser.eval('window.pageYOffset') + expect(scrollPosition).toBe(17436) + } finally { + if (browser) { + await browser.close() + } + } + }) + + it('Should update asPath', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/nav/hash-changes') + + await browser.elementByCss('#via-link').click() + + const asPath = await browser.elementByCss('div#asPath').text() + expect(asPath).toBe('ASPATH: /nav/hash-changes#via-link') + } finally { + if (browser) { + await browser.close() + } + } + }) + }) + + describe('when hash change via A tag', () => { + it('should not run getInitialProps', async () => { + const browser = await webdriver(next.appPort, '/nav/hash-changes') + + const counter = await browser + .elementByCss('#via-a') + .click() + .elementByCss('p') + .text() + + expect(counter).toBe('COUNT: 0') + + await browser.close() + }) + }) + + describe('when hash get removed', () => { + it('should not run getInitialProps', async () => { + const browser = await webdriver(next.appPort, '/nav/hash-changes') + + const counter = await browser + .elementByCss('#via-a') + .click() + .elementByCss('#page-url') + .click() + .elementByCss('p') + .text() + + expect(counter).toBe('COUNT: 1') + + await browser.close() + }) + + it('should not run getInitialProps when removing via back', async () => { + const browser = await webdriver(next.appPort, '/nav/hash-changes') + + const counter = await browser + .elementByCss('#scroll-to-item-400') + .click() + .back() + .elementByCss('p') + .text() + + expect(counter).toBe('COUNT: 0') + await browser.close() + }) + }) + + describe('when hash set to empty', () => { + it('should not run getInitialProps', async () => { + const browser = await webdriver(next.appPort, '/nav/hash-changes') + + const counter = await browser + .elementByCss('#via-a') + .click() + .elementByCss('#via-empty-hash') + .click() + .elementByCss('p') + .text() + + expect(counter).toBe('COUNT: 0') + + await browser.close() + }) + }) + }) + + describe('with hash changes with state', () => { + describe('when passing state via hash change', () => { + it('should increment the history state counter', async () => { + const browser = await webdriver( + next.appPort, + '/nav/hash-changes-with-state#' + ) + + const historyCount = await browser + .elementByCss('#increment-history-count') + .click() + .elementByCss('#increment-history-count') + .click() + .elementByCss('div#history-count') + .text() + + expect(historyCount).toBe('HISTORY COUNT: 2') + + const counter = await browser.elementByCss('p').text() + + // getInitialProps should not be called with only hash changes + expect(counter).toBe('COUNT: 0') + + await browser.close() + }) + + it('should increment the shallow history state counter', async () => { + const browser = await webdriver( + next.appPort, + '/nav/hash-changes-with-state#' + ) + + const historyCount = await browser + .elementByCss('#increment-shallow-history-count') + .click() + .elementByCss('#increment-shallow-history-count') + .click() + .elementByCss('div#shallow-history-count') + .text() + + expect(historyCount).toBe('SHALLOW HISTORY COUNT: 2') + + const counter = await browser.elementByCss('p').text() + + expect(counter).toBe('COUNT: 0') + + await browser.close() + }) + }) + }) + + describe('with shallow routing', () => { + it('should update the url without running getInitialProps', async () => { + const browser = await webdriver(next.appPort, '/nav/shallow-routing') + const counter = await browser + .elementByCss('#increase') + .click() + .elementByCss('#increase') + .click() + .elementByCss('#counter') + .text() + expect(counter).toBe('Counter: 2') + + const getInitialPropsRunCount = await browser + .elementByCss('#get-initial-props-run-count') + .text() + expect(getInitialPropsRunCount).toBe('getInitialProps run count: 1') + + await browser.close() + }) + + it('should handle the back button and should not run getInitialProps', async () => { + const browser = await webdriver(next.appPort, '/nav/shallow-routing') + let counter = await browser + .elementByCss('#increase') + .click() + .elementByCss('#increase') + .click() + .elementByCss('#counter') + .text() + expect(counter).toBe('Counter: 2') + + counter = await browser.back().elementByCss('#counter').text() + expect(counter).toBe('Counter: 1') + + const getInitialPropsRunCount = await browser + .elementByCss('#get-initial-props-run-count') + .text() + expect(getInitialPropsRunCount).toBe('getInitialProps run count: 1') + + await browser.close() + }) + + it('should run getInitialProps always when rending the page to the screen', async () => { + const browser = await webdriver(next.appPort, '/nav/shallow-routing') + + const counter = await browser + .elementByCss('#increase') + .click() + .elementByCss('#increase') + .click() + .elementByCss('#home-link') + .click() + .waitForElementByCss('.nav-home') + .back() + .waitForElementByCss('.shallow-routing') + .elementByCss('#counter') + .text() + expect(counter).toBe('Counter: 2') + + const getInitialPropsRunCount = await browser + .elementByCss('#get-initial-props-run-count') + .text() + expect(getInitialPropsRunCount).toBe('getInitialProps run count: 2') + + await browser.close() + }) + + it('should keep the scroll position on shallow routing', async () => { + const browser = await webdriver(next.appPort, '/nav/shallow-routing') + await browser.eval(() => + document.querySelector('#increase').scrollIntoView() + ) + const scrollPosition = await browser.eval('window.pageYOffset') + + expect(scrollPosition).toBeGreaterThan(3000) + + await browser.elementByCss('#increase').click() + await waitFor(500) + const newScrollPosition = await browser.eval('window.pageYOffset') + + expect(newScrollPosition).toBe(scrollPosition) + + await browser.elementByCss('#increase2').click() + await waitFor(500) + const newScrollPosition2 = await browser.eval('window.pageYOffset') + + expect(newScrollPosition2).toBe(0) + + await browser.eval(() => + document.querySelector('#invalidShallow').scrollIntoView() + ) + const scrollPositionDown = await browser.eval('window.pageYOffset') + + expect(scrollPositionDown).toBeGreaterThan(3000) + + await browser.elementByCss('#invalidShallow').click() + await waitFor(500) + const newScrollPosition3 = await browser.eval('window.pageYOffset') + + expect(newScrollPosition3).toBe(0) + }) + }) + + it('should scroll to top when the scroll option is set to true', async () => { + const browser = await webdriver(next.appPort, '/nav/shallow-routing') + await browser.eval(() => + document.querySelector('#increaseWithScroll').scrollIntoView() + ) + const scrollPosition = await browser.eval('window.pageYOffset') + + expect(scrollPosition).toBeGreaterThan(3000) + + await browser.elementByCss('#increaseWithScroll').click() + await check(async () => { + const newScrollPosition = await browser.eval('window.pageYOffset') + return newScrollPosition === 0 ? 'success' : 'fail' + }, 'success') + }) + + describe('with URL objects', () => { + it('should work with ', async () => { + const browser = await webdriver(next.appPort, '/nav') + const text = await browser + .elementByCss('#query-string-link') + .click() + .waitForElementByCss('.nav-querystring') + .elementByCss('p') + .text() + expect(text).toBe('10') + + expect(await browser.url()).toBe( + `http://localhost:${next.appPort}/nav/querystring/10#10` + ) + await browser.close() + }) + + it('should work with "Router.push"', async () => { + const browser = await webdriver(next.appPort, '/nav') + const text = await browser + .elementByCss('#query-string-button') + .click() + .waitForElementByCss('.nav-querystring') + .elementByCss('p') + .text() + expect(text).toBe('10') + + expect(await browser.url()).toBe( + `http://localhost:${next.appPort}/nav/querystring/10#10` + ) + await browser.close() + }) + + it('should work with the "replace" prop', async () => { + const browser = await webdriver(next.appPort, '/nav') + + let stackLength = await browser.eval('window.history.length') + + expect(stackLength).toBe(2) + + // Navigation to /about using a replace link should maintain the url stack length + const text = await browser + .elementByCss('#about-replace-link') + .click() + .waitForElementByCss('.nav-about') + .elementByCss('p') + .text() + + expect(text).toBe('This is the about page.') + + stackLength = await browser.eval('window.history.length') + + expect(stackLength).toBe(2) + + // Going back to the home with a regular link will augment the history count + await browser + .elementByCss('#home-link') + .click() + .waitForElementByCss('.nav-home') + + stackLength = await browser.eval('window.history.length') + + expect(stackLength).toBe(3) + + await browser.close() + }) + + it('should handle undefined in router.push', async () => { + const browser = await webdriver(next.appPort, '/nav/query-params') + await browser.elementByCss('#click-me').click() + const query = JSON.parse( + await browser.waitForElementByCss('#query-value').text() + ) + expect(query).toEqual({ + param1: '', + param2: '', + param3: '', + param4: '0', + param5: 'false', + param7: '', + param8: '', + param9: '', + param10: '', + param11: ['', '', '', '0', 'false', '', '', '', '', ''], + }) + }) + }) + + describe('with querystring relative urls', () => { + it('should work with Link', async () => { + const browser = await webdriver(next.appPort, '/nav/query-only') + try { + await browser.elementByCss('#link').click() + + await check(() => browser.waitForElementByCss('#prop').text(), 'foo') + } finally { + await browser.close() + } + }) + + it('should work with router.push', async () => { + const browser = await webdriver(next.appPort, '/nav/query-only') + try { + await browser.elementByCss('#router-push').click() + + await check(() => browser.waitForElementByCss('#prop').text(), 'bar') + } finally { + await browser.close() + } + }) + + it('should work with router.replace', async () => { + const browser = await webdriver(next.appPort, '/nav/query-only') + try { + await browser.elementByCss('#router-replace').click() + + await check(() => browser.waitForElementByCss('#prop').text(), 'baz') + } finally { + await browser.close() + } + }) + }) + + describe('with getInitialProp redirect', () => { + it('should redirect the page via client side', async () => { + const browser = await webdriver(next.appPort, '/nav') + const text = await browser + .elementByCss('#redirect-link') + .click() + .waitForElementByCss('.nav-about') + .elementByCss('p') + .text() + + expect(text).toBe('This is the about page.') + await browser.close() + }) + + it('should redirect the page when loading', async () => { + const browser = await webdriver(next.appPort, '/nav/redirect') + const text = await browser + .waitForElementByCss('.nav-about') + .elementByCss('p') + .text() + + expect(text).toBe('This is the about page.') + await browser.close() + }) + }) + + describe('with different types of urls', () => { + it('should work with normal page', async () => { + const browser = await webdriver(next.appPort, '/with-cdm') + const text = await browser.elementByCss('p').text() + + expect(text).toBe('ComponentDidMount executed on client.') + await browser.close() + }) + + it('should work with dir/ page', async () => { + const browser = await webdriver(next.appPort, '/nested-cdm') + const text = await browser.elementByCss('p').text() + + expect(text).toBe('ComponentDidMount executed on client.') + await browser.close() + }) + + it('should not work with /index page', async () => { + const browser = await webdriver(next.appPort, '/index') + expect(await browser.elementByCss('h1').text()).toBe('404') + expect(await browser.elementByCss('h2').text()).toBe( + 'This page could not be found.' + ) + await browser.close() + }) + + it('should work with / page', async () => { + const browser = await webdriver(next.appPort, '/') + const text = await browser.elementByCss('p').text() + + expect(text).toBe('ComponentDidMount executed on client.') + await browser.close() + }) + }) + + describe('with the HOC based router', () => { + it('should navigate as expected', async () => { + const browser = await webdriver(next.appPort, '/nav/with-hoc') + + const pathname = await browser.elementByCss('#pathname').text() + expect(pathname).toBe('Current path: /nav/with-hoc') + + const asPath = await browser.elementByCss('#asPath').text() + expect(asPath).toBe('Current asPath: /nav/with-hoc') + + const text = await browser + .elementByCss('.nav-with-hoc a') + .click() + .waitForElementByCss('.nav-home') + .elementByCss('p') + .text() + + expect(text).toBe('This is the home.') + await browser.close() + }) + }) + + describe('with asPath', () => { + describe('inside getInitialProps', () => { + it('should show the correct asPath with a Link with as prop', async () => { + const browser = await webdriver(next.appPort, '/nav') + const asPath = await browser + .elementByCss('#as-path-link') + .click() + .waitForElementByCss('.as-path-content') + .elementByCss('.as-path-content') + .text() + + expect(asPath).toBe('/as/path') + await browser.close() + }) + + it('should show the correct asPath with a Link without the as prop', async () => { + const browser = await webdriver(next.appPort, '/nav') + const asPath = await browser + .elementByCss('#as-path-link-no-as') + .click() + .waitForElementByCss('.as-path-content') + .elementByCss('.as-path-content') + .text() + + expect(asPath).toBe('/nav/as-path') + await browser.close() + }) + }) + + describe('with next/router', () => { + it('should show the correct asPath', async () => { + const browser = await webdriver(next.appPort, '/nav') + const asPath = await browser + .elementByCss('#as-path-using-router-link') + .click() + .waitForElementByCss('.as-path-content') + .elementByCss('.as-path-content') + .text() + + expect(asPath).toBe('/nav/as-path-using-router') + await browser.close() + }) + + it('should navigate an absolute url on push', async () => { + const browser = await webdriver( + next.appPort, + `/absolute-url?port=${next.appPort}` + ) + await browser.waitForElementByCss('#router-push').click() + await check( + () => browser.eval(() => window.location.origin), + 'https://vercel.com' + ) + }) + + it('should navigate an absolute url on replace', async () => { + const browser = await webdriver( + next.appPort, + `/absolute-url?port=${next.appPort}` + ) + await browser.waitForElementByCss('#router-replace').click() + await check( + () => browser.eval(() => window.location.origin), + 'https://vercel.com' + ) + }) + + it('should navigate an absolute local url on push', async () => { + const browser = await webdriver( + next.appPort, + `/absolute-url?port=${next.appPort}` + ) + // @ts-expect-error _didNotNavigate is set intentionally + await browser.eval(() => (window._didNotNavigate = true)) + await browser.waitForElementByCss('#router-local-push').click() + const text = await browser + .waitForElementByCss('.nav-about') + .elementByCss('p') + .text() + expect(text).toBe('This is the about page.') + // @ts-expect-error _didNotNavigate is set intentionally + expect(await browser.eval(() => window._didNotNavigate)).toBe(true) + }) + + it('should navigate an absolute local url on replace', async () => { + const browser = await webdriver( + next.appPort, + `/absolute-url?port=${next.appPort}` + ) + // @ts-expect-error _didNotNavigate is set intentionally + await browser.eval(() => (window._didNotNavigate = true)) + await browser.waitForElementByCss('#router-local-replace').click() + const text = await browser + .waitForElementByCss('.nav-about') + .elementByCss('p') + .text() + expect(text).toBe('This is the about page.') + // @ts-expect-error _didNotNavigate is set intentionally + expect(await browser.eval(() => window._didNotNavigate)).toBe(true) + }) + }) + + describe('with next/link', () => { + it('should use pushState with same href and different asPath', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/nav/as-path-pushstate') + await browser + .elementByCss('#hello') + .click() + .waitForElementByCss('#something-hello') + const queryOne = JSON.parse( + await browser.elementByCss('#router-query').text() + ) + expect(queryOne.something).toBe('hello') + await browser + .elementByCss('#same-query') + .click() + .waitForElementByCss('#something-same-query') + const queryTwo = JSON.parse( + await browser.elementByCss('#router-query').text() + ) + expect(queryTwo.something).toBe('hello') + await browser.back().waitForElementByCss('#something-hello') + const queryThree = JSON.parse( + await browser.elementByCss('#router-query').text() + ) + expect(queryThree.something).toBe('hello') + await browser + .elementByCss('#else') + .click() + .waitForElementByCss('#something-else') + await browser + .elementByCss('#hello2') + .click() + .waitForElementByCss('#nav-as-path-pushstate') + await browser.back().waitForElementByCss('#something-else') + const queryFour = JSON.parse( + await browser.elementByCss('#router-query').text() + ) + expect(queryFour.something).toBe(undefined) + } finally { + if (browser) { + await browser.close() + } + } + }) + + it('should detect asPath query changes correctly', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/nav/as-path-query') + await browser + .elementByCss('#hello') + .click() + .waitForElementByCss('#something-hello-something-hello') + const queryOne = JSON.parse( + await browser.elementByCss('#router-query').text() + ) + expect(queryOne.something).toBe('hello') + await browser + .elementByCss('#hello2') + .click() + .waitForElementByCss('#something-hello-something-else') + const queryTwo = JSON.parse( + await browser.elementByCss('#router-query').text() + ) + expect(queryTwo.something).toBe('else') + } finally { + if (browser) { + await browser.close() + } + } + }) + }) + }) + + describe('runtime errors', () => { + it('should show redbox when a client side error is thrown inside a component', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/error-inside-browser-page') + expect(await hasRedbox(browser, true)).toBe(true) + const text = await getRedboxSource(browser) + expect(text).toMatch(/An Expected error occurred/) + expect(text).toMatch( + /pages[\\/]error-inside-browser-page\.js \(5:12\)/ + ) + } finally { + if (browser) { + await browser.close() + } + } + }) + + it('should show redbox when a client side error is thrown outside a component', async () => { + let browser + try { + browser = await webdriver( + next.appPort, + '/error-in-the-browser-global-scope' + ) + expect(await hasRedbox(browser, true)).toBe(true) + const text = await getRedboxSource(browser) + expect(text).toMatch(/An Expected error occurred/) + expect(text).toMatch(/error-in-the-browser-global-scope\.js \(2:8\)/) + } finally { + if (browser) { + await browser.close() + } + } + }) + }) + + describe('with 404 pages', () => { + it('should 404 on not existent page', async () => { + const browser = await webdriver(next.appPort, '/non-existent') + expect(await browser.elementByCss('h1').text()).toBe('404') + expect(await browser.elementByCss('h2').text()).toBe( + 'This page could not be found.' + ) + await browser.close() + }) + + it('should 404 on wrong casing', async () => { + const browser = await webdriver(next.appPort, '/nAv/AbOuT') + expect(await browser.elementByCss('h1').text()).toBe('404') + expect(await browser.elementByCss('h2').text()).toBe( + 'This page could not be found.' + ) + await browser.close() + }) + + it('should get url dynamic param', async () => { + const browser = await webdriver( + next.appPort, + '/dynamic/dynamic-part/route' + ) + expect(await browser.elementByCss('p').text()).toBe('dynamic-part') + await browser.close() + }) + + it('should 404 on wrong casing of url dynamic param', async () => { + const browser = await webdriver( + next.appPort, + '/dynamic/dynamic-part/RoUtE' + ) + expect(await browser.elementByCss('h1').text()).toBe('404') + expect(await browser.elementByCss('h2').text()).toBe( + 'This page could not be found.' + ) + await browser.close() + }) + + it('should not 404 for /', async () => { + const browser = await webdriver(next.appPort, '/nav/about/') + const text = await browser.elementByCss('p').text() + expect(text).toBe('This is the about page.') + await browser.close() + }) + + it('should should not contain a page script in a 404 page', async () => { + const browser = await webdriver(next.appPort, '/non-existent') + const scripts = await browser.elementsByCss('script[src]') + for (const script of scripts) { + const src = await script.getAttribute('src') + expect(src.includes('/non-existent')).toBeFalsy() + } + await browser.close() + }) + }) + + describe('updating head while client routing', () => { + it('should only execute async and defer scripts once', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/head') + + await browser.waitForElementByCss('h1') + await waitFor(2000) + expect( + Number(await browser.eval('window.__test_async_executions')) + ).toBe(1) + expect( + Number(await browser.eval('window.__test_defer_executions')) + ).toBe(1) + } finally { + if (browser) { + await browser.close() + } + } + }) + + it('should warn when stylesheets or scripts are in head', async () => { + let browser + try { + browser = await webdriver(next.appPort, '/head') + + await browser.waitForElementByCss('h1') + await waitFor(1000) + const browserLogs = await browser.log('browser') + let foundStyles = false + let foundScripts = false + const logs = [] + browserLogs.forEach(({ message }) => { + if (message.includes('Do not add stylesheets using next/head')) { + foundStyles = true + logs.push(message) + } + if (message.includes('Do not add